void CArchNetworkWinsock::closeSocketForWrite(CArchSocket s) { assert(s != NULL); if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) { if (getsockerror_winsock() != WSAENOTCONN) { throwError(getsockerror_winsock()); } } }
void ArchNetworkWinsock::closeSocketForRead(ArchSocket s) { assert(s != NULL); if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) { if (getsockerror_winsock() != WSAENOTCONN) { throwError(getsockerror_winsock()); } } }
bool CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (connect_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) { if (getsockerror_winsock() == WSAEISCONN) { return true; } if (getsockerror_winsock() == WSAEWOULDBLOCK) { return false; } throwError(getsockerror_winsock()); } return true; }
void CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking) { assert(s != 0); int flag = blocking ? 0 : 1; if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } }
void CArchNetworkWinsock::listenOnSocket(CArchSocket s) { assert(s != NULL); // hardcoding backlog if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } }
void CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } }
bool CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse) { assert(s != NULL); // get old state BOOL oflag; int size = sizeof(oflag); if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } // set new state BOOL flag = reuse ? 1 : 0; size = sizeof(flag); if (setsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &flag, size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } return (oflag != 0); }
bool CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay) { assert(s != NULL); // get old state BOOL oflag; int size = sizeof(oflag); if (getsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } // set new state BOOL flag = noDelay ? 1 : 0; size = sizeof(flag); if (setsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &flag, size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } return (oflag != 0); }
size_t CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len) { assert(s != NULL); int n = recv_winsock(s->m_socket, buf, (int)len, 0); if (n == SOCKET_ERROR) { int err = getsockerror_winsock(); if (err == WSAEINTR || err == WSAEWOULDBLOCK) { return 0; } throwError(err); } return static_cast<size_t>(n); }
CArchSocket CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr) { assert(s != NULL); // create new socket and temporary address CArchSocketImpl* socket = new CArchSocketImpl; CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr)); // accept on socket SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len); if (fd == INVALID_SOCKET) { int err = getsockerror_winsock(); delete socket; free(tmp); *addr = NULL; if (err == WSAEWOULDBLOCK) { return NULL; } throwError(err); } try { setBlockingOnSocket(fd, false); } catch (...) { close_winsock(fd); delete socket; free(tmp); *addr = NULL; throw; } // initialize socket socket->m_socket = fd; socket->m_refCount = 1; socket->m_event = WSACreateEvent_winsock(); socket->m_pollWrite = true; // copy address if requested if (addr != NULL) { *addr = ARCH->copyAddr(tmp); } free(tmp); return socket; }
void CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s) { assert(s != NULL); // get the error from the socket layer int err = 0; int size = sizeof(err); if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_ERROR, &err, &size) == SOCKET_ERROR) { err = getsockerror_winsock(); } // throw if there's an error if (err != 0) { throwError(err); } }
size_t CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len) { assert(s != NULL); int n = send_winsock(s->m_socket, buf, (int)len, 0); if (n == SOCKET_ERROR) { int err = getsockerror_winsock(); if (err == WSAEINTR) { return 0; } if (err == WSAEWOULDBLOCK) { s->m_pollWrite = true; return 0; } throwError(err); } return static_cast<size_t>(n); }
void CArchNetworkWinsock::closeSocket(CArchSocket s) { assert(s != NULL); // unref the socket and note if it should be released ARCH->lockMutex(m_mutex); const bool doClose = (--s->m_refCount == 0); ARCH->unlockMutex(m_mutex); // close the socket if necessary if (doClose) { if (close_winsock(s->m_socket) == SOCKET_ERROR) { // close failed. restore the last ref and throw. int err = getsockerror_winsock(); ARCH->lockMutex(m_mutex); ++s->m_refCount; ARCH->unlockMutex(m_mutex); throwError(err); } WSACloseEvent_winsock(s->m_event); delete s; } }
CArchSocket CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type) { // create socket SOCKET fd = socket_winsock(s_family[family], s_type[type], 0); if (fd == INVALID_SOCKET) { throwError(getsockerror_winsock()); } try { setBlockingOnSocket(fd, false); } catch (...) { close_winsock(fd); throw; } // allocate socket object CArchSocketImpl* socket = new CArchSocketImpl; socket->m_socket = fd; socket->m_refCount = 1; socket->m_event = WSACreateEvent_winsock(); socket->m_pollWrite = true; return socket; }
int CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout) { int i; DWORD n; // prepare sockets and wait list bool canWrite = false; WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT)); for (i = 0, n = 0; i < num; ++i) { // reset return flags pe[i].m_revents = 0; // set invalid flag if socket is bogus then go to next socket if (pe[i].m_socket == NULL) { pe[i].m_revents |= kPOLLNVAL; continue; } // select desired events long socketEvents = 0; if ((pe[i].m_events & kPOLLIN) != 0) { socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; } if ((pe[i].m_events & kPOLLOUT) != 0) { socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE; // if m_pollWrite is false then we assume the socket is // writable. winsock doesn't signal writability except // when the state changes from unwritable. if (!pe[i].m_socket->m_pollWrite) { canWrite = true; pe[i].m_revents |= kPOLLOUT; } } // if no events then ignore socket if (socketEvents == 0) { continue; } // select socket for desired events WSAEventSelect_winsock(pe[i].m_socket->m_socket, pe[i].m_socket->m_event, socketEvents); // add socket event to wait list events[n++] = pe[i].m_socket->m_event; } // if no sockets then return immediately if (n == 0) { return 0; } // add the unblock event CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance(); CArchThread thread = mt->newCurrentThread(); WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread); ARCH->closeThread(thread); if (unblockEvent == NULL) { unblockEvent = new WSAEVENT; m_unblockEvents.push_back(unblockEvent); *unblockEvent = WSACreateEvent_winsock(); mt->setNetworkDataForCurrentThread(unblockEvent); } events[n++] = *unblockEvent; // prepare timeout DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout); if (canWrite) { // if we know we can write then don't block t = 0; } // wait DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE); // reset the unblock event WSAResetEvent_winsock(*unblockEvent); // handle results if (result == WSA_WAIT_FAILED) { if (getsockerror_winsock() == WSAEINTR) { // interrupted system call ARCH->testCancelThread(); return 0; } throwError(getsockerror_winsock()); } if (result == WSA_WAIT_TIMEOUT && !canWrite) { return 0; } if (result == WSA_WAIT_EVENT_0 + n - 1) { // the unblock event was signalled return 0; } for (i = 0, n = 0; i < num; ++i) { // skip events we didn't check if (pe[i].m_socket == NULL || (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) { continue; } // get events WSANETWORKEVENTS info; if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket, pe[i].m_socket->m_event, &info) == SOCKET_ERROR) { continue; } if ((info.lNetworkEvents & FD_READ) != 0) { pe[i].m_revents |= kPOLLIN; } if ((info.lNetworkEvents & FD_ACCEPT) != 0) { pe[i].m_revents |= kPOLLIN; } if ((info.lNetworkEvents & FD_WRITE) != 0) { pe[i].m_revents |= kPOLLOUT; // socket is now writable so don't bothing polling for // writable until it becomes unwritable. pe[i].m_socket->m_pollWrite = false; } if ((info.lNetworkEvents & FD_CONNECT) != 0) { if (info.iErrorCode[FD_CONNECT_BIT] != 0) { pe[i].m_revents |= kPOLLERR; } else { pe[i].m_revents |= kPOLLOUT; pe[i].m_socket->m_pollWrite = false; } } if ((info.lNetworkEvents & FD_CLOSE) != 0) { if (info.iErrorCode[FD_CLOSE_BIT] != 0) { pe[i].m_revents |= kPOLLERR; } else { if ((pe[i].m_events & kPOLLIN) != 0) { pe[i].m_revents |= kPOLLIN; } if ((pe[i].m_events & kPOLLOUT) != 0) { pe[i].m_revents |= kPOLLOUT; } } } if (pe[i].m_revents != 0) { ++n; } } return (int)n; }