• Main Page
  • Classes
  • Files
  • File List

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

Generated on Fri May 24 2013 00:00:03 for Synergy by  doxygen 1.7.1