/* Copyright (C) 2008-2011 Romain Moret at Grame This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "JackNetUnixSocket.h" #include "JackError.h" #include #include #include #include #include #include // define IPV6_ADD_MEMBERSHIP for Mac OS X #ifndef IPV6_ADD_MEMBERSHIP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #endif #ifndef IPV6_DROP_MEMBERSHIP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif using namespace std; // See RFC 3493; The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 Edition #define _sock4(x) (*(struct sockaddr_in *)&x) #define _sock6(x) (*(struct sockaddr_in6*)&x) #define _ss_addr_p(x) ((fFamily==AF_INET6) ? \ (void*)&(((struct sockaddr_in6*)&x)->sin6_addr) \ : (void*)&(((struct sockaddr_in *)&x)->sin_addr)) #define JNS_UNSPEC 0x0 #define JNS_PROBED 0x1 #define JNS_BOUND 0x2 #define JNS_CONNCD 0x4 #define JNS_MCAST 0x10 namespace Jack { //utility ********************************************************************************************************* int GetHostName(char * name, int size) { if (gethostname(name, size) == SOCKET_ERROR) { jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE)); strcpy(name, "default"); return SOCKET_ERROR; } return 0; } //construct/destruct*********************************************************************************************** JackNetUnixSocket::JackNetUnixSocket() : fFamily(AF_UNSPEC), fSockfd(0), fState(JNS_UNSPEC), fPort(0), fTimeOut(0) { Reset(); } JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port) : fFamily(AF_UNSPEC), fSockfd(0), fState(JNS_UNSPEC), fPort(0), fTimeOut(0) { Reset(); fPort = port; if(NewSocket(ip)==SOCKET_ERROR) jack_error("JackNetUnixSocket::JackNetUnixSocket Cannot initialize (%s:%d): %s",ip,port,strerror(NET_ERROR_CODE)); } JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket) { Clone(socket); } JackNetUnixSocket::~JackNetUnixSocket() { Close(); } JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket) { if (this != &socket) Clone(socket); return *this; } //socket*********************************************************************************************************** void JackNetUnixSocket::Clone(const JackNetUnixSocket& socket) { fSockfd = 0; fTimeOut = 0; fPort = socket.fPort; fFamily = socket.fFamily; fState = socket.fState; fState &= (JNS_MCAST | JNS_PROBED); // Reset all fields except mcast and probed memcpy(&fSendAddr, & socket.fSendAddr, sizeof(fSendAddr)); memcpy(&fRecvAddr, & socket.fRecvAddr, sizeof(fRecvAddr)); } /* When using Multicast always create socket with new (mip,port) or call NewSocket(mip) for autoinitialized sockets first. * This makes sure proper workarounds for Multicast incompatibility will be activated while setting up address family. */ int JackNetUnixSocket::ProbeAF(const char* ip, struct sockaddr_storage *addr, int (*call)(int,const struct sockaddr*,socklen_t)) { struct addrinfo hint,*res, *ri; char sport[6]; int ret; snprintf(sport,6,"%d",fPort); memset(&hint,0,sizeof(hint)); hint.ai_family = fFamily; hint.ai_socktype = SOCK_DGRAM; hint.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICSERV; if(ip == NULL) hint.ai_flags |= AI_PASSIVE; ret = getaddrinfo(ip,sport,&hint,&res); if(ret) { jack_error("JackNetUnixSocket::ProbeAF getaddrinfo(%s:%s): %s",ip,sport,gai_strerror(ret)); return ret; } #define GLIBC_BUG // An ugly GLIBC bug, which one may argue to be RFC bug. See http://sourceware.org/bugzilla/show_bug.cgi?id=14967 #ifdef GLIBC_BUG // Of course gai configuration can say to have v4 having precedence explicitly but... here we prefer ipv6. period if(!ip && res->ai_family == AF_INET && res->ai_next && res->ai_next->ai_family == AF_INET6) { jack_log("JackNetUnixSocket::ProbeAF swapping addrinfo entries to work around GLIBC getaddrinfo bug: AF_INET<->AF_INET6"); // Swapping first two entries ri = res->ai_next; res->ai_next = ri->ai_next; ri->ai_next = res; res = ri; } else // << Remove up to this very line including once GLIBC is fixed << #endif ri = res; do { jack_log("JackNetUnixSocket::ProbeAF trying AF[%d], TYPE[%d], PROTO[%d]", ri->ai_family,ri->ai_socktype,ri->ai_protocol); ret = socket(ri->ai_family, ri->ai_socktype, ri->ai_protocol); if(ret < 0) continue; if(!(*call)(ret, ri->ai_addr, ri->ai_addrlen)) break; close(ret); jack_log("JackNetUnixSocket::ProbeAF failed for AF[%d], %s",ri->ai_family,(ri->ai_next)?"trying next":"giving up"); } while((ri = ri->ai_next) != NULL); // probe successfully made a *call on socket for ip represented by ri if(ri) { fSockfd = ret; fFamily = ri->ai_family; memcpy(addr,ri->ai_addr,ri->ai_addrlen); jack_log("JackNetUnixSocket::ProbeAF probed[%d] AF[%d] for %s",ret,fFamily,ip); fState |= JNS_PROBED; if(fFamily == AF_INET6 && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) fState |= JNS_MCAST; } else ret = SOCKET_ERROR; freeaddrinfo(res); return ret; } int JackNetUnixSocket::NewSocket() { return NewSocket(NULL); } int JackNetUnixSocket::NewSocket(const char *ip) { if(fFamily == AF_UNSPEC) { if(ip) { if(ProbeAF(ip,&fSendAddr,connect)<0) return SOCKET_ERROR; } else { if(ProbeAF(ip,&fRecvAddr,bind)<0) return SOCKET_ERROR; // It should be with AF/port/ANY after bind memcpy(&fSendAddr,&fRecvAddr,sizeof(fRecvAddr)); } // Now re-create the fd to get a brand-new unnamed socket } if (fSockfd) { Close(); Reset(); } fSockfd = socket(fFamily, SOCK_DGRAM, 0); /* Enable address reuse */ int res, on = 1; #ifdef __APPLE__ if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) { #else if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) { #endif StrError(NET_ERROR_CODE); } int tos = 0; /* see */ /* DSCP Field Hex/Bin/Dec Layer 2 Prio Traffic Type Acronym WMM Access Category 0x38 / 111000 / 56 7 Network Control NC AC_VO 0x30 / 110000 / 48 6 Voice VO AC_VO 0x28 / 101000 / 40 5 Video VI AC_VI 0x20 / 100000 / 32 4 Controlled Load CL AC_VI 0x18 / 011000 / 24 3 Excellent Effort EE AC_BE 0x10 / 010000 / 16 2 Spare -- AC_BK 0x08 / 001000 / 8 1 Background BK AC_BK 0x00 / 000000 / 0 0 Best Effort BE AC_BE */ socklen_t len = sizeof(tos); res = getsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, &len); tos = 46 * 4; // see res = setsockopt(fSockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); return fSockfd; } bool JackNetUnixSocket::IsLocal(char* ip) { if (strcmp(ip, "127.0.0.1") == 0) { return true; } else if(!strcmp(ip,"::1")) return true; struct ifaddrs *ifas, *ifa; socklen_t len; if (getifaddrs(&ifas) == -1) { jack_error("JackNetUnixSocket::IsLocal error in getifaddrs"); return false; } for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; // Address is mandatory len = (ifa->ifa_addr->sa_family==AF_INET)?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6); if(!getnameinfo(ifa->ifa_addr, len, f_addr_buff, INET6_ADDRSTRLEN, NULL,0, NI_NUMERICSERV | NI_DGRAM | NI_NUMERICSERV | NI_DGRAM | NI_NUMERICHOST)) if(!strcmp(f_addr_buff,ip)) break; } freeifaddrs(ifas); return (ifa != NULL); } int JackNetUnixSocket::Bind() { int yes=1; if(fState & JNS_BOUND) return 0; // Multicast is incompatible with V4MAPPED or V4COMPAT addresses, if probe detected MC we need V6ONLY if(fFamily == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&_sock6(fRecvAddr).sin6_addr) && fState & JNS_MCAST) if(SetOption(IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) return SOCKET_ERROR; if(::bind(fSockfd, reinterpret_cast(&fRecvAddr), sizeof(fRecvAddr))) return SOCKET_ERROR; fState |= JNS_BOUND; return 0; } int JackNetUnixSocket::Bind(const char *if_name) { int ret = Bind(); if(!ret && strcmp(if_name,"any")) { if(fFamily == AF_INET) { // 'all' for this case will lead to 'last valid interface', which is not that one might expect if(strcmp(if_name,"all")) ret = BindMCastIface(if_name, IP_MULTICAST_IF, &_sock4(fSendAddr).sin_addr); else jack_error("Multicast Interface all not found, sending from default"); } else if(fFamily == AF_INET6) { struct if_nameindex *if_ni = if_nameindex(); // In V6 world we do everything differently. if(if_ni) { int i; for (i=0; if_ni[i].if_index > 0; i++) { if(if_ni[i].if_index == 1) continue; // Skip loopback if(!strcmp(if_ni[i].if_name,if_name)) { ret = SetOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_ni[i].if_index, sizeof(if_ni[i].if_index)); jack_log("JackNetUnixSocket::Bind Multicasting from %s",if_ni[i].if_name); break; } } if(if_ni[i].if_index == 0) jack_error("Multicast Interface %s not found, sending from default",if_name); if_freenameindex(if_ni); } } } return ret; } int JackNetUnixSocket::BindWith(const char* ip) { if(fFamily == AF_UNSPEC) { if(!fPort) return SOCKET_ERROR; if(ProbeAF(ip,&fRecvAddr,&bind)<0) return SOCKET_ERROR; fState |= JNS_BOUND; return 0; } else { if(SetRecvIP(ip)==-1) return SOCKET_ERROR; return Bind(); } } int JackNetUnixSocket::BindWith(int port) { if(fFamily == AF_UNSPEC) { fPort = port; if(ProbeAF(NULL,&fRecvAddr,&bind)<0) return SOCKET_ERROR; fState |= JNS_BOUND; return 0; } else { SetPort(port); return Bind(); } } int JackNetUnixSocket::Connect() { if(fFamily != AF_UNSPEC) return connect(fSockfd, (struct sockaddr*)&fSendAddr,sizeof(fSendAddr)); jack_error("JackNetUnixSocket::Connect Family not initialized"); return SOCKET_ERROR; } int JackNetUnixSocket::ConnectTo(const char* ip) { socklen_t l=sizeof(fRecvAddr); if(fPort==0) return SOCKET_ERROR; if(fState & JNS_PROBED) { Reset(); fFamily=AF_UNSPEC; } if(fSockfd) Close(); if(ProbeAF(ip,&fSendAddr,&connect)<0) return SOCKET_ERROR; fState |= JNS_CONNCD; return getsockname(fSockfd, (struct sockaddr *)&fRecvAddr, &l); } void JackNetUnixSocket::Close() { if (fSockfd) { close(fSockfd); } fSockfd = 0; fState = JNS_UNSPEC; } void JackNetUnixSocket::Reset() { memset(&fSendAddr, 0, sizeof(fSendAddr)); fSendAddr.ss_family = fFamily; memset(&fRecvAddr, 0, sizeof(fRecvAddr)); fRecvAddr.ss_family = fFamily; if(fPort) SetPort(fPort); } bool JackNetUnixSocket::IsSocket() { return(fSockfd) ? true : false; } //IP/PORT*********************************************************************************************************** void JackNetUnixSocket::SetPort(int port) { fPort = port; switch(fFamily) { // Playing dumb here, in fact port section of both sockaddrs is compatible case AF_INET: _sock4(fSendAddr).sin_port = htons(port); _sock4(fRecvAddr).sin_port = htons(port); break; case AF_INET6: _sock6(fSendAddr).sin6_port = htons(port); _sock6(fRecvAddr).sin6_port = htons(port); break; default: jack_info("JackNetUnixSocket::SetPort: Family not initialized"); } } int JackNetUnixSocket::GetPort() { return fPort; } //address*********************************************************************************************************** int JackNetUnixSocket::SetAddress(const char* ip, int port) { if(fFamily == AF_UNSPEC) { fPort=port; return ProbeAF(ip,&fSendAddr,&connect); } else { SetPort(port); return inet_pton(fFamily, ip, _ss_addr_p(fSendAddr)); } } int JackNetUnixSocket::SetSendIP(const char *ip) { if(fFamily == AF_UNSPEC) return -1; return inet_pton(fFamily, ip, _ss_addr_p(fSendAddr)); } char* JackNetUnixSocket::GetSendIP() { return (char*)inet_ntop(fFamily, _ss_addr_p(fSendAddr),f_addr_buff,INET6_ADDRSTRLEN); } int JackNetUnixSocket::SetRecvIP(const char *ip) { if(fFamily == AF_UNSPEC) return -1; return inet_pton(fFamily, ip, _ss_addr_p(fRecvAddr)); } char* JackNetUnixSocket::GetRecvIP() { return (char*)inet_ntop(fFamily, _ss_addr_p(fRecvAddr),f_addr_buff,INET6_ADDRSTRLEN); } //utility************************************************************************************************************ int JackNetUnixSocket::GetName(char* name) { return gethostname(name, 255); } int JackNetUnixSocket::JoinMCastGroup(const char* ip) { return JoinMCastGroup(ip,"any"); } /** Glory and shame of IPv6 interoperability: Multicast * Not only API is completely incompatible, but even socket is incompatible. I.e. you cannot use V4MAPPED/COMPATIBLE * sockets/sockaddress for Multicast. Any V4 address is just a legacy unicast socket for IPv6. Moreover, IPv6 API * implementation itself is a big mess even though there's no time anymore and way back. Here we're using POSIX API. * When dealing with Multicast - Address Family should be set once and forever for used multicast address. This * implies we cannot use V4 addresses on V6 sockets. So multicast should have V6ONLY soscket option set to allow v6 * adapter, master or manager coexist on the same host. See ProbeAF/Bind for these tricks. */ int JackNetUnixSocket::JoinMCastGroup(const char* ip, const char *if_name) { int level, option, length; void *mreq; char addr[sizeof(in6_addr)]; inet_pton(fFamily, ip, addr); if(!strcmp(if_name,"any")) { // UNSPEC binding we can do in-place using void pointers if(fFamily == AF_INET) { struct ip_mreq multicast_req; multicast_req.imr_multiaddr.s_addr = *(uint32_t*)(addr); multicast_req.imr_interface.s_addr = htonl(INADDR_ANY); level = IPPROTO_IP; option = IP_ADD_MEMBERSHIP; mreq=&multicast_req; length = sizeof(ip_mreq); } else if(fFamily == AF_INET6) { struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr,addr,sizeof(in6_addr)); mreq6.ipv6mr_interface = 0; level = IPPROTO_IPV6; option = IPV6_ADD_MEMBERSHIP; mreq = &mreq6; length = sizeof(ipv6_mreq); } else { jack_error("Unsupported family[%d]",fFamily); return -1; } return SetOption(level, option, mreq, length); } else { // For anything more complex need to call family-specific routine if(fFamily == AF_INET) return BindMCastIface(if_name, IP_ADD_MEMBERSHIP, (struct in_addr *)addr); else if(fFamily == AF_INET6) return BindMCast6Iface(if_name, (struct in6_addr *)addr); else { jack_error("Unsupported family[%d]",fFamily); return -1; } } } int JackNetUnixSocket::BindMCastIface(const char *if_name, const int option, struct in_addr *addr) { struct ifaddrs *ifas, *ifa; struct ip_mreq mreq; int specific = strcmp("all",if_name); int ret=-1; char *if_last=(char *)"any"; if (getifaddrs(&ifas) == -1) { jack_error("JackNetUnixSocket::BindMCastIface error in getifaddrs"); return -1; } mreq.imr_multiaddr.s_addr = addr->s_addr; for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; // Address is mandatory if(!ifa->ifa_name || !strcmp(if_last,ifa->ifa_name)) continue; // Name as well, also skip already enabled interface if(!(ifa->ifa_flags & IFF_MULTICAST) || !(ifa->ifa_flags & IFF_RUNNING)) continue; // And non multicast or down interface if(ifa->ifa_addr->sa_family != AF_INET) continue; // And non-matching family if(!specific || !strcmp(ifa->ifa_name,if_name)) { mreq.imr_interface.s_addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr; ret = SetOption(IPPROTO_IP, option, &mreq, sizeof(struct ip_mreq)); if(ret) break; if_last = ifa->ifa_name; jack_log("JackNetUnixSocket::BindMCastIface attaching to %s", if_last); } } freeifaddrs(ifas); if(!strcmp(if_last,"any")) jack_error("JackNetUnixSocket::BindMCastIface cannot find valid interface"); return ret; } int JackNetUnixSocket::BindMCast6Iface(const char *if_name, struct in6_addr *mip) { int i, ret=-1, specific=strcmp("all",if_name); struct if_nameindex *if_ni = if_nameindex(); struct ipv6_mreq mreq; if(if_ni) { memcpy(&mreq.ipv6mr_multiaddr, mip, sizeof(struct in6_addr)); for (i=0; if_ni[i].if_index > 0; i++) { if(if_ni[i].if_index == 1) continue; // Skip loopback mreq.ipv6mr_interface = if_ni[i].if_index; if(!specific || !strcmp(if_ni[i].if_name,if_name)) { ret = SetOption(IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)); if(ret < 0) break; } } if_freenameindex(if_ni); } return ret; } //options************************************************************************************************************ int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen) { return setsockopt(fSockfd, level, optname, optval, optlen); } int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen) { return getsockopt(fSockfd, level, optname, optval, optlen); } //timeout************************************************************************************************************ #if defined(__sun__) || defined(sun) int JackNetUnixSocket::SetTimeOut(int us) { int flags; fTimeOut = us; if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) { jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL"); return -1; } flags |= O_NONBLOCK; if (fcntl(fSockfd, F_SETFL, flags) < 0) { jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL"); return 1; } return 0; } int JackNetUnixSocket::WaitRead() { if (fTimeOut > 0) { struct timeval tv; fd_set fdset; ssize_t res; tv.tv_sec = fTimeOut / 1000000; tv.tv_usec = fTimeOut % 1000000; FD_ZERO(&fdset); FD_SET(fSockfd, &fdset); do { res = select(fSockfd + 1, &fdset, NULL, NULL, &tv); } while (res < 0 && errno == EINTR); if (res < 0) { return res; } else if (res == 0) { errno = ETIMEDOUT; return -1; } } return 0; } int JackNetUnixSocket::WaitWrite() { if (fTimeOut > 0) { struct timeval tv; fd_set fdset; ssize_t res; tv.tv_sec = fTimeOut / 1000000; tv.tv_usec = fTimeOut % 1000000; FD_ZERO(&fdset); FD_SET(fSockfd, &fdset); do { res = select(fSockfd + 1, NULL, &fdset, NULL, &tv); } while (res < 0 && errno == EINTR); if (res < 0) { return res; } else if (res == 0) { errno = ETIMEDOUT; return -1; } } return 0; } #else int JackNetUnixSocket::SetTimeOut(int us) { jack_log("JackNetUnixSocket::SetTimeout %d usecs", us); struct timeval timeout; //less than 1 sec if (us < 1000000) { timeout.tv_sec = 0; timeout.tv_usec = us; } else { //more than 1 sec float sec = float(us) / 1000000.f; timeout.tv_sec = (int)sec; float usec = (sec - float(timeout.tv_sec)) * 1000000; timeout.tv_usec =(int)usec; } return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); } #endif //local loop********************************************************************************************************** int JackNetUnixSocket::SetLocalLoop() { char disable = 0; unsigned int dis6 = 0; switch(fFamily) { case AF_INET: return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable)); case AF_INET6: return SetOption(IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &dis6, sizeof(dis6)); default: jack_error("JackNetUnixSocket::SetLocalLoop: Family not initialized"); return -1; } } //network operations************************************************************************************************** int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags) { #if defined(__sun__) || defined(sun) if (WaitWrite() < 0) { return -1; } #endif int res; if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast(&fSendAddr), sizeof(fSendAddr))) < 0) { jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno)); } return res; } int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip) { int addr_conv = inet_pton(fFamily, ip, _ss_addr_p(fSendAddr)); if (addr_conv < 1) { return addr_conv; } //fSendAddr.sin_port = htons(fPort); #if defined(__sun__) || defined(sun) if (WaitWrite() < 0) { return -1; } #endif return SendTo(buffer, nbytes, flags); } int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags) { #if defined(__sun__) || defined(sun) if (WaitWrite() < 0) { return -1; } #endif int res; if ((res = send(fSockfd, buffer, nbytes, flags)) < 0) { jack_error("Send fd = %ld err = %s", fSockfd, strerror(errno)); } return res; } int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags) { socklen_t addr_len = sizeof(fRecvAddr); #if defined(__sun__) || defined(sun) if (WaitRead() < 0) { return -1; } #endif int res; if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast(&fRecvAddr), &addr_len)) < 0) { jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno)); } return res; } int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags) { #if defined(__sun__) || defined(sun) if (WaitRead() < 0) { return -1; } #endif int res; if ((res = recv(fSockfd, buffer, nbytes, flags)) < 0) { jack_error("Recv fd = %ld err = %s", fSockfd, strerror(errno)); } return res; } int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags) { jack_log("JackNetUnixSocket::CatchHost"); socklen_t addr_len = sizeof(fSendAddr); #if defined(__sun__) || defined(sun) if (WaitRead() < 0) { return -1; } #endif int res; if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast(&fSendAddr), &addr_len)) < 0) { jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno)); } return res; } net_error_t JackNetUnixSocket::GetError() { switch (errno) { case EAGAIN: case ETIMEDOUT: return NET_NO_DATA; case ECONNABORTED: case ECONNREFUSED: case ECONNRESET: case EINVAL: case EHOSTDOWN: case EHOSTUNREACH: case ENETDOWN: case ENETUNREACH: return NET_CONN_ERROR; default: //return NET_OP_ERROR; return NET_CONN_ERROR; } } void JackNetUnixSocket::PrintError() { switch (errno) { case EAGAIN: jack_error("JackNetUnixSocket : EAGAIN"); break; case ETIMEDOUT: jack_error("JackNetUnixSocket : ETIMEDOUT"); break; case ECONNABORTED: jack_error("JackNetUnixSocket : ECONNABORTED"); break; case ECONNREFUSED: jack_error("JackNetUnixSocket : ECONNREFUSED"); break; case ECONNRESET: jack_error("JackNetUnixSocket : ECONNRESET"); break; case EINVAL: jack_error("JackNetUnixSocket : EINVAL"); break; case EHOSTDOWN: jack_error("JackNetUnixSocket : EHOSTDOWN"); break; case EHOSTUNREACH: jack_error("JackNetUnixSocket : EHOSTUNREACH"); break; case ENETDOWN: jack_error("JackNetUnixSocket : ENETDOWN"); break; case ENETUNREACH: jack_error("JackNetUnixSocket : ENETUNREACH"); break; default: jack_error("JackNetUnixSocket : %d", errno); break; } } }