ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress* addr) { assert(s != NULL); // create new socket and temporary address ArchSocketImpl* socket = new ArchSocketImpl; ArchNetAddress tmp = ArchNetAddressImpl::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; }
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; }