Jack2  1.9.10
JackNetUnixSocket.cpp
00001 /*
00002 Copyright (C) 2008-2011 Romain Moret at Grame
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU General Public License as published by
00006 the Free Software Foundation; either version 2 of the License, or
00007 (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #include "JackNetUnixSocket.h"
00021 #include "JackError.h"
00022 
00023 #include <unistd.h>
00024 #include <fcntl.h>
00025 
00026 using namespace std;
00027 
00028 namespace Jack
00029 {
00030     //utility *********************************************************************************************************
00031     int GetHostName(char * name, int size)
00032     {
00033         if (gethostname(name, size) == SOCKET_ERROR) {
00034             jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
00035             strcpy(name, "default");
00036             return SOCKET_ERROR;
00037         }
00038         return 0;
00039     }
00040 
00041     //construct/destruct***********************************************************************************************
00042     JackNetUnixSocket::JackNetUnixSocket()
00043     {
00044         fSockfd = 0;
00045         fPort = 0;
00046         fTimeOut = 0;
00047         fSendAddr.sin_family = AF_INET;
00048         fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00049         memset(&fSendAddr.sin_zero, 0, 8);
00050         fRecvAddr.sin_family = AF_INET;
00051         fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00052         memset(&fRecvAddr.sin_zero, 0, 8);
00053     }
00054 
00055     JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
00056     {
00057         fSockfd = 0;
00058         fPort = port;
00059         fTimeOut = 0;
00060         fSendAddr.sin_family = AF_INET;
00061         fSendAddr.sin_port = htons(port);
00062         inet_aton(ip, &fSendAddr.sin_addr);
00063         memset(&fSendAddr.sin_zero, 0, 8);
00064         fRecvAddr.sin_family = AF_INET;
00065         fRecvAddr.sin_port = htons(port);
00066         fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00067         memset(&fRecvAddr.sin_zero, 0, 8);
00068     }
00069 
00070     JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
00071     {
00072         fSockfd = 0;
00073         fTimeOut = 0;
00074         fPort = socket.fPort;
00075         fSendAddr = socket.fSendAddr;
00076         fRecvAddr = socket.fRecvAddr;
00077     }
00078 
00079     JackNetUnixSocket::~JackNetUnixSocket()
00080     {
00081         Close();
00082     }
00083 
00084     JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
00085     {
00086         if (this != &socket) {
00087             fSockfd = 0;
00088             fPort = socket.fPort;
00089             fSendAddr = socket.fSendAddr;
00090             fRecvAddr = socket.fRecvAddr;
00091         }
00092         return *this;
00093     }
00094 
00095     //socket***********************************************************************************************************
00096     int JackNetUnixSocket::NewSocket()
00097     {
00098         if (fSockfd) {
00099             Close();
00100             Reset();
00101         }
00102         fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
00103 
00104         /* Enable address reuse */
00105         int res, on = 1;
00106     #ifdef __APPLE__
00107         if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) < 0) {
00108     #else
00109         if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
00110     #endif
00111             StrError(NET_ERROR_CODE);
00112         }
00113         return fSockfd;
00114     }
00115 
00116     bool JackNetUnixSocket::IsLocal(char* ip)
00117     {
00118         if (strcmp(ip, "127.0.0.1") == 0) {
00119             return true;
00120         }
00121 
00122         char host_name[32];
00123         gethostname(host_name, sizeof(host_name));
00124 
00125         struct hostent* host = gethostbyname(host_name);
00126         if (host) {
00127             for (int i = 0; host->h_addr_list[i] != 0; ++i) {
00128                 struct in_addr addr;
00129                 memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
00130                 if (strcmp(inet_ntoa(addr), ip) == 0) {
00131                     return true;
00132                 }
00133             }
00134             return false;
00135         } else {
00136             return false;
00137         }
00138     }
00139 
00140     int JackNetUnixSocket::Bind()
00141     {
00142         return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
00143     }
00144 
00145     int JackNetUnixSocket::BindWith(const char* ip)
00146     {
00147         int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
00148         if (addr_conv < 0) {
00149             return addr_conv;
00150         }
00151         return Bind();
00152     }
00153 
00154     int JackNetUnixSocket::BindWith(int port)
00155     {
00156         fRecvAddr.sin_port = htons(port);
00157         return Bind();
00158     }
00159 
00160     int JackNetUnixSocket::Connect()
00161     {
00162         return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
00163     }
00164 
00165     int JackNetUnixSocket::ConnectTo(const char* ip)
00166     {
00167         int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
00168         if (addr_conv < 0) {
00169             return addr_conv;
00170         }
00171         return Connect();
00172     }
00173 
00174     void JackNetUnixSocket::Close()
00175     {
00176         if (fSockfd) {
00177             close(fSockfd);
00178         }
00179         fSockfd = 0;
00180     }
00181 
00182     void JackNetUnixSocket::Reset()
00183     {
00184         fSendAddr.sin_family = AF_INET;
00185         fSendAddr.sin_port = htons(fPort);
00186         fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00187         memset(&fSendAddr.sin_zero, 0, 8);
00188         fRecvAddr.sin_family = AF_INET;
00189         fRecvAddr.sin_port = htons(fPort);
00190         fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00191         memset(&fRecvAddr.sin_zero, 0, 8);
00192     }
00193 
00194     bool JackNetUnixSocket::IsSocket()
00195     {
00196         return(fSockfd) ? true : false;
00197     }
00198 
00199     //IP/PORT***********************************************************************************************************
00200     void JackNetUnixSocket::SetPort(int port)
00201     {
00202         fPort = port;
00203         fSendAddr.sin_port = htons(port);
00204         fRecvAddr.sin_port = htons(port);
00205     }
00206 
00207     int JackNetUnixSocket::GetPort()
00208     {
00209         return fPort;
00210     }
00211 
00212     //address***********************************************************************************************************
00213     int JackNetUnixSocket::SetAddress(const char* ip, int port)
00214     {
00215         int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
00216         if (addr_conv < 0) {
00217             return addr_conv;
00218         }
00219         fSendAddr.sin_port = htons(port);
00220         return 0;
00221     }
00222 
00223     char* JackNetUnixSocket::GetSendIP()
00224     {
00225         return inet_ntoa(fSendAddr.sin_addr);
00226     }
00227 
00228     char* JackNetUnixSocket::GetRecvIP()
00229     {
00230         return inet_ntoa(fRecvAddr.sin_addr);
00231     }
00232 
00233     //utility************************************************************************************************************
00234     int JackNetUnixSocket::GetName(char* name)
00235     {
00236         return gethostname(name, 255);
00237     }
00238 
00239     int JackNetUnixSocket::JoinMCastGroup(const char* ip)
00240     {
00241         struct ip_mreq multicast_req;
00242         inet_aton(ip, &multicast_req.imr_multiaddr);
00243         multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
00244         return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
00245     }
00246 
00247     //options************************************************************************************************************
00248     int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
00249     {
00250         return setsockopt(fSockfd, level, optname, optval, optlen);
00251     }
00252 
00253     int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
00254     {
00255         return getsockopt(fSockfd, level, optname, optval, optlen);
00256     }
00257 
00258     //timeout************************************************************************************************************
00259 
00260 #if defined(__sun__) || defined(sun)
00261     int JackNetUnixSocket::SetTimeOut(int us)
00262     {
00263         int     flags;
00264         fTimeOut = us;
00265 
00266         if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
00267                     jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
00268                     return -1;
00269             }
00270 
00271             flags |= O_NONBLOCK;
00272             if (fcntl(fSockfd, F_SETFL, flags) < 0) {
00273                     jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
00274                     return 1;
00275             }
00276 
00277         return 0;
00278     }
00279 
00280     int JackNetUnixSocket::WaitRead()
00281     {
00282         if (fTimeOut > 0) {
00283 
00284             struct timeval tv;
00285                 fd_set fdset;
00286             ssize_t     res;
00287 
00288             tv.tv_sec = fTimeOut / 1000000;
00289                 tv.tv_usec = fTimeOut % 1000000;
00290 
00291                 FD_ZERO(&fdset);
00292                 FD_SET(fSockfd, &fdset);
00293 
00294                 do {
00295                         res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
00296                 } while (res < 0 && errno == EINTR);
00297 
00298                 if (res < 0) {
00299                         return res;
00300             } else if (res == 0) {
00301                 errno = ETIMEDOUT;
00302                         return -1;
00303                 }
00304         }
00305 
00306         return 0;
00307     }
00308 
00309     int JackNetUnixSocket::WaitWrite()
00310     {
00311         if (fTimeOut > 0) {
00312 
00313             struct timeval tv;
00314                 fd_set fdset;
00315             ssize_t     res;
00316 
00317             tv.tv_sec = fTimeOut / 1000000;
00318             tv.tv_usec = fTimeOut % 1000000;
00319 
00320                 FD_ZERO(&fdset);
00321                 FD_SET(fSockfd, &fdset);
00322 
00323                 do {
00324                         res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
00325                 } while (res < 0 && errno == EINTR);
00326 
00327                 if (res < 0) {
00328                         return res;
00329             } else if (res == 0) {
00330                 errno = ETIMEDOUT;
00331                         return -1;
00332                 }
00333         }
00334 
00335         return 0;
00336     }
00337 
00338 #else
00339     int JackNetUnixSocket::SetTimeOut(int us)
00340     {
00341         jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
00342         struct timeval timeout;
00343 
00344         //less than 1 sec
00345         if (us < 1000000) {
00346             timeout.tv_sec = 0;
00347             timeout.tv_usec = us;
00348         } else {
00349         //more than 1 sec
00350             float sec = float(us) / 1000000.f;
00351             timeout.tv_sec = (int)sec;
00352             float usec = (sec - float(timeout.tv_sec)) * 1000000;
00353             timeout.tv_usec =(int)usec;
00354         }
00355         return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
00356     }
00357 #endif
00358 
00359     //local loop**********************************************************************************************************
00360     int JackNetUnixSocket::SetLocalLoop()
00361     {
00362         char disable = 0;
00363         return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
00364     }
00365 
00366     //network operations**************************************************************************************************
00367     int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
00368     {
00369     #if defined(__sun__) || defined(sun)
00370         if (WaitWrite() < 0) {
00371             return -1;
00372         }
00373     #endif
00374         int res;
00375         if ((res = sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t))) < 0) {
00376             jack_error("SendTo fd = %ld err = %s", fSockfd, strerror(errno));
00377         }
00378         return res;
00379     }
00380 
00381     int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
00382     {
00383         int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
00384         if (addr_conv < 1) {
00385             return addr_conv;
00386         }
00387     #if defined(__sun__) || defined(sun)
00388         if (WaitWrite() < 0) {
00389             return -1;
00390         }
00391     #endif
00392         return SendTo(buffer, nbytes, flags);
00393     }
00394 
00395     int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
00396     {
00397     #if defined(__sun__) || defined(sun)
00398         if (WaitWrite() < 0) {
00399             return -1;
00400         }
00401     #endif
00402         int res;
00403         if ((res = send(fSockfd, buffer, nbytes, flags)) < 0) {
00404             jack_error("Send fd = %ld err = %s", fSockfd, strerror(errno));
00405         }
00406         return res;
00407     }
00408 
00409     int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
00410     {
00411         socklen_t addr_len = sizeof(socket_address_t);
00412     #if defined(__sun__) || defined(sun)
00413         if (WaitRead() < 0) {
00414             return -1;
00415         }
00416     #endif
00417         int res;
00418         if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len)) < 0) {
00419             jack_error("RecvFrom fd = %ld err = %s", fSockfd, strerror(errno));
00420         }
00421         return res;        
00422     }
00423 
00424     int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
00425     {
00426     #if defined(__sun__) || defined(sun)
00427         if (WaitRead() < 0) {
00428             return -1;
00429         }
00430     #endif
00431         int res;
00432         if ((res = recv(fSockfd, buffer, nbytes, flags)) < 0) {
00433             jack_error("Recv fd = %ld err = %s", fSockfd, strerror(errno));
00434         }
00435         return res;        
00436     }
00437 
00438     int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
00439     {
00440         socklen_t addr_len = sizeof(socket_address_t);
00441     #if defined(__sun__) || defined(sun)
00442         if (WaitRead() < 0) {
00443             return -1;
00444         }
00445     #endif
00446         int res;
00447         if ((res = recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len)) < 0) {
00448             jack_log("CatchHost fd = %ld err = %s", fSockfd, strerror(errno));
00449         }
00450         return res;                
00451     }
00452 
00453     net_error_t JackNetUnixSocket::GetError()
00454     {
00455         switch (errno) {
00456             case EAGAIN:
00457             case ETIMEDOUT:
00458                 return NET_NO_DATA;
00459 
00460             case ECONNABORTED:
00461             case ECONNREFUSED:
00462             case ECONNRESET:
00463             case EINVAL:
00464             case EHOSTDOWN:
00465             case EHOSTUNREACH:
00466             case ENETDOWN:
00467             case ENETUNREACH:
00468                 return NET_CONN_ERROR;
00469 
00470             default:
00471                 //return NET_OP_ERROR;
00472                 return NET_CONN_ERROR;
00473         }
00474     }
00475         
00476     void JackNetUnixSocket::PrintError()
00477     {
00478         switch (errno) {
00479                 
00480             case EAGAIN:
00481                 jack_error("JackNetUnixSocket : EAGAIN");
00482                 break;
00483             case ETIMEDOUT:
00484                 jack_error("JackNetUnixSocket : ETIMEDOUT");
00485                 break;
00486             case ECONNABORTED:
00487                 jack_error("JackNetUnixSocket : ECONNABORTED");
00488                 break;
00489             case ECONNREFUSED:
00490                 jack_error("JackNetUnixSocket : ECONNREFUSED");
00491                 break;
00492             case ECONNRESET:
00493                 jack_error("JackNetUnixSocket : ECONNRESET");
00494                 break;
00495             case EINVAL:
00496                 jack_error("JackNetUnixSocket : EINVAL");
00497                 break;
00498             case EHOSTDOWN:
00499                 jack_error("JackNetUnixSocket : EHOSTDOWN");
00500                 break;
00501             case EHOSTUNREACH:
00502                 jack_error("JackNetUnixSocket : EHOSTUNREACH");
00503                 break;
00504             case ENETDOWN:
00505                 jack_error("JackNetUnixSocket : ENETDOWN");
00506                 break;
00507             case ENETUNREACH:
00508                 jack_error("JackNetUnixSocket : ENETUNREACH");
00509                 break;
00510             default:
00511                 jack_error("JackNetUnixSocket : %d", errno);
00512                 break;
00513         }
00514     }    
00515 }