• Main Page
  • Classes
  • Files
  • File List

CArchNetworkBSD.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2012 Bolton Software Ltd.
00004  * Copyright (C) 2002 Chris Schoeneman
00005  * 
00006  * This package is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * found in the file COPYING that should have accompanied this file.
00009  * 
00010  * This package is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "CArchNetworkBSD.h"
00020 #include "CArch.h"
00021 #include "CArchMultithreadPosix.h"
00022 #include "XArchUnix.h"
00023 #if HAVE_UNISTD_H
00024 #   include <unistd.h>
00025 #endif
00026 #include <netinet/in.h>
00027 #include <netdb.h>
00028 #if !defined(TCP_NODELAY)
00029 #   include <netinet/tcp.h>
00030 #endif
00031 #include <arpa/inet.h>
00032 #include <fcntl.h>
00033 #include <errno.h>
00034 #include <string.h>
00035 
00036 #if HAVE_POLL
00037 #   include <poll.h>
00038 #else
00039 #   if HAVE_SYS_SELECT_H
00040 #       include <sys/select.h>
00041 #   endif
00042 #   if HAVE_SYS_TIME_H
00043 #       include <sys/time.h>
00044 #   endif
00045 #endif
00046 
00047 #if !HAVE_INET_ATON
00048 #   include <stdio.h>
00049 #endif
00050 
00051 static const int s_family[] = {
00052     PF_UNSPEC,
00053     PF_INET
00054 };
00055 static const int s_type[] = {
00056     SOCK_DGRAM,
00057     SOCK_STREAM
00058 };
00059 
00060 #if !HAVE_INET_ATON
00061 // parse dotted quad addresses.  we don't bother with the weird BSD'ism
00062 // of handling octal and hex and partial forms.
00063 static
00064 in_addr_t
00065 inet_aton(const char* cp, struct in_addr* inp)
00066 {
00067     unsigned int a, b, c, d;
00068     if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
00069         return 0;
00070     }
00071     if (a >= 256 || b >= 256 || c >= 256 || d >= 256) {
00072         return 0;
00073     }
00074     unsigned char* incp = (unsigned char*)inp;
00075     incp[0] = (unsigned char)(a & 0xffu);
00076     incp[1] = (unsigned char)(b & 0xffu);
00077     incp[2] = (unsigned char)(c & 0xffu);
00078     incp[3] = (unsigned char)(d & 0xffu);
00079     return inp->s_addr;
00080 }
00081 #endif
00082 
00083 //
00084 // CArchNetworkBSD
00085 //
00086 
00087 CArchNetworkBSD::CArchNetworkBSD()
00088 {
00089 }
00090 
00091 CArchNetworkBSD::~CArchNetworkBSD()
00092 {
00093     ARCH->closeMutex(m_mutex);
00094 }
00095 
00096 void
00097 CArchNetworkBSD::init()
00098 {
00099     // create mutex to make some calls thread safe
00100     m_mutex = ARCH->newMutex();
00101 }
00102 
00103 CArchSocket
00104 CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
00105 {
00106     // create socket
00107     int fd = socket(s_family[family], s_type[type], 0);
00108     if (fd == -1) {
00109         throwError(errno);
00110     }
00111     try {
00112         setBlockingOnSocket(fd, false);
00113     }
00114     catch (...) {
00115         close(fd);
00116         throw;
00117     }
00118 
00119     // allocate socket object
00120     CArchSocketImpl* newSocket = new CArchSocketImpl;
00121     newSocket->m_fd            = fd;
00122     newSocket->m_refCount      = 1;
00123     return newSocket;
00124 }
00125 
00126 CArchSocket
00127 CArchNetworkBSD::copySocket(CArchSocket s)
00128 {
00129     assert(s != NULL);
00130 
00131     // ref the socket and return it
00132     ARCH->lockMutex(m_mutex);
00133     ++s->m_refCount;
00134     ARCH->unlockMutex(m_mutex);
00135     return s;
00136 }
00137 
00138 void
00139 CArchNetworkBSD::closeSocket(CArchSocket s)
00140 {
00141     assert(s != NULL);
00142 
00143     // unref the socket and note if it should be released
00144     ARCH->lockMutex(m_mutex);
00145     const bool doClose = (--s->m_refCount == 0);
00146     ARCH->unlockMutex(m_mutex);
00147 
00148     // close the socket if necessary
00149     if (doClose) {
00150         if (close(s->m_fd) == -1) {
00151             // close failed.  restore the last ref and throw.
00152             int err = errno;
00153             ARCH->lockMutex(m_mutex);
00154             ++s->m_refCount;
00155             ARCH->unlockMutex(m_mutex);
00156             throwError(err);
00157         }
00158         delete s;
00159     }
00160 }
00161 
00162 void
00163 CArchNetworkBSD::closeSocketForRead(CArchSocket s)
00164 {
00165     assert(s != NULL);
00166 
00167     if (shutdown(s->m_fd, 0) == -1) {
00168         if (errno != ENOTCONN) {
00169             throwError(errno);
00170         }
00171     }
00172 }
00173 
00174 void
00175 CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
00176 {
00177     assert(s != NULL);
00178 
00179     if (shutdown(s->m_fd, 1) == -1) {
00180         if (errno != ENOTCONN) {
00181             throwError(errno);
00182         }
00183     }
00184 }
00185 
00186 void
00187 CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
00188 {
00189     assert(s    != NULL);
00190     assert(addr != NULL);
00191 
00192     if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
00193         throwError(errno);
00194     }
00195 }
00196 
00197 void
00198 CArchNetworkBSD::listenOnSocket(CArchSocket s)
00199 {
00200     assert(s != NULL);
00201 
00202     // hardcoding backlog
00203     if (listen(s->m_fd, 3) == -1) {
00204         throwError(errno);
00205     }
00206 }
00207 
00208 CArchSocket
00209 CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
00210 {
00211     assert(s != NULL);
00212 
00213     // if user passed NULL in addr then use scratch space
00214     CArchNetAddress dummy;
00215     if (addr == NULL) {
00216         addr = &dummy;
00217     }
00218 
00219     // create new socket and address
00220     CArchSocketImpl* newSocket = new CArchSocketImpl;
00221     *addr                      = new CArchNetAddressImpl;
00222 
00223     // accept on socket
00224     ACCEPT_TYPE_ARG3 len = (ACCEPT_TYPE_ARG3)((*addr)->m_len);
00225     int fd = accept(s->m_fd, &(*addr)->m_addr, &len);
00226     (*addr)->m_len = (socklen_t)len;
00227     if (fd == -1) {
00228         int err = errno;
00229         delete newSocket;
00230         delete *addr;
00231         *addr = NULL;
00232         if (err == EAGAIN) {
00233             return NULL;
00234         }
00235         throwError(err);
00236     }
00237 
00238     try {
00239         setBlockingOnSocket(fd, false);
00240     }
00241     catch (...) {
00242         close(fd);
00243         delete newSocket;
00244         delete *addr;
00245         *addr = NULL;
00246         throw;
00247     }
00248 
00249     // initialize socket
00250     newSocket->m_fd       = fd;
00251     newSocket->m_refCount = 1;
00252 
00253     // discard address if not requested
00254     if (addr == &dummy) {
00255         ARCH->closeAddr(dummy);
00256     }
00257 
00258     return newSocket;
00259 }
00260 
00261 bool
00262 CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
00263 {
00264     assert(s    != NULL);
00265     assert(addr != NULL);
00266 
00267     if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
00268         if (errno == EISCONN) {
00269             return true;
00270         }
00271         if (errno == EINPROGRESS) {
00272             return false;
00273         }
00274         throwError(errno);
00275     }
00276     return true;
00277 }
00278 
00279 #if HAVE_POLL
00280 
00281 int
00282 CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
00283 {
00284     assert(pe != NULL || num == 0);
00285 
00286     // return if nothing to do
00287     if (num == 0) {
00288         if (timeout > 0.0) {
00289             ARCH->sleep(timeout);
00290         }
00291         return 0;
00292     }
00293 
00294     // allocate space for translated query
00295     struct pollfd* pfd = new struct pollfd[1 + num];
00296 
00297     // translate query
00298     for (int i = 0; i < num; ++i) {
00299         pfd[i].fd     = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
00300         pfd[i].events = 0;
00301         if ((pe[i].m_events & kPOLLIN) != 0) {
00302             pfd[i].events |= POLLIN;
00303         }
00304         if ((pe[i].m_events & kPOLLOUT) != 0) {
00305             pfd[i].events |= POLLOUT;
00306         }
00307     }
00308     int n = num;
00309 
00310     // add the unblock pipe
00311     const int* unblockPipe = getUnblockPipe();
00312     if (unblockPipe != NULL) {
00313         pfd[n].fd     = unblockPipe[0];
00314         pfd[n].events = POLLIN;
00315         ++n;
00316     }
00317 
00318     // prepare timeout
00319     int t = (timeout < 0.0) ? -1 : static_cast<int>(1000.0 * timeout);
00320 
00321     // do the poll
00322     n = poll(pfd, n, t);
00323 
00324     // reset the unblock pipe
00325     if (n > 0 && unblockPipe != NULL && (pfd[num].revents & POLLIN) != 0) {
00326         // the unblock event was signalled.  flush the pipe.
00327         char dummy[100];
00328         int ignore;
00329 
00330         do {
00331             ignore = read(unblockPipe[0], dummy, sizeof(dummy));
00332         } while (errno != EAGAIN);
00333 
00334         // don't count this unblock pipe in return value
00335         --n;
00336     }
00337 
00338     // handle results
00339     if (n == -1) {
00340         if (errno == EINTR) {
00341             // interrupted system call
00342             ARCH->testCancelThread();
00343             delete[] pfd;
00344             return 0;
00345         }
00346         delete[] pfd;
00347         throwError(errno);
00348     }
00349 
00350     // translate back
00351     for (int i = 0; i < num; ++i) {
00352         pe[i].m_revents = 0;
00353         if ((pfd[i].revents & POLLIN) != 0) {
00354             pe[i].m_revents |= kPOLLIN;
00355         }
00356         if ((pfd[i].revents & POLLOUT) != 0) {
00357             pe[i].m_revents |= kPOLLOUT;
00358         }
00359         if ((pfd[i].revents & POLLERR) != 0) {
00360             pe[i].m_revents |= kPOLLERR;
00361         }
00362         if ((pfd[i].revents & POLLNVAL) != 0) {
00363             pe[i].m_revents |= kPOLLNVAL;
00364         }
00365     }
00366 
00367     delete[] pfd;
00368     return n;
00369 }
00370 
00371 #else
00372 
00373 int
00374 CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
00375 {
00376     int i, n;
00377 
00378     // prepare sets for select
00379     n = 0;
00380     fd_set readSet, writeSet, errSet;
00381     fd_set* readSetP  = NULL;
00382     fd_set* writeSetP = NULL;
00383     fd_set* errSetP   = NULL;
00384     FD_ZERO(&readSet);
00385     FD_ZERO(&writeSet);
00386     FD_ZERO(&errSet);
00387     for (i = 0; i < num; ++i) {
00388         // reset return flags
00389         pe[i].m_revents = 0;
00390 
00391         // set invalid flag if socket is bogus then go to next socket
00392         if (pe[i].m_socket == NULL) {
00393             pe[i].m_revents |= kPOLLNVAL;
00394             continue;
00395         }
00396 
00397         int fdi = pe[i].m_socket->m_fd;
00398         if (pe[i].m_events & kPOLLIN) {
00399             FD_SET(pe[i].m_socket->m_fd, &readSet);
00400             readSetP = &readSet;
00401             if (fdi > n) {
00402                 n = fdi;
00403             }
00404         }
00405         if (pe[i].m_events & kPOLLOUT) {
00406             FD_SET(pe[i].m_socket->m_fd, &writeSet);
00407             writeSetP = &writeSet;
00408             if (fdi > n) {
00409                 n = fdi;
00410             }
00411         }
00412         if (true) {
00413             FD_SET(pe[i].m_socket->m_fd, &errSet);
00414             errSetP = &errSet;
00415             if (fdi > n) {
00416                 n = fdi;
00417             }
00418         }
00419     }
00420 
00421     // add the unblock pipe
00422     const int* unblockPipe = getUnblockPipe();
00423     if (unblockPipe != NULL) {
00424         FD_SET(unblockPipe[0], &readSet);
00425         readSetP = &readSet;
00426         if (unblockPipe[0] > n) {
00427             n = unblockPipe[0];
00428         }
00429     }
00430 
00431     // if there are no sockets then don't block forever
00432     if (n == 0 && timeout < 0.0) {
00433         timeout = 0.0;
00434     }
00435 
00436     // prepare timeout for select
00437     struct timeval timeout2;
00438     struct timeval* timeout2P;
00439     if (timeout < 0.0) {
00440         timeout2P = NULL;
00441     }
00442     else {
00443         timeout2P = &timeout2;
00444         timeout2.tv_sec  = static_cast<int>(timeout);
00445         timeout2.tv_usec = static_cast<int>(1.0e+6 *
00446                                         (timeout - timeout2.tv_sec));
00447     }
00448 
00449     // do the select
00450     n = select((SELECT_TYPE_ARG1)  n + 1,
00451                 SELECT_TYPE_ARG234 readSetP,
00452                 SELECT_TYPE_ARG234 writeSetP,
00453                 SELECT_TYPE_ARG234 errSetP,
00454                 SELECT_TYPE_ARG5   timeout2P);
00455 
00456     // reset the unblock pipe
00457     if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) {
00458         // the unblock event was signalled.  flush the pipe.
00459         char dummy[100];
00460         do {
00461             read(unblockPipe[0], dummy, sizeof(dummy));
00462         } while (errno != EAGAIN);
00463     }
00464 
00465     // handle results
00466     if (n == -1) {
00467         if (errno == EINTR) {
00468             // interrupted system call
00469             ARCH->testCancelThread();
00470             return 0;
00471         }
00472         throwError(errno);
00473     }
00474     n = 0;
00475     for (i = 0; i < num; ++i) {
00476         if (pe[i].m_socket != NULL) {
00477             if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
00478                 pe[i].m_revents |= kPOLLIN;
00479             }
00480             if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
00481                 pe[i].m_revents |= kPOLLOUT;
00482             }
00483             if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
00484                 pe[i].m_revents |= kPOLLERR;
00485             }
00486         }
00487         if (pe[i].m_revents != 0) {
00488             ++n;
00489         }
00490     }
00491 
00492     return n;
00493 }
00494 
00495 #endif
00496 
00497 void
00498 CArchNetworkBSD::unblockPollSocket(CArchThread thread)
00499 {
00500     const int* unblockPipe = getUnblockPipeForThread(thread);
00501     if (unblockPipe != NULL) {
00502         char dummy = 0;
00503         int ignore;
00504 
00505         ignore = write(unblockPipe[1], &dummy, 1);
00506     }
00507 }
00508 
00509 size_t
00510 CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
00511 {
00512     assert(s != NULL);
00513 
00514     ssize_t n = read(s->m_fd, buf, len);
00515     if (n == -1) {
00516         if (errno == EINTR || errno == EAGAIN) {
00517             return 0;
00518         }
00519         throwError(errno);
00520     }
00521     return n;
00522 }
00523 
00524 size_t
00525 CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
00526 {
00527     assert(s != NULL);
00528 
00529     ssize_t n = write(s->m_fd, buf, len);
00530     if (n == -1) {
00531         if (errno == EINTR || errno == EAGAIN) {
00532             return 0;
00533         }
00534         throwError(errno);
00535     }
00536     return n;
00537 }
00538 
00539 void
00540 CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
00541 {
00542     assert(s != NULL);
00543 
00544     // get the error from the socket layer
00545     int err        = 0;
00546     socklen_t size = (socklen_t)sizeof(err);
00547     if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR,
00548                             (optval_t*)&err, &size) == -1) {
00549         err = errno;
00550     }
00551 
00552     // throw if there's an error
00553     if (err != 0) {
00554         throwError(err);
00555     }
00556 }
00557 
00558 void
00559 CArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
00560 {
00561     assert(fd != -1);
00562 
00563     int mode = fcntl(fd, F_GETFL, 0);
00564     if (mode == -1) {
00565         throwError(errno);
00566     }
00567     if (blocking) {
00568         mode &= ~O_NONBLOCK;
00569     }
00570     else {
00571         mode |= O_NONBLOCK;
00572     }
00573     if (fcntl(fd, F_SETFL, mode) == -1) {
00574         throwError(errno);
00575     }
00576 }
00577 
00578 bool
00579 CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
00580 {
00581     assert(s != NULL);
00582 
00583     // get old state
00584     int oflag;
00585     socklen_t size = (socklen_t)sizeof(oflag);
00586     if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
00587                             (optval_t*)&oflag, &size) == -1) {
00588         throwError(errno);
00589     }
00590 
00591     int flag = noDelay ? 1 : 0;
00592     size     = (socklen_t)sizeof(flag);
00593     if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
00594                             (optval_t*)&flag, size) == -1) {
00595         throwError(errno);
00596     }
00597 
00598     return (oflag != 0);
00599 }
00600 
00601 bool
00602 CArchNetworkBSD::setReuseAddrOnSocket(CArchSocket s, bool reuse)
00603 {
00604     assert(s != NULL);
00605 
00606     // get old state
00607     int oflag;
00608     socklen_t size = (socklen_t)sizeof(oflag);
00609     if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
00610                             (optval_t*)&oflag, &size) == -1) {
00611         throwError(errno);
00612     }
00613 
00614     int flag = reuse ? 1 : 0;
00615     size     = (socklen_t)sizeof(flag);
00616     if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
00617                             (optval_t*)&flag, size) == -1) {
00618         throwError(errno);
00619     }
00620 
00621     return (oflag != 0);
00622 }
00623 
00624 std::string
00625 CArchNetworkBSD::getHostName()
00626 {
00627     char name[256];
00628     if (gethostname(name, sizeof(name)) == -1) {
00629         name[0] = '\0';
00630     }
00631     else {
00632         name[sizeof(name) - 1] = '\0';
00633     }
00634     return name;
00635 }
00636 
00637 CArchNetAddress
00638 CArchNetworkBSD::newAnyAddr(EAddressFamily family)
00639 {
00640     // allocate address
00641     CArchNetAddressImpl* addr = new CArchNetAddressImpl;
00642 
00643     // fill it in
00644     switch (family) {
00645     case kINET: {
00646         struct sockaddr_in* ipAddr =
00647             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00648         ipAddr->sin_family         = AF_INET;
00649         ipAddr->sin_port           = 0;
00650         ipAddr->sin_addr.s_addr    = INADDR_ANY;
00651         addr->m_len                = (socklen_t)sizeof(struct sockaddr_in);
00652         break;
00653     }
00654 
00655     default:
00656         delete addr;
00657         assert(0 && "invalid family");
00658     }
00659 
00660     return addr;
00661 }
00662 
00663 CArchNetAddress
00664 CArchNetworkBSD::copyAddr(CArchNetAddress addr)
00665 {
00666     assert(addr != NULL);
00667 
00668     // allocate and copy address
00669     return new CArchNetAddressImpl(*addr);
00670 }
00671 
00672 CArchNetAddress
00673 CArchNetworkBSD::nameToAddr(const std::string& name)
00674 {
00675     // allocate address
00676     CArchNetAddressImpl* addr = new CArchNetAddressImpl;
00677 
00678     // try to convert assuming an IPv4 dot notation address
00679     struct sockaddr_in inaddr;
00680     memset(&inaddr, 0, sizeof(inaddr));
00681     if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
00682         // it's a dot notation address
00683         addr->m_len       = (socklen_t)sizeof(struct sockaddr_in);
00684         inaddr.sin_family = AF_INET;
00685         inaddr.sin_port   = 0;
00686         memcpy(&addr->m_addr, &inaddr, addr->m_len);
00687     }
00688 
00689     else {
00690         // mutexed address lookup (ugh)
00691         ARCH->lockMutex(m_mutex);
00692         struct hostent* info = gethostbyname(name.c_str());
00693         if (info == NULL) {
00694             ARCH->unlockMutex(m_mutex);
00695             delete addr;
00696             throwNameError(h_errno);
00697         }
00698 
00699         // copy over address (only IPv4 currently supported)
00700         if (info->h_addrtype == AF_INET) {
00701             addr->m_len       = (socklen_t)sizeof(struct sockaddr_in);
00702             inaddr.sin_family = info->h_addrtype;
00703             inaddr.sin_port   = 0;
00704             memcpy(&inaddr.sin_addr, info->h_addr_list[0],
00705                                 sizeof(inaddr.sin_addr));
00706             memcpy(&addr->m_addr, &inaddr, addr->m_len);
00707         }
00708         else {
00709             ARCH->unlockMutex(m_mutex);
00710             delete addr;
00711             throw XArchNetworkNameUnsupported(
00712                     "The requested name is valid but "
00713                     "does not have a supported address family");
00714         }
00715 
00716         // done with static buffer
00717         ARCH->unlockMutex(m_mutex);
00718     }
00719 
00720     return addr;
00721 }
00722 
00723 void
00724 CArchNetworkBSD::closeAddr(CArchNetAddress addr)
00725 {
00726     assert(addr != NULL);
00727 
00728     delete addr;
00729 }
00730 
00731 std::string
00732 CArchNetworkBSD::addrToName(CArchNetAddress addr)
00733 {
00734     assert(addr != NULL);
00735 
00736     // mutexed name lookup (ugh)
00737     ARCH->lockMutex(m_mutex);
00738     struct hostent* info = gethostbyaddr(
00739                             reinterpret_cast<const char*>(&addr->m_addr),
00740                             addr->m_len, addr->m_addr.sa_family);
00741     if (info == NULL) {
00742         ARCH->unlockMutex(m_mutex);
00743         throwNameError(h_errno);
00744     }
00745 
00746     // save (primary) name
00747     std::string name = info->h_name;
00748 
00749     // done with static buffer
00750     ARCH->unlockMutex(m_mutex);
00751 
00752     return name;
00753 }
00754 
00755 std::string
00756 CArchNetworkBSD::addrToString(CArchNetAddress addr)
00757 {
00758     assert(addr != NULL);
00759 
00760     switch (getAddrFamily(addr)) {
00761     case kINET: {
00762         struct sockaddr_in* ipAddr =
00763             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00764         ARCH->lockMutex(m_mutex);
00765         std::string s = inet_ntoa(ipAddr->sin_addr);
00766         ARCH->unlockMutex(m_mutex);
00767         return s;
00768     }
00769 
00770     default:
00771         assert(0 && "unknown address family");
00772         return "";
00773     }
00774 }
00775 
00776 IArchNetwork::EAddressFamily
00777 CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
00778 {
00779     assert(addr != NULL);
00780 
00781     switch (addr->m_addr.sa_family) {
00782     case AF_INET:
00783         return kINET;
00784 
00785     default:
00786         return kUNKNOWN;
00787     }
00788 }
00789 
00790 void
00791 CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
00792 {
00793     assert(addr != NULL);
00794 
00795     switch (getAddrFamily(addr)) {
00796     case kINET: {
00797         struct sockaddr_in* ipAddr =
00798             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00799         ipAddr->sin_port = htons(port);
00800         break;
00801     }
00802 
00803     default:
00804         assert(0 && "unknown address family");
00805         break;
00806     }
00807 }
00808 
00809 int
00810 CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
00811 {
00812     assert(addr != NULL);
00813 
00814     switch (getAddrFamily(addr)) {
00815     case kINET: {
00816         struct sockaddr_in* ipAddr =
00817             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00818         return ntohs(ipAddr->sin_port);
00819     }
00820 
00821     default:
00822         assert(0 && "unknown address family");
00823         return 0;
00824     }
00825 }
00826 
00827 bool
00828 CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
00829 {
00830     assert(addr != NULL);
00831 
00832     switch (getAddrFamily(addr)) {
00833     case kINET: {
00834         struct sockaddr_in* ipAddr =
00835             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00836         return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
00837                 addr->m_len == (socklen_t)sizeof(struct sockaddr_in));
00838     }
00839 
00840     default:
00841         assert(0 && "unknown address family");
00842         return true;
00843     }
00844 }
00845 
00846 bool
00847 CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
00848 {
00849     return (a->m_len == b->m_len &&
00850             memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
00851 }
00852 
00853 const int*
00854 CArchNetworkBSD::getUnblockPipe()
00855 {
00856     CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
00857     CArchThread thread        = mt->newCurrentThread();
00858     const int* p              = getUnblockPipeForThread(thread);
00859     ARCH->closeThread(thread);
00860     return p;
00861 }
00862 
00863 const int*
00864 CArchNetworkBSD::getUnblockPipeForThread(CArchThread thread)
00865 {
00866     CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
00867     int* unblockPipe          = (int*)mt->getNetworkDataForThread(thread);
00868     if (unblockPipe == NULL) {
00869         unblockPipe = new int[2];
00870         if (pipe(unblockPipe) != -1) {
00871             try {
00872                 setBlockingOnSocket(unblockPipe[0], false);
00873                 mt->setNetworkDataForCurrentThread(unblockPipe);
00874             }
00875             catch (...) {
00876                 delete[] unblockPipe;
00877                 unblockPipe = NULL;
00878             }
00879         }
00880         else {
00881             delete[] unblockPipe;
00882             unblockPipe = NULL;
00883         }
00884     }
00885     return unblockPipe;
00886 }
00887 
00888 void
00889 CArchNetworkBSD::throwError(int err)
00890 {
00891     switch (err) {
00892     case EINTR:
00893         ARCH->testCancelThread();
00894         throw XArchNetworkInterrupted(new XArchEvalUnix(err));
00895 
00896     case EACCES:
00897     case EPERM:
00898         throw XArchNetworkAccess(new XArchEvalUnix(err));
00899 
00900     case ENFILE:
00901     case EMFILE:
00902     case ENODEV:
00903     case ENOBUFS:
00904     case ENOMEM:
00905     case ENETDOWN:
00906 #if defined(ENOSR)
00907     case ENOSR:
00908 #endif
00909         throw XArchNetworkResource(new XArchEvalUnix(err));
00910 
00911     case EPROTOTYPE:
00912     case EPROTONOSUPPORT:
00913     case EAFNOSUPPORT:
00914     case EPFNOSUPPORT:
00915     case ESOCKTNOSUPPORT:
00916     case EINVAL:
00917     case ENOPROTOOPT:
00918     case EOPNOTSUPP:
00919     case ESHUTDOWN:
00920 #if defined(ENOPKG)
00921     case ENOPKG:
00922 #endif
00923         throw XArchNetworkSupport(new XArchEvalUnix(err));
00924 
00925     case EIO:
00926         throw XArchNetworkIO(new XArchEvalUnix(err));
00927 
00928     case EADDRNOTAVAIL:
00929         throw XArchNetworkNoAddress(new XArchEvalUnix(err));
00930 
00931     case EADDRINUSE:
00932         throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
00933 
00934     case EHOSTUNREACH:
00935     case ENETUNREACH:
00936         throw XArchNetworkNoRoute(new XArchEvalUnix(err));
00937 
00938     case ENOTCONN:
00939         throw XArchNetworkNotConnected(new XArchEvalUnix(err));
00940 
00941     case EPIPE:
00942         throw XArchNetworkShutdown(new XArchEvalUnix(err));
00943 
00944     case ECONNABORTED:
00945     case ECONNRESET:
00946         throw XArchNetworkDisconnected(new XArchEvalUnix(err));
00947 
00948     case ECONNREFUSED:
00949         throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
00950 
00951     case EHOSTDOWN:
00952     case ETIMEDOUT:
00953         throw XArchNetworkTimedOut(new XArchEvalUnix(err));
00954 
00955     default:
00956         throw XArchNetwork(new XArchEvalUnix(err));
00957     }
00958 }
00959 
00960 void
00961 CArchNetworkBSD::throwNameError(int err)
00962 {
00963     static const char* s_msg[] = {
00964         "The specified host is unknown",
00965         "The requested name is valid but does not have an IP address",
00966         "A non-recoverable name server error occurred",
00967         "A temporary error occurred on an authoritative name server",
00968         "An unknown name server error occurred"
00969     };
00970 
00971     switch (err) {
00972     case HOST_NOT_FOUND:
00973         throw XArchNetworkNameUnknown(s_msg[0]);
00974 
00975     case NO_DATA:
00976         throw XArchNetworkNameNoAddress(s_msg[1]);
00977 
00978     case NO_RECOVERY:
00979         throw XArchNetworkNameFailure(s_msg[2]);
00980 
00981     case TRY_AGAIN:
00982         throw XArchNetworkNameUnavailable(s_msg[3]);
00983 
00984     default:
00985         throw XArchNetworkName(s_msg[4]);
00986     }
00987 }

Generated on Wed Jun 19 2013 00:00:04 for Synergy by  doxygen 1.7.1