CArchNetworkBSD.cpp

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

Generated on Fri Nov 6 00:18:44 2009 for synergy-plus by  doxygen 1.4.7