static int wait_read(mailstream_low * s) { fd_set fds_read; struct timeval timeout; int fd; struct mailstream_ssl_data * ssl_data; int max_fd; int r; int cancelled; int got_data; #ifdef WIN32 HANDLE event; #endif ssl_data = (struct mailstream_ssl_data *) s->data; if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } #ifdef USE_GNUTLS if (gnutls_record_check_pending(ssl_data->session) != 0) return 0; #endif FD_ZERO(&fds_read); fd = mailstream_cancel_get_fd(ssl_data->cancel); FD_SET(fd, &fds_read); #ifdef WIN32 event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(ssl_data->fd, event, FD_READ | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (WAIT_TIMEOUT == r) { WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == fd); got_data = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); #else FD_SET(ssl_data->fd, &fds_read); max_fd = ssl_data->fd; if (fd > max_fd) max_fd = fd; r = select(max_fd + 1, &fds_read, NULL, NULL, &timeout); if (r <= 0) return -1; cancelled = (FD_ISSET(fd, &fds_read)); got_data = FD_ISSET(ssl_data->fd, &fds_read); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(ssl_data->cancel); return -1; } return 0; }
static int wait_write(mailstream_low * s) { fd_set fds_read; fd_set fds_write; struct timeval timeout; int r; int fd; struct mailstream_ssl_data * ssl_data; int max_fd; int cancelled; int write_enabled; #ifdef WIN32 HANDLE event; #endif ssl_data = (struct mailstream_ssl_data *) s->data; if (mailstream_cancel_cancelled(ssl_data->cancel)) return -1; if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } FD_ZERO(&fds_read); fd = mailstream_cancel_get_fd(ssl_data->cancel); FD_SET(fd, &fds_read); FD_ZERO(&fds_write); #ifdef WIN32 event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(ssl_data->fd, event, FD_WRITE | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (r < 0) { WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == fd) /* SEB 20070709 */; write_enabled = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(ssl_data->fd, event, 0); CloseHandle(event); #else FD_SET(ssl_data->fd, &fds_write); max_fd = ssl_data->fd; if (fd > max_fd) max_fd = fd; r = select(max_fd + 1, &fds_read, &fds_write, NULL, &timeout); if (r <= 0) return -1; cancelled = FD_ISSET(fd, &fds_read); write_enabled = FD_ISSET(ssl_data->fd, &fds_write); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(ssl_data->cancel); return -1; } if (!write_enabled) return 0; return 1; }
/* Relay data between a socket and a process until the process dies or stops sending or receiving data. The socket descriptor and process pipe handles are in the data argument, which must be a pointer to struct subprocess_info. This function is a workaround for the fact that we can't just run a process after redirecting its input handles to a socket. If the process, for example, redirects its own stdin, it somehow confuses the socket and stdout stops working. This is exactly what ncat does (as part of the Windows stdin workaround), so it can't be ignored. This function can be invoked through CreateThread to simulate fork+exec, or called directly to simulate exec. It frees the subprocess_info struct and closes the socket and pipe handles before returning. Returns the exit code of the subprocess. */ static DWORD WINAPI subprocess_thread_func(void *data) { struct subprocess_info *info; char pipe_buffer[BUFSIZ]; OVERLAPPED overlap = { 0 }; HANDLE events[3]; DWORD ret, rc; int crlf_state = 0; info = (struct subprocess_info *) data; /* Three events we watch for: socket read, pipe read, and process end. */ events[0] = (HANDLE) WSACreateEvent(); WSAEventSelect(info->fdn.fd, events[0], FD_READ | FD_CLOSE); events[1] = info->child_out_r; events[2] = info->proc; /* To avoid blocking or polling, we use asynchronous I/O, or what Microsoft calls "overlapped" I/O, on the process pipe. WaitForMultipleObjects reports when the read operation is complete. */ ReadFile(info->child_out_r, pipe_buffer, sizeof(pipe_buffer), NULL, &overlap); /* Loop until EOF or error. */ for (;;) { DWORD n_r, n_w; int i, n; i = WaitForMultipleObjects(3, events, FALSE, INFINITE); if (i == WAIT_OBJECT_0) { /* Read from socket, write to process. */ char buffer[BUFSIZ]; int pending; ResetEvent(events[0]); do { n = ncat_recv(&info->fdn, buffer, sizeof(buffer), &pending); if (n <= 0) goto loop_end; n_r = n; if (WriteFile(info->child_in_w, buffer, n_r, &n_w, NULL) == 0) break; if (n_w != n) goto loop_end; } while (pending); } else if (i == WAIT_OBJECT_0 + 1) { char *crlf = NULL, *wbuf; /* Read from process, write to socket. */ if (GetOverlappedResult(info->child_out_r, &overlap, &n_r, FALSE)) { wbuf = pipe_buffer; if (o.crlf) { n = n_r; if (fix_line_endings((char *) pipe_buffer, &n, &crlf, &crlf_state)) wbuf = crlf; n_r = n; } /* The above call to WSAEventSelect puts the socket in non-blocking mode, but we want this send to block, not potentially return WSAEWOULDBLOCK. We call block_socket, but first we must clear out the select event. */ WSAEventSelect(info->fdn.fd, events[0], 0); block_socket(info->fdn.fd); n = ncat_send(&info->fdn, wbuf, n_r); if (crlf != NULL) free(crlf); if (n != n_r) break; /* Restore the select event (and non-block the socket again.) */ WSAEventSelect(info->fdn.fd, events[0], FD_READ | FD_CLOSE); /* Queue another ansychronous read. */ ReadFile(info->child_out_r, pipe_buffer, sizeof(pipe_buffer), NULL, &overlap); } else { if (GetLastError() != ERROR_IO_PENDING) /* Error or end of file. */ break; } } else if (i == WAIT_OBJECT_0 + 2) { /* The child died. There are no more writes left in the pipe because WaitForMultipleObjects guarantees events with lower indexes are handled first. */ break; } else { break; } } loop_end: WSACloseEvent(events[0]); rc = unregister_subprocess(info->proc); ncat_assert(rc != -1); GetExitCodeProcess(info->proc, &ret); if (ret == STILL_ACTIVE) { if (o.debug > 1) logdebug("Subprocess still running, terminating it.\n"); rc = TerminateProcess(info->proc, 0); if (rc == 0) { if (o.debug > 1) logdebug("TerminateProcess failed with code %d.\n", rc); } } GetExitCodeProcess(info->proc, &ret); if (o.debug > 1) logdebug("Subprocess ended with exit code %d.\n", ret); shutdown(info->fdn.fd, 2); subprocess_info_close(info); free(info); rc = WaitForSingleObject(pseudo_sigchld_mutex, INFINITE); ncat_assert(rc == WAIT_OBJECT_0); if (pseudo_sigchld_handler != NULL) pseudo_sigchld_handler(); rc = ReleaseMutex(pseudo_sigchld_mutex); ncat_assert(rc != 0); return ret; }
int poll (struct pollfd *pfd, nfds_t nfd, int timeout) { #ifndef WINDOWS_NATIVE fd_set rfds, wfds, efds; struct timeval tv; struct timeval *ptv; int maxfd, rc; nfds_t i; if (nfd < 0) { errno = EINVAL; return -1; } /* Don't check directly for NFD too large. Any practical use of a too-large NFD is caught by one of the other checks below, and checking directly for getdtablesize is too much of a portability and/or performance and/or correctness hassle. */ /* EFAULT is not necessary to implement, but let's do it in the simplest case. */ if (!pfd && nfd) { errno = EFAULT; return -1; } /* convert timeout number into a timeval structure */ if (timeout == 0) { ptv = &tv; ptv->tv_sec = 0; ptv->tv_usec = 0; } else if (timeout > 0) { ptv = &tv; ptv->tv_sec = timeout / 1000; ptv->tv_usec = (timeout % 1000) * 1000; } else if (timeout == INFTIM) /* wait forever */ ptv = NULL; else { errno = EINVAL; return -1; } /* create fd sets and determine max fd */ maxfd = -1; FD_ZERO (&rfds); FD_ZERO (&wfds); FD_ZERO (&efds); for (i = 0; i < nfd; i++) { if (pfd[i].fd < 0) continue; if (maxfd < pfd[i].fd) { maxfd = pfd[i].fd; if (FD_SETSIZE <= maxfd) { errno = EINVAL; return -1; } } if (pfd[i].events & (POLLIN | POLLRDNORM)) FD_SET (pfd[i].fd, &rfds); /* see select(2): "the only exceptional condition detectable is out-of-band data received on a socket", hence we push POLLWRBAND events onto wfds instead of efds. */ if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) FD_SET (pfd[i].fd, &wfds); if (pfd[i].events & (POLLPRI | POLLRDBAND)) FD_SET (pfd[i].fd, &efds); } /* examine fd sets */ rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv); if (rc < 0) return rc; /* establish results */ rc = 0; for (i = 0; i < nfd; i++) { pfd[i].revents = (pfd[i].fd < 0 ? 0 : compute_revents (pfd[i].fd, pfd[i].events, &rfds, &wfds, &efds)); rc += pfd[i].revents != 0; } return rc; #else static struct timeval tv0; static HANDLE hEvent; WSANETWORKEVENTS ev; HANDLE h, handle_array[FD_SETSIZE + 2]; DWORD ret, wait_timeout, nhandles; fd_set rfds, wfds, xfds; BOOL poll_again; MSG msg; int rc = 0; nfds_t i; if (nfd < 0 || timeout < -1) { errno = EINVAL; return -1; } if (!hEvent) hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); restart: handle_array[0] = hEvent; nhandles = 1; FD_ZERO (&rfds); FD_ZERO (&wfds); FD_ZERO (&xfds); /* Classify socket handles and create fd sets. */ for (i = 0; i < nfd; i++) { int sought = pfd[i].events; pfd[i].revents = 0; if (pfd[i].fd < 0) continue; if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND | POLLPRI | POLLRDBAND))) continue; h = (HANDLE) _get_osfhandle (pfd[i].fd); assure (h != NULL); if (IsSocketHandle (h)) { int requested = FD_CLOSE; /* see above; socket handles are mapped onto select. */ if (sought & (POLLIN | POLLRDNORM)) { requested |= FD_READ | FD_ACCEPT; FD_SET ((SOCKET) h, &rfds); } if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND)) { requested |= FD_WRITE | FD_CONNECT; FD_SET ((SOCKET) h, &wfds); } if (sought & (POLLPRI | POLLRDBAND)) { requested |= FD_OOB; FD_SET ((SOCKET) h, &xfds); } if (requested) WSAEventSelect ((SOCKET) h, hEvent, requested); } else { /* Poll now. If we get an event, do not poll again. Also, screen buffer handles are waitable, and they'll block until a character is available. windows_compute_revents eliminates bits for the "wrong" direction. */ pfd[i].revents = windows_compute_revents (h, &sought); if (sought) handle_array[nhandles++] = h; if (pfd[i].revents) timeout = 0; } } if (select (0, &rfds, &wfds, &xfds, &tv0) > 0) { /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but no need to call select again. */ poll_again = FALSE; wait_timeout = 0; } else { poll_again = TRUE; if (timeout == INFTIM) wait_timeout = INFINITE; else wait_timeout = timeout; } for (;;) { ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE, wait_timeout, QS_ALLINPUT); if (ret == WAIT_OBJECT_0 + nhandles) { /* new input of some other kind */ BOOL bRet; while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0) { TranslateMessage (&msg); DispatchMessage (&msg); } } else break; } if (poll_again) select (0, &rfds, &wfds, &xfds, &tv0); /* Place a sentinel at the end of the array. */ handle_array[nhandles] = NULL; nhandles = 1; for (i = 0; i < nfd; i++) { int happened; if (pfd[i].fd < 0) continue; if (!(pfd[i].events & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND))) continue; h = (HANDLE) _get_osfhandle (pfd[i].fd); if (h != handle_array[nhandles]) { /* It's a socket. */ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); WSAEventSelect ((SOCKET) h, 0, 0); /* If we're lucky, WSAEnumNetworkEvents already provided a way to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ if (FD_ISSET ((SOCKET) h, &rfds) && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT))) ev.lNetworkEvents |= FD_READ | FD_ACCEPT; if (FD_ISSET ((SOCKET) h, &wfds)) ev.lNetworkEvents |= FD_WRITE | FD_CONNECT; if (FD_ISSET ((SOCKET) h, &xfds)) ev.lNetworkEvents |= FD_OOB; happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events, ev.lNetworkEvents); } else { /* Not a socket. */ int sought = pfd[i].events; happened = windows_compute_revents (h, &sought); nhandles++; } if ((pfd[i].revents |= happened) != 0) rc++; } if (!rc && timeout == INFTIM) { SleepEx (1, TRUE); goto restart; } return rc; #endif }
BOOL CUdpCommClient::Init() { // if (FALSE == CThreadClient::Init()) { return FALSE; } // if (FALSE == m_bSockLibFlag) { return FALSE; } // m_tTimeout = time(NULL); // if (NULL == m_hQuit) { m_nErrorCode = GetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // if (NULL == m_hWrEvent) { m_nErrorCode = GetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // // 일단 UDP로 // m_dSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (INVALID_SOCKET == m_dSock) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // if (FALSE == UdpFixBind()) { return FALSE; } //... SOO SOCKET BUFF SIZING : // m_ulRcvBuff = 1024 * 1024 * 1000; // m_ulSndBuff = 1024 * 1024 * 1000; // if (SOCKET_ERROR == setsockopt(m_dSock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&m_ulRcvBuff), sizeof(m_ulRcvBuff))) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); } // if (SOCKET_ERROR == setsockopt(m_dSock, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&m_ulSndBuff), sizeof(m_ulSndBuff))) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); } // int nLenVariable = sizeof(m_ulMaxSndPktLen); if (SOCKET_ERROR == getsockopt(m_dSock, SOL_SOCKET, SO_MAX_MSG_SIZE, reinterpret_cast<char*>(&m_ulMaxSndPktLen), &nLenVariable)) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // if (FALSE == m_cRecvChunk.Ext(m_ulMaxRcvPktLen + 1)) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_USERDEF, OCFCLIENT_ERROR_USERDEF_CATEGORY_MEMORY, 0xFF, 0, NULL); return FALSE; } // m_hSockEvent = WSACreateEvent(); if (WSA_INVALID_EVENT == m_hSockEvent) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // // Only For UDP // if (WSAEventSelect(m_dSock, m_hSockEvent, FD_READ | FD_WRITE) == SOCKET_ERROR) { m_nErrorCode = WSAGetLastError(); HandleError(OCFCLIENT_ERROR_WINSOCK, m_nErrorCode, 0xFF, 0, NULL); return FALSE; } // m_bConnectFlag = TRUE; m_bWouldBlock = FALSE; return TRUE; }
void Network::Begin (void) { // an alternative to select() is to use Windows events; first create a regular auto-reset event HANDLE eventSocketReady = CreateEvent (NULL, false, false, NULL); // second, register sock_in with the event using FD_READ notifications only (i.e., available for READ) WSAEventSelect(sock_in, eventSocketReady, FD_READ); // associate event with socket char buf [MAX_PKT_SIZE]; DWORD timeout = INFINITE; //infinite timeout while (true) { int ret; if (timeout != 0) ret = WaitForSingleObject (eventSocketReady, timeout);// either a timeout occurs or something is pending inside sock_in double cur_time = m->GetTime(); // packets are ready to be extracted? if (timeout == 0 || ret == WAIT_TIMEOUT) { // examine the front packet Packet head = Q.front(); // can be tranmitted right now? while (head.d <= cur_time) { // remove from the queue Q.pop_front(); // generate random number to decide reordering double u = (double)rand()/RAND_MAX; // u in [0,1] // reorder with probability P_REORDER, but only if the queue is non-empty // note: this code can reorder the same packet multiple times, but each time by one position // to disable multiple reorderings of the same packet, uncomment the statement below if (u < p_reorder && Q.size() > 0)// && head.has_been_reordered == false) { m->printf ("[%f] Network: reordered pkt of size %d, message %d\n", m->ElapsedTime(), head.pkt_size, *(int*)head.pkt_data); head.has_been_reordered = true; // swap this packet with the next one Packet tmp; // save the current packet memcpy (&tmp, &head, sizeof (Packet)); // take the next one head = Q.front(); Q.pop_front(); // store the old one in its place Q.push_front (tmp); } // printf takes 1.9 ms to execute, this will normally delay transmission of packets that follow if the sending rate is high; // disable all printfs for high-speed transfers, or they will become the bottleneck m->printf ("[%f] Network: sent message %d, scheduled %f\n", m->ElapsedTime(), *(int*)head.pkt_data, m->RelativeTime(head.d)); // send to destination sendto (sock_out, head.pkt_data, head.pkt_size, 0, (struct sockaddr*) &destination, sizeof(struct sockaddr_in)); delete head.pkt_data; // if there is still stuff in the queue, see if it needs to be transmitted if (Q.size() > 0) head = Q.front(); // peek at the next packet else break; } } else // data in socket { int bytes = recv (sock_in, buf, MAX_PKT_SIZE, 0); if (bytes == SOCKET_ERROR) { m->printf ("[%f] Network: recvfrom error %d\n", m->ElapsedTime(), WSAGetLastError()); exit (-1); } else { // lose this pkt with probability p_loss double u = (double)rand()/RAND_MAX; // u in [0,1] if (u >= p_loss) { // keep the packet Packet new_pkt; // create a new pkt entry new_pkt.pkt_data = new char [bytes]; memcpy (new_pkt.pkt_data, buf, bytes); new_pkt.pkt_size = bytes; new_pkt.has_been_reordered = false; // add it to the queue PushInNetworkQueue (new_pkt); } else m->printf ("[%f] Network: dropped pkt of size %d, message %d\n", m->ElapsedTime(), bytes, *(int*)buf); } } // recompute the sleep delay if (Q.size() > 0) { // if the queue is not empty, figure out how much to sleep double cur_time = m->GetTime(); if (Q.front().d > cur_time) timeout = (DWORD)floor( (Q.front().d - cur_time) * 1000.0 + 0.5); // round to the nearest integer ms else // do not sleep timeout = 0; } else // queue is empty, sleep forever timeout = INFINITE; } }
unsigned __stdcall I4C3DAcceptedThreadProc(void* pParam) { LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); I4C3DChildContext* pChildContext = (I4C3DChildContext*)pParam; I4C3DUDPPacket packet = {0}; const SIZE_T packetBufferSize = sizeof(packet.szCommand); SIZE_T totalRecvBytes = 0; int nBytes = 0; BOOL bBreak = FALSE; DWORD dwResult = 0; WSAEVENT hEvent = NULL; WSAEVENT hEventArray[2] = {0}; WSANETWORKEVENTS events = {0}; hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hEvent == NULL) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); shutdown(pChildContext->clientSocket, SD_SEND); recv(pChildContext->clientSocket, packet.szCommand, packetBufferSize, 0); shutdown(pChildContext->clientSocket, SD_BOTH); closesocket(pChildContext->clientSocket); RemoveChildThread( pChildContext->hChildThread ); free(pChildContext); return EXIT_FAILURE; } WSAEventSelect(pChildContext->clientSocket, hEvent, FD_READ | FD_CLOSE); hEventArray[0] = hEvent; hEventArray[1] = pChildContext->pContext->hStopEvent; FillMemory(packet.szCommand, packetBufferSize, 0xFF); while (!bBreak) { if (!CheckNetworkEventError(events)) { break; } dwResult = WSAWaitForMultipleEvents(2, hEventArray, FALSE, WSA_INFINITE, FALSE); DEBUG_PROFILE_MONITOR; if (dwResult == WSA_WAIT_FAILED) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } if (dwResult - WSA_WAIT_EVENT_0 == 0) { if (WSAEnumNetworkEvents(pChildContext->clientSocket, hEvent, &events) != 0) { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_HANDLE_INVALID), GetLastError(), g_FILE, __LINE__); break; } if (events.lNetworkEvents & FD_CLOSE) { break; } else if (events.lNetworkEvents & FD_READ) { nBytes = recv(pChildContext->clientSocket, packet.szCommand + totalRecvBytes, packetBufferSize - totalRecvBytes, 0); if (nBytes == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { continue; } else { LoggingMessage(Log_Error, _T(MESSAGE_ERROR_SOCKET_RECV), WSAGetLastError(), g_FILE, __LINE__); } break; } else if (nBytes > 0) { totalRecvBytes += nBytes; PCSTR pTermination = (PCSTR)memchr(packet.szCommand, pChildContext->cTermination, totalRecvBytes); // 終端文字が見つからない場合、バッファをクリア if (pTermination == NULL) { if (totalRecvBytes >= packetBufferSize) { FillMemory(packet.szCommand, packetBufferSize, 0xFF); totalRecvBytes = 0; } continue; } do { DEBUG_PROFILE_MONITOR; // プラグインへ電文転送 pChildContext->pContext->pController->Execute(&packet, pTermination-packet.szCommand+1); volatile int i; for (i = 0; i < g_sleepCount; ++i) { Sleep(1); } //} else { // // Hotkey // MoveMemory(szCommand, recvBuffer, pTermination-recvBuffer); // szCommand[pTermination-recvBuffer] = '\0'; // EnterCriticalSection(&g_Lock); // pChildContext->pContext->pController->Execute(pChildContext->pContext, &delta, szCommand); // LeaveCriticalSection(&g_Lock); //} if (pTermination == (packet.szCommand + totalRecvBytes - 1)) { FillMemory(packet.szCommand, packetBufferSize, 0xFF); totalRecvBytes = 0; } else if (pTermination < (packet.szCommand + totalRecvBytes - 1)) { int nCopySize = packetBufferSize - (pTermination - packet.szCommand + 1); totalRecvBytes -= (pTermination - packet.szCommand + 1); MoveMemory(packet.szCommand, pTermination+1, nCopySize); FillMemory(packet.szCommand + nCopySize, packetBufferSize - nCopySize, 0xFF); } else { bBreak = TRUE; LoggingMessage(Log_Error, _T(MESSAGE_ERROR_MESSAGE_INVALID), GetLastError(), g_FILE, __LINE__); break; } DEBUG_PROFILE_MONITOR; } while ((pTermination = (LPCSTR)memchr(packet.szCommand, pChildContext->cTermination, totalRecvBytes)) != NULL); DEBUG_PROFILE_MONITOR; } } } else if (dwResult - WSA_WAIT_EVENT_0 == 1) { // pChildContext->pContext->hStopEvent に終了イベントがセットされた break; } } SafeCloseHandle(hEvent); // closesocket shutdown(pChildContext->clientSocket, SD_SEND); recv(pChildContext->clientSocket, packet.szCommand, packetBufferSize, 0); shutdown(pChildContext->clientSocket, SD_BOTH); closesocket(pChildContext->clientSocket); RemoveChildThread( pChildContext->hChildThread ); free(pChildContext); LoggingMessage(Log_Debug, _T(MESSAGE_DEBUG_PROCESSING), GetLastError(), g_FILE, __LINE__); return EXIT_SUCCESS; }
static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct socketWin * const listenSocketP = chanSwitchP->implP; HANDLE acceptEvent = WSACreateEvent(); bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ WSAEventSelect(listenSocketP->winsock, acceptEvent, FD_ACCEPT | FD_CLOSE | FD_READ); while (!channelP && !*errorP && !interrupted) { HANDLE interrupts[2] = {acceptEvent, listenSocketP->interruptEvent}; int rc; struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); rc = WaitForMultipleObjects(2, interrupts, FALSE, INFINITE); if (WAIT_OBJECT_0 + 1 == rc) { interrupted = TRUE; continue; }; rc = accept(listenSocketP->winsock, &peerAddr, &size); if (rc >= 0) { int const acceptedWinsock = rc; createChannelForAccept(acceptedWinsock, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) closesocket(acceptedWinsock); } else { int const lastError = WSAGetLastError(); if (lastError == WSAEINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, WSA error = %d (%s)", lastError, getWSAError(lastError)); } } *channelPP = channelP; CloseHandle(acceptEvent); }
/* callback from ares when socket operation is started */ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int write) { /* look to see if we have a handle for this socket in our list */ uv_loop_t* loop = (uv_loop_t*) data; uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock); int timeoutms = 0; if (read == 0 && write == 0) { /* if read and write are 0, cleanup existing data */ /* The code assumes that c-ares does a callback with read = 0 and */ /* write = 0 when the socket is closed. After we recieve this we stop */ /* monitoring the socket. */ if (uv_handle_ares != NULL) { uv_req_t* uv_ares_req; uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL); /* remove Wait */ if (uv_handle_ares->h_wait) { UnregisterWaitEx(uv_handle_ares->h_wait, uv_handle_ares->h_close_event); uv_handle_ares->h_wait = NULL; } /* detach socket from the event */ WSAEventSelect(sock, NULL, 0); if (uv_handle_ares->h_event != WSA_INVALID_EVENT) { WSACloseEvent(uv_handle_ares->h_event); uv_handle_ares->h_event = WSA_INVALID_EVENT; } /* remove handle from list */ uv_remove_ares_handle(uv_handle_ares); /* Post request to cleanup the Task */ uv_ares_req = &uv_handle_ares->ares_req; uv_req_init(loop, uv_ares_req); uv_ares_req->type = UV_ARES_CLEANUP_REQ; uv_ares_req->data = uv_handle_ares; /* post ares done with socket - finish cleanup when all threads done. */ POST_COMPLETION_FOR_REQ(loop, uv_ares_req); } else { assert(0); uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); } } else { if (uv_handle_ares == NULL) { /* setup new handle */ /* The code assumes that c-ares will call us when it has an open socket. We need to call into c-ares when there is something to read, or when it becomes writable. */ uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t)); if (uv_handle_ares == NULL) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } uv_handle_ares->type = UV_ARES_TASK; uv_handle_ares->close_cb = NULL; uv_handle_ares->data = loop; uv_handle_ares->sock = sock; uv_handle_ares->h_wait = NULL; uv_handle_ares->flags = 0; /* create an event to wait on socket signal */ uv_handle_ares->h_event = WSACreateEvent(); if (uv_handle_ares->h_event == WSA_INVALID_EVENT) { uv_fatal_error(WSAGetLastError(), "WSACreateEvent"); } /* tie event to socket */ if (SOCKET_ERROR == WSAEventSelect(sock, uv_handle_ares->h_event, FD_READ | FD_WRITE | FD_CONNECT)) { uv_fatal_error(WSAGetLastError(), "WSAEventSelect"); } /* add handle to list */ uv_add_ares_handle(loop, uv_handle_ares); uv_ref(loop); /* * we have a single polling timer for all ares sockets. * This is preferred to using ares_timeout. See ares_timeout.c warning. * if timer is not running start it, and keep socket count */ if (loop->ares_active_sockets == 0) { uv_timer_init(loop, &loop->ares_polling_timer); uv_timer_start(&loop->ares_polling_timer, uv_ares_poll, 1000L, 1000L); } loop->ares_active_sockets++; /* specify thread pool function to call when event is signaled */ if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait, uv_handle_ares->h_event, uv_ares_socksignal_tp, (void*)uv_handle_ares, INFINITE, WT_EXECUTEINWAITTHREAD) == 0) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } } else { /* found existing handle. */ assert(uv_handle_ares->type == UV_ARES_TASK); assert(uv_handle_ares->data != NULL); assert(uv_handle_ares->h_event != WSA_INVALID_EVENT); } } }
int WEventSocket::EventSelect(long events) { return WSAEventSelect(m_hSocket,m_hEvent,events); }
static ssize_t mailstream_low_socket_read(mailstream_low * s, void * buf, size_t count) { struct mailstream_socket_data * socket_data; socket_data = (struct mailstream_socket_data *) s->data; if (mailstream_cancel_cancelled(socket_data->cancel)) return -1; /* timeout */ { fd_set fds_read; struct timeval timeout; int r; int fd; int cancelled; int got_data; #ifdef WIN32 HANDLE event; #else int max_fd; #endif if (s->timeout == 0) { timeout = mailstream_network_delay; } else { timeout.tv_sec = s->timeout; timeout.tv_usec = 0; } FD_ZERO(&fds_read); fd = mailstream_cancel_get_fd(socket_data->cancel); FD_SET(fd, &fds_read); #ifdef WIN32 event = CreateEvent(NULL, TRUE, FALSE, NULL); WSAEventSelect(socket_data->fd, event, FD_READ | FD_CLOSE); FD_SET(event, &fds_read); r = WaitForMultipleObjects(fds_read.fd_count, fds_read.fd_array, FALSE, timeout.tv_sec * 1000 + timeout.tv_usec / 1000); if (WAIT_TIMEOUT == r) { WSAEventSelect(socket_data->fd, event, 0); CloseHandle(event); return -1; } cancelled = (fds_read.fd_array[r - WAIT_OBJECT_0] == fd); got_data = (fds_read.fd_array[r - WAIT_OBJECT_0] == event); WSAEventSelect(socket_data->fd, event, 0); CloseHandle(event); #else FD_SET(socket_data->fd, &fds_read); max_fd = socket_data->fd; if (fd > max_fd) max_fd = fd; r = select(max_fd + 1, &fds_read, NULL,/* &fds_excp*/ NULL, &timeout); if (r <= 0) return -1; cancelled = FD_ISSET(fd, &fds_read); got_data = FD_ISSET(socket_data->fd, &fds_read); #endif if (cancelled) { /* cancelled */ mailstream_cancel_ack(socket_data->cancel); return -1; } if (!got_data) return 0; } if (socket_data->use_read) { return read(socket_data->fd, buf, count); } else { return recv(socket_data->fd, buf, count, 0); } }
// Use the socket in the CHandshakes object to listen for remote computers who want to connect to us // Returns true if we're listening, false if it didn't work BOOL CHandshakes::Listen() { if ( IsValid() ) return TRUE; // Make sure only one thread can execute the code of this method at a time CSingleLock pLock( &m_pSection, TRUE ); // When the method exits, local pLock will be destructed, and the lock released m_hSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( ! IsValid() ) // Now, make sure it has been created { theApp.Message( MSG_ERROR, _T("Failed to create TCP socket. (1st Try)") ); // Second attempt m_hSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( ! IsValid() ) { theApp.Message( MSG_ERROR, _T("Failed to create TCP socket. (2nd Try)") ); return FALSE; } } // Disables the Nagle algorithm for send coalescing VERIFY( setsockopt( m_hSocket, IPPROTO_TCP, TCP_NODELAY, "\x01", 1) == 0 ); // Get our computer's Internet IP address and port number from the network object SOCKADDR_IN saHost = Network.m_pHost; // This is the address of our computer as visible to remote computers on the Internet // If the program connection settings disallow binding, zero the 4 bytes of the IP address if ( ! Settings.Connection.InBind ) saHost.sin_addr.s_addr = INADDR_ANY; // s_addr is the IP address formatted as a single u_long else { // Set the exclusive address option VERIFY( setsockopt( m_hSocket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, "\x01", 1 ) == 0 ); } // First attempt to bind socket if ( bind( m_hSocket, (SOCKADDR*)&saHost, sizeof( saHost ) ) != 0 ) { theApp.Message( MSG_ERROR, IDS_NETWORK_CANT_LISTEN, (LPCTSTR)CString( inet_ntoa( saHost.sin_addr ) ), htons( saHost.sin_port ) ); if ( saHost.sin_addr.s_addr == INADDR_ANY ) return FALSE; // Second attempt to bind socket saHost.sin_addr.s_addr = INADDR_ANY; if ( bind( m_hSocket, (SOCKADDR*)&saHost, sizeof( saHost ) ) != 0 ) { theApp.Message( MSG_ERROR, IDS_NETWORK_CANT_LISTEN, (LPCTSTR)CString( inet_ntoa( saHost.sin_addr ) ), htons( saHost.sin_port ) ); return FALSE; } } // Report that we are now listening on our IP address theApp.Message( MSG_INFO, IDS_NETWORK_LISTENING_TCP, (LPCTSTR)CString( inet_ntoa( saHost.sin_addr ) ), htons( saHost.sin_port ) ); // Set it up so that when a remote computer connects to us, the m_pWakeup event is fired WSAEventSelect( // Specify an event object to associate with the specified set of FD_XXX network events m_hSocket, // Our listening socket GetWakeupEvent(), // Our event, a CEvent object member variable FD_ACCEPT ); // The network event to trigger this is us accepting a remote computer's connection // Have the socket wait, listening for remote computer on the Internet to connect to it listen( // Place a socket in a state in which it is listening for an incoming connection m_hSocket, // Our socket 256 ); // Maximum length of the queue of pending connections, let 256 computers try to call us at once (do) Network.AcquireLocalAddress( m_hSocket ); // Create a new thread to run the ThreadStart method, passing it a pointer to this C return BeginThread( "Handshakes" ); }
void Run() { break_ = false; // prepare the window events which we use to wake up on incoming data // we use this instead of select() primarily to support the AsyncBreak() // mechanism. std::vector<HANDLE> events( socketListeners_.size() + 1, 0 ); int j=0; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i, ++j ){ HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL ); WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below events[j] = event; } events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event // configure the timer queue double currentTimeMs = GetCurrentTimeMs(); // expiry time ms, listener std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); i != timerListeners_.end(); ++i ) timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); const int MAX_BUFFER_SIZE = 4098; char *data = new char[ MAX_BUFFER_SIZE ]; IpEndpointName remoteEndpoint; while( !break_ ){ currentTimeMs = GetCurrentTimeMs(); DWORD waitTime = INFINITE; if( !timerQueue_.empty() ){ waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs ? timerQueue_.front().first - currentTimeMs : 0 ); } DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime ); if( break_ ) break; if( waitResult != WAIT_TIMEOUT ){ for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){ int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); if( size > 0 ){ socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint ); if( break_ ) break; } } } // execute any expired timers currentTimeMs = GetCurrentTimeMs(); bool resort = false; for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ i->second.listener->TimerExpired(); if( break_ ) break; i->first += i->second.periodMs; resort = true; } if( resort ) std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); } delete [] data; // free events j = 0; for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); i != socketListeners_.end(); ++i, ++j ){ WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event CloseHandle( events[j] ); unsigned long enableNonblocking = 0; ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again } }