CArchNetworkWinsock.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 
00016 #include "CArchNetworkWinsock.h"
00017 #include "CArch.h"
00018 #include "CArchMultithreadWindows.h"
00019 #include "IArchMultithread.h"
00020 #include "XArchWindows.h"
00021 #include <malloc.h>
00022 
00023 static const int s_family[] = {
00024     PF_UNSPEC,
00025     PF_INET
00026 };
00027 static const int s_type[] = {
00028     SOCK_DGRAM,
00029     SOCK_STREAM
00030 };
00031 
00032 static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
00033 static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
00034 static int (PASCAL FAR *close_winsock)(SOCKET s);
00035 static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen);
00036 static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen);
00037 static int (PASCAL FAR *getsockerror_winsock)(void);
00038 static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen);
00039 static u_short (PASCAL FAR *htons_winsock)(u_short v);
00040 static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in);
00041 static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp);
00042 static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR * data);
00043 static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog);
00044 static u_short (PASCAL FAR *ntohs_winsock)(u_short v);
00045 static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags);
00046 static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
00047 static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags);
00048 static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen);
00049 static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how);
00050 static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol);
00051 static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type);
00052 static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
00053 static int (PASCAL FAR *WSACleanup_winsock)(void);
00054 static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset);
00055 static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void);
00056 static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT);
00057 static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT);
00058 static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT);
00059 static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long);
00060 static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL);
00061 static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS);
00062 
00063 #undef FD_ISSET
00064 #define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
00065 
00066 #define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
00067 
00068 static HMODULE          s_networkModule = NULL;
00069 
00070 static
00071 FARPROC
00072 netGetProcAddress(HMODULE module, LPCSTR name)
00073 {
00074     FARPROC func = ::GetProcAddress(module, name);
00075     if (!func) {
00076         throw XArchNetworkSupport("");
00077     }
00078     return func;
00079 }
00080 
00081 CArchNetAddressImpl*
00082 CArchNetAddressImpl::alloc(size_t size)
00083 {
00084     size_t totalSize          = size + ADDR_HDR_SIZE;
00085     CArchNetAddressImpl* addr = (CArchNetAddressImpl*)malloc(totalSize);
00086     addr->m_len               = size;
00087     return addr;
00088 }
00089 
00090 
00091 //
00092 // CArchNetworkWinsock
00093 //
00094 
00095 CArchNetworkWinsock::CArchNetworkWinsock()
00096 {
00097     static const char* s_library[] = { "ws2_32.dll" };
00098 
00099     assert(WSACleanup_winsock == NULL);
00100     assert(s_networkModule    == NULL);
00101 
00102     // try each winsock library
00103     for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) {
00104         try {
00105             init((HMODULE)::LoadLibrary(s_library[i]));
00106             m_mutex = ARCH->newMutex();
00107             return;
00108         }
00109         catch (XArchNetwork&) {
00110             // ignore
00111         }
00112     }
00113 
00114     // can't initialize any library
00115     throw XArchNetworkSupport("Cannot load winsock library");
00116 }
00117 
00118 CArchNetworkWinsock::~CArchNetworkWinsock()
00119 {
00120     if (s_networkModule != NULL) {
00121         WSACleanup_winsock();
00122         ::FreeLibrary(s_networkModule);
00123 
00124         WSACleanup_winsock = NULL;
00125         s_networkModule    = NULL;
00126     }
00127     ARCH->closeMutex(m_mutex);
00128 }
00129 
00130 void
00131 CArchNetworkWinsock::init(HMODULE module)
00132 {
00133     if (module == NULL) {
00134         throw XArchNetworkSupport("");
00135     }
00136 
00137     // get startup function address
00138     int (PASCAL FAR *startup)(WORD, LPWSADATA);
00139     setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
00140 
00141     // startup network library
00142     WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/);
00143     WSADATA data;
00144     int err = startup(version, &data);
00145     if (data.wVersion != version) {
00146         throw XArchNetworkSupport(new XArchEvalWinsock(err));
00147     }
00148     if (err != 0) {
00149         // some other initialization error
00150         throwError(err);
00151     }
00152 
00153     // get function addresses
00154     setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen));
00155     setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen));
00156     setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s));
00157     setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen));
00158     setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
00159     setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void));
00160     setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen));
00161     setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v));
00162     setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
00163     setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
00164     setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *));
00165     setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog));
00166     setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v));
00167     setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags));
00168     setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
00169     setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags));
00170     setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen));
00171     setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how));
00172     setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol));
00173     setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
00174     setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
00175     setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
00176     setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
00177     setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void));
00178     setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT));
00179     setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
00180     setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
00181     setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long));
00182     setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL));
00183     setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
00184 
00185     s_networkModule = module;
00186 }
00187 
00188 CArchSocket
00189 CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
00190 {
00191     // create socket
00192     SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
00193     if (fd == INVALID_SOCKET) {
00194         throwError(getsockerror_winsock());
00195     }
00196     try {
00197         setBlockingOnSocket(fd, false);
00198     }
00199     catch (...) {
00200         close_winsock(fd);
00201         throw;
00202     }
00203 
00204     // allocate socket object
00205     CArchSocketImpl* socket = new CArchSocketImpl;
00206     socket->m_socket        = fd;
00207     socket->m_refCount      = 1;
00208     socket->m_event         = WSACreateEvent_winsock();
00209     socket->m_pollWrite     = true;
00210     return socket;
00211 }
00212 
00213 CArchSocket
00214 CArchNetworkWinsock::copySocket(CArchSocket s)
00215 {
00216     assert(s != NULL);
00217 
00218     // ref the socket and return it
00219     ARCH->lockMutex(m_mutex);
00220     ++s->m_refCount;
00221     ARCH->unlockMutex(m_mutex);
00222     return s;
00223 }
00224 
00225 void
00226 CArchNetworkWinsock::closeSocket(CArchSocket s)
00227 {
00228     assert(s != NULL);
00229 
00230     // unref the socket and note if it should be released
00231     ARCH->lockMutex(m_mutex);
00232     const bool doClose = (--s->m_refCount == 0);
00233     ARCH->unlockMutex(m_mutex);
00234 
00235     // close the socket if necessary
00236     if (doClose) {
00237         if (close_winsock(s->m_socket) == SOCKET_ERROR) {
00238             // close failed.  restore the last ref and throw.
00239             int err = getsockerror_winsock();
00240             ARCH->lockMutex(m_mutex);
00241             ++s->m_refCount;
00242             ARCH->unlockMutex(m_mutex);
00243             throwError(err);
00244         }
00245         WSACloseEvent_winsock(s->m_event);
00246         delete s;
00247     }
00248 }
00249 
00250 void
00251 CArchNetworkWinsock::closeSocketForRead(CArchSocket s)
00252 {
00253     assert(s != NULL);
00254 
00255     if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
00256         if (getsockerror_winsock() != WSAENOTCONN) {
00257             throwError(getsockerror_winsock());
00258         }
00259     }
00260 }
00261 
00262 void
00263 CArchNetworkWinsock::closeSocketForWrite(CArchSocket s)
00264 {
00265     assert(s != NULL);
00266 
00267     if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
00268         if (getsockerror_winsock() != WSAENOTCONN) {
00269             throwError(getsockerror_winsock());
00270         }
00271     }
00272 }
00273 
00274 void
00275 CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr)
00276 {
00277     assert(s    != NULL);
00278     assert(addr != NULL);
00279 
00280     if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) {
00281         throwError(getsockerror_winsock());
00282     }
00283 }
00284 
00285 void
00286 CArchNetworkWinsock::listenOnSocket(CArchSocket s)
00287 {
00288     assert(s != NULL);
00289 
00290     // hardcoding backlog
00291     if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
00292         throwError(getsockerror_winsock());
00293     }
00294 }
00295 
00296 CArchSocket
00297 CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
00298 {
00299     assert(s != NULL);
00300 
00301     // create new socket and temporary address
00302     CArchSocketImpl* socket = new CArchSocketImpl;
00303     CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
00304 
00305     // accept on socket
00306     SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
00307     if (fd == INVALID_SOCKET) {
00308         int err = getsockerror_winsock();
00309         delete socket;
00310         free(tmp);
00311         *addr = NULL;
00312         if (err == WSAEWOULDBLOCK) {
00313             return NULL;
00314         }
00315         throwError(err);
00316     }
00317 
00318     try {
00319         setBlockingOnSocket(fd, false);
00320     }
00321     catch (...) {
00322         close_winsock(fd);
00323         delete socket;
00324         free(tmp);
00325         *addr = NULL;
00326         throw;
00327     }
00328 
00329     // initialize socket
00330     socket->m_socket    = fd;
00331     socket->m_refCount  = 1;
00332     socket->m_event     = WSACreateEvent_winsock();
00333     socket->m_pollWrite = true;
00334 
00335     // copy address if requested
00336     if (addr != NULL) {
00337         *addr = ARCH->copyAddr(tmp);
00338     }
00339 
00340     free(tmp);
00341     return socket;
00342 }
00343 
00344 bool
00345 CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
00346 {
00347     assert(s    != NULL);
00348     assert(addr != NULL);
00349 
00350     if (connect_winsock(s->m_socket, &addr->m_addr,
00351                             addr->m_len) == SOCKET_ERROR) {
00352         if (getsockerror_winsock() == WSAEISCONN) {
00353             return true;
00354         }
00355         if (getsockerror_winsock() == WSAEWOULDBLOCK) {
00356             return false;
00357         }
00358         throwError(getsockerror_winsock());
00359     }
00360     return true;
00361 }
00362 
00363 int
00364 CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
00365 {
00366     int i;
00367     DWORD n;
00368 
00369     // prepare sockets and wait list
00370     bool canWrite = false;
00371     WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
00372     for (i = 0, n = 0; i < num; ++i) {
00373         // reset return flags
00374         pe[i].m_revents = 0;
00375 
00376         // set invalid flag if socket is bogus then go to next socket
00377         if (pe[i].m_socket == NULL) {
00378             pe[i].m_revents |= kPOLLNVAL;
00379             continue;
00380         }
00381 
00382         // select desired events
00383         long socketEvents = 0;
00384         if ((pe[i].m_events & kPOLLIN) != 0) {
00385             socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
00386         }
00387         if ((pe[i].m_events & kPOLLOUT) != 0) {
00388             socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
00389 
00390             // if m_pollWrite is false then we assume the socket is
00391             // writable.  winsock doesn't signal writability except
00392             // when the state changes from unwritable.
00393             if (!pe[i].m_socket->m_pollWrite) {
00394                 canWrite         = true;
00395                 pe[i].m_revents |= kPOLLOUT;
00396             }
00397         }
00398 
00399         // if no events then ignore socket
00400         if (socketEvents == 0) {
00401             continue;
00402         }
00403 
00404         // select socket for desired events
00405         WSAEventSelect_winsock(pe[i].m_socket->m_socket,
00406                             pe[i].m_socket->m_event, socketEvents);
00407 
00408         // add socket event to wait list
00409         events[n++] = pe[i].m_socket->m_event;
00410     }
00411 
00412     // if no sockets then return immediately
00413     if (n == 0) {
00414         return 0;
00415     }
00416 
00417     // add the unblock event
00418     CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
00419     CArchThread thread     = mt->newCurrentThread();
00420     WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
00421     ARCH->closeThread(thread);
00422     if (unblockEvent == NULL) {
00423         unblockEvent  = new WSAEVENT;
00424         *unblockEvent = WSACreateEvent_winsock();
00425         mt->setNetworkDataForCurrentThread(unblockEvent);
00426     }
00427     events[n++] = *unblockEvent;
00428 
00429     // prepare timeout
00430     DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
00431     if (canWrite) {
00432         // if we know we can write then don't block
00433         t = 0;
00434     }
00435 
00436     // wait
00437     DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);
00438 
00439     // reset the unblock event
00440     WSAResetEvent_winsock(*unblockEvent);
00441 
00442     // handle results
00443     if (result == WSA_WAIT_FAILED) {
00444         if (getsockerror_winsock() == WSAEINTR) {
00445             // interrupted system call
00446             ARCH->testCancelThread();
00447             return 0;
00448         }
00449         throwError(getsockerror_winsock());
00450     }
00451     if (result == WSA_WAIT_TIMEOUT && !canWrite) {
00452         return 0;
00453     }
00454     if (result == WSA_WAIT_EVENT_0 + n - 1) {
00455         // the unblock event was signalled
00456         return 0;
00457     }
00458     for (i = 0, n = 0; i < num; ++i) {
00459         // skip events we didn't check
00460         if (pe[i].m_socket == NULL ||
00461             (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
00462             continue;
00463         }
00464 
00465         // get events
00466         WSANETWORKEVENTS info;
00467         if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
00468                             pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
00469             continue;
00470         }
00471         if ((info.lNetworkEvents & FD_READ) != 0) {
00472             pe[i].m_revents |= kPOLLIN;
00473         }
00474         if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
00475             pe[i].m_revents |= kPOLLIN;
00476         }
00477         if ((info.lNetworkEvents & FD_WRITE) != 0) {
00478             pe[i].m_revents |= kPOLLOUT;
00479 
00480             // socket is now writable so don't bothing polling for
00481             // writable until it becomes unwritable.
00482             pe[i].m_socket->m_pollWrite = false;
00483         }
00484         if ((info.lNetworkEvents & FD_CONNECT) != 0) {
00485             if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
00486                 pe[i].m_revents |= kPOLLERR;
00487             }
00488             else {
00489                 pe[i].m_revents |= kPOLLOUT;
00490                 pe[i].m_socket->m_pollWrite = false;
00491             }
00492         }
00493         if ((info.lNetworkEvents & FD_CLOSE) != 0) {
00494             if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
00495                 pe[i].m_revents |= kPOLLERR;
00496             }
00497             else {
00498                 if ((pe[i].m_events & kPOLLIN) != 0) {
00499                     pe[i].m_revents |= kPOLLIN;
00500                 }
00501                 if ((pe[i].m_events & kPOLLOUT) != 0) {
00502                     pe[i].m_revents |= kPOLLOUT;
00503                 }
00504             }
00505         }
00506         if (pe[i].m_revents != 0) {
00507             ++n;
00508         }
00509     }
00510 
00511     return (int)n;
00512 }
00513 
00514 void
00515 CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
00516 {
00517     // set the unblock event
00518     CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
00519     WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
00520     if (unblockEvent != NULL) {
00521         WSASetEvent_winsock(*unblockEvent);
00522     }
00523 }
00524 
00525 size_t
00526 CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
00527 {
00528     assert(s != NULL);
00529 
00530     int n = recv_winsock(s->m_socket, buf, len, 0);
00531     if (n == SOCKET_ERROR) {
00532         int err = getsockerror_winsock();
00533         if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
00534             return 0;
00535         }
00536         throwError(err);
00537     }
00538     return static_cast<size_t>(n);
00539 }
00540 
00541 size_t
00542 CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
00543 {
00544     assert(s != NULL);
00545 
00546     int n = send_winsock(s->m_socket, buf, len, 0);
00547     if (n == SOCKET_ERROR) {
00548         int err = getsockerror_winsock();
00549         if (err == WSAEINTR) {
00550             return 0;
00551         }
00552         if (err == WSAEWOULDBLOCK) {
00553             s->m_pollWrite = true;
00554             return 0;
00555         }
00556         throwError(err);
00557     }
00558     return static_cast<size_t>(n);
00559 }
00560 
00561 void
00562 CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s)
00563 {
00564     assert(s != NULL);
00565 
00566     // get the error from the socket layer
00567     int err  = 0;
00568     int size = sizeof(err);
00569     if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
00570                                     SO_ERROR, &err, &size) == SOCKET_ERROR) {
00571         err = getsockerror_winsock();
00572     }
00573 
00574     // throw if there's an error
00575     if (err != 0) {
00576         throwError(err);
00577     }
00578 }
00579 
00580 void
00581 CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
00582 {
00583     assert(s != 0);
00584 
00585     int flag = blocking ? 0 : 1;
00586     if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) {
00587         throwError(getsockerror_winsock());
00588     }
00589 }
00590 
00591 bool
00592 CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay)
00593 {
00594     assert(s != NULL);
00595 
00596     // get old state
00597     BOOL oflag;
00598     int size = sizeof(oflag);
00599     if (getsockopt_winsock(s->m_socket, IPPROTO_TCP,
00600                                 TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) {
00601         throwError(getsockerror_winsock());
00602     }
00603 
00604     // set new state
00605     BOOL flag = noDelay ? 1 : 0;
00606     size     = sizeof(flag);
00607     if (setsockopt_winsock(s->m_socket, IPPROTO_TCP,
00608                                 TCP_NODELAY, &flag, size) == SOCKET_ERROR) {
00609         throwError(getsockerror_winsock());
00610     }
00611 
00612     return (oflag != 0);
00613 }
00614 
00615 bool
00616 CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse)
00617 {
00618     assert(s != NULL);
00619 
00620     // get old state
00621     BOOL oflag;
00622     int size = sizeof(oflag);
00623     if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
00624                                 SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) {
00625         throwError(getsockerror_winsock());
00626     }
00627 
00628     // set new state
00629     BOOL flag = reuse ? 1 : 0;
00630     size     = sizeof(flag);
00631     if (setsockopt_winsock(s->m_socket, SOL_SOCKET,
00632                                 SO_REUSEADDR, &flag, size) == SOCKET_ERROR) {
00633         throwError(getsockerror_winsock());
00634     }
00635 
00636     return (oflag != 0);
00637 }
00638 
00639 std::string
00640 CArchNetworkWinsock::getHostName()
00641 {
00642     char name[256];
00643     if (gethostname_winsock(name, sizeof(name)) == -1) {
00644         name[0] = '\0';
00645     }
00646     else {
00647         name[sizeof(name) - 1] = '\0';
00648     }
00649     return name;
00650 }
00651 
00652 CArchNetAddress
00653 CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
00654 {
00655     CArchNetAddressImpl* addr = NULL;
00656     switch (family) {
00657     case kINET: {
00658         addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
00659         struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
00660         ipAddr->sin_family         = AF_INET;
00661         ipAddr->sin_port           = 0;
00662         ipAddr->sin_addr.s_addr    = INADDR_ANY;
00663         break;
00664     }
00665 
00666     default:
00667         assert(0 && "invalid family");
00668     }
00669     return addr;
00670 }
00671 
00672 CArchNetAddress
00673 CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
00674 {
00675     assert(addr != NULL);
00676 
00677     CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
00678     memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
00679     return copy;
00680 }
00681 
00682 CArchNetAddress
00683 CArchNetworkWinsock::nameToAddr(const std::string& name)
00684 {
00685     // allocate address
00686     CArchNetAddressImpl* addr = NULL;
00687 
00688     // try to convert assuming an IPv4 dot notation address
00689     struct sockaddr_in inaddr;
00690     memset(&inaddr, 0, sizeof(inaddr));
00691     inaddr.sin_family      = AF_INET;
00692     inaddr.sin_port        = 0;
00693     inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
00694     if (inaddr.sin_addr.s_addr != INADDR_NONE) {
00695         // it's a dot notation address
00696         addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
00697         memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
00698     }
00699 
00700     else {
00701         // address lookup
00702         struct hostent* info = gethostbyname_winsock(name.c_str());
00703         if (info == NULL) {
00704             throwNameError(getsockerror_winsock());
00705         }
00706 
00707         // copy over address (only IPv4 currently supported)
00708         if (info->h_addrtype == AF_INET) {
00709             addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
00710             memcpy(&inaddr.sin_addr, info->h_addr_list[0],
00711                                 sizeof(inaddr.sin_addr));
00712             memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
00713         }
00714         else {
00715             throw XArchNetworkNameUnsupported(
00716                     "The requested name is valid but "
00717                     "does not have a supported address family");
00718         }
00719     }
00720 
00721     return addr;
00722 }
00723 
00724 void
00725 CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
00726 {
00727     assert(addr != NULL);
00728 
00729     free(addr);
00730 }
00731 
00732 std::string
00733 CArchNetworkWinsock::addrToName(CArchNetAddress addr)
00734 {
00735     assert(addr != NULL);
00736 
00737     // name lookup
00738     struct hostent* info = gethostbyaddr_winsock(
00739                             reinterpret_cast<const char FAR*>(&addr->m_addr),
00740                             addr->m_len, addr->m_addr.sa_family);
00741     if (info == NULL) {
00742         throwNameError(getsockerror_winsock());
00743     }
00744 
00745     // return (primary) name
00746     return info->h_name;
00747 }
00748 
00749 std::string
00750 CArchNetworkWinsock::addrToString(CArchNetAddress addr)
00751 {
00752     assert(addr != NULL);
00753 
00754     switch (getAddrFamily(addr)) {
00755     case kINET: {
00756         struct sockaddr_in* ipAddr =
00757             reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
00758         return inet_ntoa_winsock(ipAddr->sin_addr);
00759     }
00760 
00761     default:
00762         assert(0 && "unknown address family");
00763         return "";
00764     }
00765 }
00766 
00767 IArchNetwork::EAddressFamily
00768 CArchNetworkWinsock::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 CArchNetworkWinsock::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_winsock(static_cast<u_short>(port));
00791         break;
00792     }
00793 
00794     default:
00795         assert(0 && "unknown address family");
00796         break;
00797     }
00798 }
00799 
00800 int
00801 CArchNetworkWinsock::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_winsock(ipAddr->sin_port);
00810     }
00811 
00812     default:
00813         assert(0 && "unknown address family");
00814         return 0;
00815     }
00816 }
00817 
00818 bool
00819 CArchNetworkWinsock::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 (addr->m_len == sizeof(struct sockaddr_in) &&
00828                 ipAddr->sin_addr.s_addr == INADDR_ANY);
00829     }
00830 
00831     default:
00832         assert(0 && "unknown address family");
00833         return true;
00834     }
00835 }
00836 
00837 bool
00838 CArchNetworkWinsock::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
00839 {
00840     return (a == b || (a->m_len == b->m_len &&
00841             memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0));
00842 }
00843 
00844 void
00845 CArchNetworkWinsock::throwError(int err)
00846 {
00847     switch (err) {
00848     case WSAEACCES:
00849         throw XArchNetworkAccess(new XArchEvalWinsock(err));
00850 
00851     case WSAEMFILE:
00852     case WSAENOBUFS:
00853     case WSAENETDOWN:
00854         throw XArchNetworkResource(new XArchEvalWinsock(err));
00855 
00856     case WSAEPROTOTYPE:
00857     case WSAEPROTONOSUPPORT:
00858     case WSAEAFNOSUPPORT:
00859     case WSAEPFNOSUPPORT:
00860     case WSAESOCKTNOSUPPORT:
00861     case WSAEINVAL:
00862     case WSAENOPROTOOPT:
00863     case WSAEOPNOTSUPP:
00864     case WSAESHUTDOWN:
00865     case WSANOTINITIALISED:
00866     case WSAVERNOTSUPPORTED:
00867     case WSASYSNOTREADY:
00868         throw XArchNetworkSupport(new XArchEvalWinsock(err));
00869 
00870     case WSAEADDRNOTAVAIL:
00871         throw XArchNetworkNoAddress(new XArchEvalWinsock(err));
00872 
00873     case WSAEADDRINUSE:
00874         throw XArchNetworkAddressInUse(new XArchEvalWinsock(err));
00875 
00876     case WSAEHOSTUNREACH:
00877     case WSAENETUNREACH:
00878         throw XArchNetworkNoRoute(new XArchEvalWinsock(err));
00879 
00880     case WSAENOTCONN:
00881         throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
00882 
00883     case WSAEDISCON:
00884         throw XArchNetworkShutdown(new XArchEvalWinsock(err));
00885 
00886     case WSAENETRESET:
00887     case WSAECONNABORTED:
00888     case WSAECONNRESET:
00889         throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
00890 
00891     case WSAECONNREFUSED:
00892         throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err));
00893 
00894     case WSAEHOSTDOWN:
00895     case WSAETIMEDOUT:
00896         throw XArchNetworkTimedOut(new XArchEvalWinsock(err));
00897 
00898     case WSAHOST_NOT_FOUND:
00899         throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
00900 
00901     case WSANO_DATA:
00902         throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
00903 
00904     case WSANO_RECOVERY:
00905         throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
00906 
00907     case WSATRY_AGAIN:
00908         throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
00909 
00910     default:
00911         throw XArchNetwork(new XArchEvalWinsock(err));
00912     }
00913 }
00914 
00915 void
00916 CArchNetworkWinsock::throwNameError(int err)
00917 {
00918     switch (err) {
00919     case WSAHOST_NOT_FOUND:
00920         throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
00921 
00922     case WSANO_DATA:
00923         throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
00924 
00925     case WSANO_RECOVERY:
00926         throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
00927 
00928     case WSATRY_AGAIN:
00929         throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
00930 
00931     default:
00932         throw XArchNetworkName(new XArchEvalWinsock(err));
00933     }
00934 }

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