📄 os_win32.c
字号:
{ struct timeval tv; fd_set rfds; int sock = fdTable[fd].fid.sock; int rv; char trash[1024]; FD_ZERO(&rfds); do {#pragma warning( disable : 4127 ) FD_SET((unsigned) sock, &rfds);#pragma warning( default : 4127 ) tv.tv_sec = 2; tv.tv_usec = 0; rv = select(sock + 1, &rfds, NULL, NULL, &tv); } while (rv > 0 && recv(sock, trash, sizeof(trash), 0) > 0); } } closesocket(fdTable[fd].fid.sock); break; default: ret = -1; /* fake failure */ } Win32FreeDescriptor(fd); return ret;}/* *-------------------------------------------------------------- * * OS_CloseRead -- * * Cancel outstanding asynchronous reads and prevent subsequent * reads from completing. * * Results: * Socket or file is shutdown. Return values mimic Unix shutdown: * 0 success, -1 failure * *-------------------------------------------------------------- */int OS_CloseRead(int fd){ int ret = 0; /* * Catch it if fd is a bogus value */ ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC || fdTable[fd].type == FD_SOCKET_SYNC); if (shutdown(fdTable[fd].fid.sock,SD_RECEIVE) == SOCKET_ERROR) ret = -1; return ret;}/* *-------------------------------------------------------------- * * OS_DoIo -- * * This function was formerly OS_Select. It's purpose is * to pull I/O completion events off the queue and dispatch * them to the appropriate place. * * Results: * Returns 0. * * Side effects: * Handlers are called. * *-------------------------------------------------------------- */int OS_DoIo(struct timeval *tmo){ unsigned long fd; unsigned long bytes; POVERLAPPED_REQUEST pOv; struct timeb tb; int ms; int ms_last; int err; /* XXX * We can loop in here, but not too long, as wait handlers * must run. * For cgi stdin, apparently select returns when io completion * ports don't, so don't wait the full timeout. */ if(tmo) ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2; else ms = 1000; ftime(&tb); ms_last = tb.time*1000 + tb.millitm; while (ms >= 0) { if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100) ms = 100; if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd, (LPOVERLAPPED *)&pOv, ms) && !pOv) { err = WSAGetLastError(); return 0; /* timeout */ } ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX)); /* call callback if descriptor still valid */ ASSERT(pOv); if(pOv->instance == fdTable[fd].instance) (*pOv->procPtr)(pOv->clientData, bytes); free(pOv); ftime(&tb); ms -= (tb.time*1000 + tb.millitm - ms_last); ms_last = tb.time*1000 + tb.millitm; } return 0;}static int isAddrOK(struct sockaddr_in * inet_sockaddr, const char * okAddrs){ static const char *token = " ,;:\t"; char *ipaddr; char *p; if (okAddrs == NULL) return TRUE; ipaddr = inet_ntoa(inet_sockaddr->sin_addr); p = strstr(okAddrs, ipaddr); if (p == NULL) return FALSE; if (p == okAddrs) { p += strlen(ipaddr); return (strchr(token, *p) != NULL); } if (strchr(token, *--p) != NULL) { p += strlen(ipaddr) + 1; return (strchr(token, *p) != NULL); } return FALSE;}#ifndef NO_WSAACEPTstatic int CALLBACK isAddrOKCallback(LPWSABUF lpCallerId, LPWSABUF dc0, LPQOS dc1, LPQOS dc2, LPWSABUF dc3, LPWSABUF dc4, GROUP *dc5, DWORD data){ struct sockaddr_in *sockaddr = (struct sockaddr_in *) lpCallerId->buf; // Touch the args to avoid warnings dc0 = NULL; dc1 = NULL; dc2 = NULL; dc3 = NULL; dc4 = NULL; dc5 = NULL; if ((void *) data == NULL) return CF_ACCEPT; if (sockaddr->sin_family != AF_INET) return CF_ACCEPT; return isAddrOK(sockaddr, (const char *) data) ? CF_ACCEPT : CF_REJECT;}#endifstatic void printLastError(const char * text){ LPVOID buf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR) &buf, 0, NULL ); fprintf(stderr, "%s: %s\n", text, (LPCTSTR) buf); LocalFree(buf);}static int acceptNamedPipe(){ int ipcFd = -1; if (! ConnectNamedPipe(hListen, NULL)) { switch (GetLastError()) { case ERROR_PIPE_CONNECTED: // A client connected after CreateNamedPipe but // before ConnectNamedPipe. Its a good connection. break; case ERROR_IO_PENDING: // The NamedPipe was opened with an Overlapped structure // and there is a pending io operation. mod_fastcgi // did this in 2.2.12 (fcgi_pm.c v1.52). case ERROR_PIPE_LISTENING: // The pipe handle is in nonblocking mode. case ERROR_NO_DATA: // The previous client closed its handle (and we failed // to call DisconnectNamedPipe) default: printLastError("unexpected ConnectNamedPipe() error"); } } ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int) hListen, -1); if (ipcFd == -1) { DisconnectNamedPipe(hListen); } return ipcFd;}static int acceptSocket(const char *webServerAddrs){ SOCKET hSock; int ipcFd = -1; for (;;) { struct sockaddr sockaddr; int sockaddrLen = sizeof(sockaddr); for (;;) { const struct timeval timeout = {1, 0}; fd_set readfds; FD_ZERO(&readfds);#pragma warning( disable : 4127 ) FD_SET((unsigned int) hListen, &readfds);#pragma warning( default : 4127 ) if (select(0, &readfds, NULL, NULL, &timeout) == 0) { if (shutdownPending) { OS_LibShutdown(); return -1; } } else { break; } } #if NO_WSAACEPT hSock = accept((SOCKET) hListen, &sockaddr, &sockaddrLen); if (hSock == INVALID_SOCKET) { break; } if (isAddrOK((struct sockaddr_in *) &sockaddr, webServerAddrs)) { break; } closesocket(hSock);#else hSock = WSAAccept((unsigned int) hListen, &sockaddr, &sockaddrLen, isAddrOKCallback, (DWORD) webServerAddrs); if (hSock != INVALID_SOCKET) { break; } if (WSAGetLastError() != WSAECONNREFUSED) { break; }#endif } if (hSock == INVALID_SOCKET) { /* Use FormatMessage() */ fprintf(stderr, "accept()/WSAAccept() failed: %d", WSAGetLastError()); return -1; } ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1); if (ipcFd == -1) { closesocket(hSock); } return ipcFd;}/* *---------------------------------------------------------------------- * * OS_Accept -- * * Accepts a new FastCGI connection. This routine knows whether * we're dealing with TCP based sockets or NT Named Pipes for IPC. * * fail_on_intr is ignored in the Win lib. * * Results: * -1 if the operation fails, otherwise this is a valid IPC fd. * *---------------------------------------------------------------------- */int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs){ int ipcFd = -1; // Touch args to prevent warnings listen_sock = 0; fail_on_intr = 0; // @todo Muliple listen sockets and sockets other than 0 are not // supported due to the use of globals. if (shutdownPending) { OS_LibShutdown(); return -1; } // The mutex is to keep other processes (and threads, when supported) // from going into the accept cycle. The accept cycle needs to // periodically break out to check the state of the shutdown flag // and there's no point to having more than one thread do that. if (acceptMutex != INVALID_HANDLE_VALUE) { DWORD ret;#if YOU_WANT_TO_MAKE_THE_PROCESS_HANG_AFTER_FIRST_REQUEST while ((ret = WaitForSingleObject(acceptMutex, ACCEPT_TIMEOUT)) == WAIT_TIMEOUT) { if (shutdownPending) break; } if (ret == WAIT_FAILED) {#else if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED) {#endif printLastError("WaitForSingleObject() failed"); return -1; } } if (shutdownPending) { OS_LibShutdown(); } else if (listenType == FD_PIPE_SYNC) { ipcFd = acceptNamedPipe(); } else if (listenType == FD_SOCKET_SYNC) { ipcFd = acceptSocket(webServerAddrs); } else { fprintf(stderr, "unknown listenType (%d)\n", listenType); } if (acceptMutex != INVALID_HANDLE_VALUE) { ReleaseMutex(acceptMutex); } return ipcFd;}/* *---------------------------------------------------------------------- * * OS_IpcClose * * OS IPC routine to close an IPC connection. * * Results: * * * Side effects: * IPC connection is closed. * *---------------------------------------------------------------------- */int OS_IpcClose(int ipcFd, int shutdown){ if (ipcFd == -1) return 0; /* * Catch it if fd is a bogus value */ ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX)); ASSERT(fdTable[ipcFd].type != FD_UNUSED); switch (listenType) { case FD_PIPE_SYNC: /* * Make sure that the client (ie. a Web Server in this case) has * read all data from the pipe before we disconnect. */ if (! FlushFileBuffers(fdTable[ipcFd].fid.fileHandle)) return -1; if (! DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) return -1; OS_StopImpersonation(); /* fall through */ case FD_SOCKET_SYNC: OS_Close(ipcFd, shutdown); break; case FD_UNUSED: default: return -1; break; } return 0;}/* *---------------------------------------------------------------------- * * OS_IsFcgi -- * * Determines whether this process is a FastCGI process or not. * * Results: * Returns 1 if FastCGI, 0 if not. * * Side effects: * None. * *---------------------------------------------------------------------- */int OS_IsFcgi(int sock){ // Touch args to prevent warnings sock = 0; /* XXX This is broken for sock */ return (listenType != FD_UNUSED); }/* *---------------------------------------------------------------------- * * OS_SetFlags -- * * Sets selected flag bits in an open file descriptor. Currently * this is only to put a SOCKET into non-blocking mode. * *---------------------------------------------------------------------- */void OS_SetFlags(int fd, int flags){ unsigned long pLong = 1L; if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) { if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) == SOCKET_ERROR) { //exit(WSAGetLastError()); SetLastError(WSAGetLastError()); return; } if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock, hIoCompPort, fd, 1)) { //err = GetLastError(); //exit(err); return; } fdTable[fd].type = FD_SOCKET_ASYNC; } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -