/*
* os_win32.c --
*
- *
- * Copyright (c) 1995 Open Market, Inc.
- * All rights reserved.
- *
- * This file contains proprietary and confidential information and
- * remains the unpublished property of Open Market, Inc. Use,
- * disclosure, or reproduction is prohibited except as permitted by
- * express written license agreement with Open Market, Inc.
- *
* Bill Snapper
* snapper@openmarket.com
*
* (Special thanks to Karen and Bill. They made my job much easier and
* significantly more enjoyable.)
+ *
+ * Copyright (c) 1996 Open Market, Inc.
+ *
+ * See the file "LICENSE" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef lint
-static const char rcsid[] = "$Id: os_win32.c,v 1.2 1999/07/28 00:18:31 roberts Exp $";
+static const char rcsid[] = "$Id: os_win32.c,v 1.35 2004/01/31 17:47:07 robs Exp $";
#endif /* not lint */
-#include "fcgi_config.h"
-
-#define DLLAPI __declspec(dllexport)
-
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <sys/timeb.h>
-#include <windows.h>
+#include <process.h>
+#include <signal.h>
+
+#define DLLAPI __declspec(dllexport)
+#include "fcgimisc.h"
#include "fcgios.h"
-#define ASSERT assert
+#define WIN32_OPEN_MAX 128 /* XXX: Small hack */
-#define WIN32_OPEN_MAX 32 /* XXX: Small hack */
-#define MUTEX_VARNAME "_FCGI_MUTEX_"
+/*
+ * millisecs to wait for a client connection before checking the
+ * shutdown flag (then go back to waiting for a connection, etc).
+ */
+#define ACCEPT_TIMEOUT 1000
+#define MUTEX_VARNAME "_FCGI_MUTEX_"
+#define SHUTDOWN_EVENT_NAME "_FCGI_SHUTDOWN_EVENT_"
+#define LOCALHOST "localhost"
static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE;
static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE};
-static HANDLE hPipeMutex = INVALID_HANDLE_VALUE;;
-static char pipeMutexEnv[80] = "";
+// This is a nail for listening to more than one port..
+static HANDLE acceptMutex = INVALID_HANDLE_VALUE;
+
+static BOOLEAN shutdownPending = FALSE;
+static BOOLEAN shutdownNow = FALSE;
/*
* An enumeration of the file types
LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */
};
-typedef struct FD_TABLE *PFD_TABLE;
-
+/*
+ * XXX Note there is no dyanmic sizing of this table, so if the
+ * number of open file descriptors exceeds WIN32_OPEN_MAX the
+ * app will blow up.
+ */
static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
+static CRITICAL_SECTION fdTableCritical;
+
struct OVERLAPPED_REQUEST {
OVERLAPPED overlapped;
unsigned long instance; /* file instance (won't match after a close) */
static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
-static int isFastCGI = FALSE;
-static int isCGI = FALSE;
-static int listenType = FD_UNUSED;
+static FILE_TYPE listenType = FD_UNUSED;
+
+// XXX This should be a DESCRIPTOR
static HANDLE hListen = INVALID_HANDLE_VALUE;
-static int libInitialized = 0;
-\f
+static BOOLEAN libInitialized = FALSE;
+
/*
*--------------------------------------------------------------
*
*/
static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
{
- int index;
+ int index = -1;
- /*
- * If the "desiredFd" is not -1, try to get this entry for our
- * pseudo file descriptor. If this is not available, return -1
- * as the caller wanted to get this mapping. This is typically
- * only used for mapping stdio handles.
- */
- if ((desiredFd >= 0) &&
- (desiredFd < WIN32_OPEN_MAX)) {
-
- if(fdTable[desiredFd].type == FD_UNUSED) {
- index = desiredFd;
- goto found_entry;
- } else {
- return -1;
- }
-
- }
+ EnterCriticalSection(&fdTableCritical);
/*
- * Next see if the entry that matches "fd" is available.
+ * If desiredFd is set, try to get this entry (this is used for
+ * mapping stdio handles). Otherwise try to get the fd entry.
+ * If this is not available, find a the first empty slot. .
*/
- if ((fd > 0) &&
- (fd < WIN32_OPEN_MAX) && (fdTable[fd].type == FD_UNUSED)) {
- index = fd;
- goto found_entry;
+ if (desiredFd >= 0 && desiredFd < WIN32_OPEN_MAX)
+ {
+ if (fdTable[desiredFd].type == FD_UNUSED)
+ {
+ index = desiredFd;
+ }
+ }
+ else if (fd > 0)
+ {
+ if (fd < WIN32_OPEN_MAX && fdTable[fd].type == FD_UNUSED)
+ {
+ index = fd;
+ }
+ else
+ {
+ int i;
+
+ for (i = 1; i < WIN32_OPEN_MAX; ++i)
+ {
+ if (fdTable[i].type == FD_UNUSED)
+ {
+ index = i;
+ break;
+ }
+ }
+ }
}
-
- /*
- * Scan entries for one we can use. Start at 1 (0 fake id fails
- * in some cases). -K*
- */
- for (index = 1; index < WIN32_OPEN_MAX; index++)
- if (fdTable[index].type == FD_UNUSED)
- break;
-
- /* If no table entries are available, return error. */
- if (index == WIN32_OPEN_MAX) {
- SetLastError(WSAEMFILE);
- DebugBreak();
- return -1;
+
+ if (index != -1)
+ {
+ fdTable[index].fid.value = fd;
+ fdTable[index].type = type;
+ fdTable[index].path = NULL;
+ fdTable[index].Errno = NO_ERROR;
+ fdTable[index].status = 0;
+ fdTable[index].offset = -1;
+ fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
+ fdTable[index].hMapMutex = NULL;
+ fdTable[index].ovList = NULL;
}
-found_entry:
- fdTable[index].fid.value = fd;
- fdTable[index].type = type;
- fdTable[index].path = NULL;
- fdTable[index].Errno = NO_ERROR;
- fdTable[index].status = 0;
- fdTable[index].offset = -1;
- fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
- fdTable[index].hMapMutex = NULL;
- fdTable[index].ovList = NULL;
-
+ LeaveCriticalSection(&fdTableCritical);
return index;
}
-\f
+
/*
*--------------------------------------------------------------
*
*
*--------------------------------------------------------------
*/
-static void StdinThread(LPDWORD startup){
-
+static void StdinThread(void * startup)
+{
int doIo = TRUE;
- int fd;
- int bytesRead;
+ unsigned long fd;
+ unsigned long bytesRead;
POVERLAPPED_REQUEST pOv;
+ // Touch the arg to prevent warning
+ startup = NULL;
+
while(doIo) {
/*
* Block until a request to read from stdin comes in or a
ExitThread(0);
}
-\f
+void OS_ShutdownPending(void)
+{
+ shutdownPending = TRUE;
+}
+
+static void ShutdownRequestThread(void * arg)
+{
+ HANDLE shutdownEvent = (HANDLE) arg;
+
+ WaitForSingleObject(shutdownEvent, INFINITE);
+
+ shutdownPending = TRUE;
+
+ // emulate the unix behaviour
+ raise(SIGTERM);
+
+ if (listenType == FD_PIPE_SYNC)
+ {
+ // Its a hassle to get ConnectNamedPipe to return early,
+ // so just wack the whole process - yes, this will toast
+ // any requests in progress, but at least its a clean
+ // shutdown (its better than TerminateProcess())
+ exit(0);
+ }
+
+ // FD_SOCKET_SYNC: When in Accept(), select() is used to poll
+ // the shutdownPending flag - yeah this isn't pretty either
+ // but its only one process doing it if an Accept mutex is used.
+ // This at least buys no toasted requests.
+}
+
/*
*--------------------------------------------------------------
*
WSADATA wsaData;
int err;
int fakeFd;
- DWORD pipeMode;
- DWORD threadId;
char *cLenPtr = NULL;
- char *mutexPtr = NULL;
-
+ char *val = NULL;
+
if(libInitialized)
return 0;
+ InitializeCriticalSection(&fdTableCritical);
+
/*
* Initialize windows sockets library.
*/
- wVersion = MAKEWORD(1,1);
+ wVersion = MAKEWORD(2,0);
err = WSAStartup( wVersion, &wsaData );
if (err) {
fprintf(stderr, "Error starting Windows Sockets. Error: %d",
}
/*
+ * If a shutdown event is in the env, save it (I don't see any to
+ * remove it from the environment out from under the application).
+ * Spawn a thread to wait on the shutdown request.
+ */
+ val = getenv(SHUTDOWN_EVENT_NAME);
+ if (val != NULL)
+ {
+ HANDLE shutdownEvent = (HANDLE) atoi(val);
+
+ if (_beginthread(ShutdownRequestThread, 0, shutdownEvent) == -1)
+ {
+ return -1;
+ }
+ }
+
+ if (acceptMutex == INVALID_HANDLE_VALUE)
+ {
+ /* If an accept mutex is in the env, use it */
+ val = getenv(MUTEX_VARNAME);
+ if (val != NULL)
+ {
+ acceptMutex = (HANDLE) atoi(val);
+ }
+ }
+
+ /*
* Determine if this library is being used to listen for FastCGI
* connections. This is communicated by STDIN containing a
* valid handle to a listener object. In this case, both the
*/
if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
(GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
- (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) {
+ (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) )
+ {
+ DWORD pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ HANDLE oldStdIn = GetStdHandle(STD_INPUT_HANDLE);
+
+ // Move the handle to a "low" number
+ if (! DuplicateHandle(GetCurrentProcess(), oldStdIn,
+ GetCurrentProcess(), &hListen,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ return -1;
+ }
- hListen = GetStdHandle(STD_INPUT_HANDLE);
- isFastCGI = TRUE;
+ if (! SetStdHandle(STD_INPUT_HANDLE, hListen))
+ {
+ return -1;
+ }
+
+ CloseHandle(oldStdIn);
/*
* Set the pipe handle state so that it operates in wait mode.
* XXX: Initial assumption is that SetNamedPipeHandleState will
* fail if this is an IP socket...
*/
- pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
- if(SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) {
+ if (SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL))
+ {
listenType = FD_PIPE_SYNC;
- /*
- * Lookup the mutex. If one is found, save it and
- * remove it from the env table if it's not already
- * been done.
- */
- mutexPtr = getenv(MUTEX_VARNAME);
- if(mutexPtr != NULL) {
- hPipeMutex = (HANDLE)atoi(mutexPtr);
- putenv(MUTEX_VARNAME"=");
- }
- } else {
+ }
+ else
+ {
listenType = FD_SOCKET_SYNC;
}
}
*/
if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
atoi(cLenPtr) > 0) {
- hStdinThread = CreateThread(NULL, 8192,
- (LPTHREAD_START_ROUTINE)&StdinThread,
- NULL, 0, &threadId);
- if (hStdinThread == NULL) {
+ hStdinThread = (HANDLE) _beginthread(StdinThread, 0, NULL);
+ if (hStdinThread == (HANDLE) -1) {
printf("<H2>OS_LibInit Failed to create STDIN thread! ERROR: %d</H2>\r\n\r\n",
GetLastError());
return -1;
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
void OS_LibShutdown()
{
- if(hIoCompPort != INVALID_HANDLE_VALUE) {
+ if (hIoCompPort != INVALID_HANDLE_VALUE)
+ {
CloseHandle(hIoCompPort);
- hIoCompPort = INVALID_HANDLE_VALUE;
+ hIoCompPort = INVALID_HANDLE_VALUE;
}
- if(hStdinCompPort != INVALID_HANDLE_VALUE) {
+ if (hStdinCompPort != INVALID_HANDLE_VALUE)
+ {
CloseHandle(hStdinCompPort);
- hStdinCompPort = INVALID_HANDLE_VALUE;
+ hStdinCompPort = INVALID_HANDLE_VALUE;
}
- /*
- * Shutdown the socket library.
- */
+ if (acceptMutex != INVALID_HANDLE_VALUE)
+ {
+ ReleaseMutex(acceptMutex);
+ }
+
+ DisconnectNamedPipe(hListen);
+
+ CancelIo(hListen);
+
+
WSACleanup();
- return;
}
-\f
/*
*--------------------------------------------------------------
*
{
/* Catch it if fd is a bogus value */
ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
- ASSERT(fdTable[fd].type != FD_UNUSED);
- switch (fdTable[fd].type) {
- case FD_FILE_SYNC:
- case FD_FILE_ASYNC:
- /* Free file path string */
- ASSERT(fdTable[fd].path != NULL);
- free(fdTable[fd].path);
- fdTable[fd].path = NULL;
- break;
- default:
- /*
- * Break through to generic fdTable free-descriptor code
- */
- break;
+ EnterCriticalSection(&fdTableCritical);
+
+ if (fdTable[fd].type != FD_UNUSED)
+ {
+ switch (fdTable[fd].type)
+ {
+ case FD_FILE_SYNC:
+ case FD_FILE_ASYNC:
+
+ /* Free file path string */
+ ASSERT(fdTable[fd].path != NULL);
+ free(fdTable[fd].path);
+ fdTable[fd].path = NULL;
+ break;
+
+ default:
+ break;
+ }
+ ASSERT(fdTable[fd].path == NULL);
+
+ fdTable[fd].type = FD_UNUSED;
+ fdTable[fd].path = NULL;
+ fdTable[fd].Errno = NO_ERROR;
+ fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
+
+ if (fdTable[fd].hMapMutex != NULL)
+ {
+ CloseHandle(fdTable[fd].hMapMutex);
+ fdTable[fd].hMapMutex = NULL;
+ }
}
- ASSERT(fdTable[fd].path == NULL);
- fdTable[fd].type = FD_UNUSED;
- fdTable[fd].path = NULL;
- fdTable[fd].Errno = NO_ERROR;
- fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
- if (fdTable[fd].hMapMutex != NULL) {
- CloseHandle(fdTable[fd].hMapMutex);
- fdTable[fd].hMapMutex = NULL;
- }
+
+ LeaveCriticalSection(&fdTableCritical);
+
return;
}
-\f
+static short getPort(const char * bindPath)
+{
+ short port = 0;
+ char * p = strchr(bindPath, ':');
+
+ if (p && *++p)
+ {
+ char buf[6];
+
+ strncpy(buf, p, 6);
+ buf[5] = '\0';
+
+ port = (short) atoi(buf);
+ }
+
+ return port;
+}
+
/*
* OS_CreateLocalIpcFd --
*
*
*----------------------------------------------------------------------
*/
-int OS_CreateLocalIpcFd(char *bindPath)
+int OS_CreateLocalIpcFd(const char *bindPath, int backlog)
{
- int retFd = -1;
- SECURITY_ATTRIBUTES sa;
- HANDLE hListenPipe = INVALID_HANDLE_VALUE;
- char *localPath;
- SOCKET listenSock;
- int bpLen;
- int servLen;
- struct sockaddr_in sockAddr;
- char host[1024];
- short port;
- int tcp = FALSE;
- int flag = 1;
- char *tp;
-
- strcpy(host, bindPath);
- if((tp = strchr(host, ':')) != 0) {
- *tp++ = 0;
- if((port = atoi(tp)) == 0) {
- *--tp = ':';
- } else {
- tcp = TRUE;
- }
- }
- if(tcp && (*host && strcmp(host, "localhost") != 0)) {
- fprintf(stderr, "To start a service on a TCP port can not "
- "specify a host name.\n"
- "You should either use \"localhost:<port>\" or "
- " just use \":<port>.\"\n");
- exit(1);
+ int pseudoFd = -1;
+ short port = getPort(bindPath);
+
+ if (acceptMutex == INVALID_HANDLE_VALUE)
+ {
+ acceptMutex = CreateMutex(NULL, FALSE, NULL);
+ if (acceptMutex == NULL) return -2;
+ if (! SetHandleInformation(acceptMutex, HANDLE_FLAG_INHERIT, TRUE)) return -3;
}
- if(tcp) {
- listenSock = socket(AF_INET, SOCK_STREAM, 0);
- if(listenSock == SOCKET_ERROR) {
- return -1;
- }
- /*
- * Bind the listening socket.
- */
- memset((char *) &sockAddr, 0, sizeof(sockAddr));
- sockAddr.sin_family = AF_INET;
- sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
- sockAddr.sin_port = htons(port);
- servLen = sizeof(sockAddr);
-
- if(bind(listenSock, (struct sockaddr *) &sockAddr, servLen) < 0
- || listen(listenSock, 5) < 0) {
- perror("bind/listen");
- exit(errno);
- }
+ // There's nothing to be gained (at the moment) by a shutdown Event
- retFd = Win32NewDescriptor(FD_SOCKET_SYNC, (int)listenSock, -1);
- return retFd;
+ if (port && *bindPath != ':' && strncmp(bindPath, LOCALHOST, strlen(LOCALHOST)))
+ {
+ fprintf(stderr, "To start a service on a TCP port can not "
+ "specify a host name.\n"
+ "You should either use \"localhost:<port>\" or "
+ " just use \":<port>.\"\n");
+ exit(1);
}
+ listenType = (port) ? FD_SOCKET_SYNC : FD_PIPE_ASYNC;
+
+ if (port)
+ {
+ SOCKET listenSock;
+ struct sockaddr_in sockAddr;
+ int sockLen = sizeof(sockAddr);
+
+ memset(&sockAddr, 0, sizeof(sockAddr));
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ sockAddr.sin_port = htons(port);
+
+ listenSock = socket(AF_INET, SOCK_STREAM, 0);
+ if (listenSock == INVALID_SOCKET)
+ {
+ return -4;
+ }
- /*
- * Initialize the SECURITY_ATTRIUBTES structure.
- */
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE; /* This will be inherited by the
- * FastCGI process
- */
+ if (bind(listenSock, (struct sockaddr *) &sockAddr, sockLen) )
+ {
+ return -12;
+ }
- /*
- * Create a mutex to be used to synchronize access to accepting a
- * connection on a named pipe. We don't want to own this at creation
- * time but would rather let the first process that goes for it
- * be able to acquire it.
- */
- hPipeMutex = CreateMutex(NULL, FALSE, NULL);
- if(hPipeMutex == NULL) {
- return -1;
- }
- if(!SetHandleInformation(hPipeMutex, HANDLE_FLAG_INHERIT,
- TRUE)) {
- return -1;
+ if (listen(listenSock, backlog))
+ {
+ return -5;
+ }
+
+ pseudoFd = Win32NewDescriptor(listenType, listenSock, -1);
+
+ if (pseudoFd == -1)
+ {
+ closesocket(listenSock);
+ return -6;
+ }
+
+ hListen = (HANDLE) listenSock;
}
- sprintf(pipeMutexEnv, "%s=%d", MUTEX_VARNAME, (int)hPipeMutex);
- putenv(pipeMutexEnv);
+ else
+ {
+ HANDLE hListenPipe = INVALID_HANDLE_VALUE;
+ char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
+
+ if (! pipePath)
+ {
+ return -7;
+ }
- /*
- * Create a unique name to be used for the socket bind path.
- * Make sure that this name is unique and that there's no process
- * bound to it.
- *
- * Named Pipe Pathname: \\.\pipe\FastCGI\OM_WS.pid.N
- * Where: N is the pipe instance on the machine.
- *
- */
- bpLen = (int)strlen(bindPathPrefix);
- bpLen += strlen(bindPath);
- localPath = malloc(bpLen+2);
- strcpy(localPath, bindPathPrefix);
- strcat(localPath, bindPath);
+ strcpy(pipePath, bindPathPrefix);
+ strcat(pipePath, bindPath);
- /*
- * Create and setup the named pipe to be used by the fcgi server.
- */
- hListenPipe = CreateNamedPipe(localPath, /* name of pipe */
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE | PIPE_WAIT |
- PIPE_READMODE_BYTE, /* pipe IO type */
- PIPE_UNLIMITED_INSTANCES, /* number of instances */
- 4096, /* size of outbuf (0 == allocate as necessary) */
- 4096, /* size of inbuf */
- 0, /*1000,*/ /* default time-out value */
- &sa); /* security attributes */
- free(localPath);
- /*
- * Can't create an instance of the pipe, fail...
- */
- if (hListenPipe == INVALID_HANDLE_VALUE) {
- return -1;
+ hListenPipe = CreateNamedPipe(pipePath,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
+ PIPE_UNLIMITED_INSTANCES,
+ 4096, 4096, 0, NULL);
+
+ free(pipePath);
+
+ if (hListenPipe == INVALID_HANDLE_VALUE)
+ {
+ return -8;
+ }
+
+ if (! SetHandleInformation(hListenPipe, HANDLE_FLAG_INHERIT, TRUE))
+ {
+ return -9;
+ }
+
+ pseudoFd = Win32NewDescriptor(listenType, (int) hListenPipe, -1);
+
+ if (pseudoFd == -1)
+ {
+ CloseHandle(hListenPipe);
+ return -10;
+ }
+
+ hListen = (HANDLE) hListenPipe;
}
- retFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hListenPipe, -1);
- return retFd;
+ return pseudoFd;
}
-\f
/*
*----------------------------------------------------------------------
*
*/
int OS_FcgiConnect(char *bindPath)
{
- char *pipePath = NULL;
- HANDLE hPipe;
- int pseudoFd, err;
-
- struct sockaddr_in sockAddr;
- int servLen, resultSock;
- int connectStatus;
- char *tp;
- char host[1024];
- short port;
- int tcp = FALSE;
-
- strcpy(host, bindPath);
- if((tp = strchr(host, ':')) != 0) {
- *tp++ = 0;
- if((port = atoi(tp)) == 0) {
- *--tp = ':';
- } else {
- tcp = TRUE;
- }
- }
- if(tcp == TRUE) {
- struct hostent *hp;
- if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
- fprintf(stderr, "Unknown host: %s\n", bindPath);
- exit(1000);
- }
- sockAddr.sin_family = AF_INET;
- memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
- sockAddr.sin_port = htons(port);
- servLen = sizeof(sockAddr);
- resultSock = socket(AF_INET, SOCK_STREAM, 0);
-
- assert(resultSock >= 0);
- connectStatus = connect(resultSock, (struct sockaddr *)
- &sockAddr, servLen);
- if(connectStatus < 0) {
- /*
- * Most likely (errno == ENOENT || errno == ECONNREFUSED)
- * and no FCGI application server is running.
- */
- closesocket(resultSock);
- return -1;
- }
- pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, resultSock, -1);
- if(pseudoFd == -1) {
- closesocket(resultSock);
- }
- return pseudoFd;
- }
+ short port = getPort(bindPath);
+ int pseudoFd = -1;
+
+ if (port)
+ {
+ struct hostent *hp;
+ char *host = NULL;
+ struct sockaddr_in sockAddr;
+ int sockLen = sizeof(sockAddr);
+ SOCKET sock;
+
+ if (*bindPath != ':')
+ {
+ char * p = strchr(bindPath, ':');
+ int len = p - bindPath + 1;
+
+ host = malloc(len);
+ strncpy(host, bindPath, len);
+ host[len] = '\0';
+ }
+
+ hp = gethostbyname(host ? host : LOCALHOST);
- /*
- * Not a TCP connection, create and connect to a named pipe.
- */
- pipePath = malloc((size_t)(strlen(bindPathPrefix) + strlen(bindPath) + 2));
- if(pipePath == NULL) {
- return -1;
- }
- strcpy(pipePath, bindPathPrefix);
- strcat(pipePath, bindPath);
-
- hPipe = CreateFile (pipePath,
- /* Generic access, read/write. */
- GENERIC_WRITE | GENERIC_READ,
- /* Share both read and write. */
- FILE_SHARE_READ | FILE_SHARE_WRITE ,
- NULL, /* No security.*/
- OPEN_EXISTING, /* Fail if not existing. */
- FILE_FLAG_OVERLAPPED, /* Use overlap. */
- NULL); /* No template. */
-
- free(pipePath);
- if(hPipe == INVALID_HANDLE_VALUE) {
- return -1;
+ if (host)
+ {
+ free(host);
+ }
+
+ if (hp == NULL)
+ {
+ fprintf(stderr, "Unknown host: %s\n", bindPath);
+ return -1;
+ }
+
+ memset(&sockAddr, 0, sizeof(sockAddr));
+ sockAddr.sin_family = AF_INET;
+ memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
+ sockAddr.sin_port = htons(port);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET)
+ {
+ return -1;
+ }
+
+ if (! connect(sock, (struct sockaddr *) &sockAddr, sockLen))
+ {
+ closesocket(sock);
+ return -1;
+ }
+
+ pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, sock, -1);
+ if (pseudoFd == -1)
+ {
+ closesocket(sock);
+ return -1;
+ }
}
+ else
+ {
+ char *pipePath = malloc(strlen(bindPathPrefix) + strlen(bindPath) + 1);
+ HANDLE hPipe;
+
+ if (! pipePath)
+ {
+ return -1;
+ }
- if ((pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int)hPipe, -1)) == -1) {
- CloseHandle(hPipe);
- return -1;
- } else {
+ strcpy(pipePath, bindPathPrefix);
+ strcat(pipePath, bindPath);
+
+ hPipe = CreateFile(pipePath,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ free(pipePath);
+
+ if( hPipe == INVALID_HANDLE_VALUE)
+ {
+ return -1;
+ }
+
+ pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int) hPipe, -1);
+
+ if (pseudoFd == -1)
+ {
+ CloseHandle(hPipe);
+ return -1;
+ }
+
/*
- * Set stdin equal to our pseudo FD and create the I/O completion
- * port to be used for async I/O.
- */
- if (!CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) {
- err = GetLastError();
- Win32FreeDescriptor(pseudoFd);
- CloseHandle(hPipe);
- return -1;
- }
+ * Set stdin equal to our pseudo FD and create the I/O completion
+ * port to be used for async I/O.
+ */
+ if (! CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1))
+ {
+ Win32FreeDescriptor(pseudoFd);
+ CloseHandle(hPipe);
+ return -1;
+ }
}
- return pseudoFd;
+
+ return pseudoFd;
}
-\f
/*
*--------------------------------------------------------------
*
int OS_Read(int fd, char * buf, size_t len)
{
DWORD bytesRead;
- int ret;
+ int ret = -1;
- /*
- * Catch any bogus fd values
- */
ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
- switch (fdTable[fd].type) {
+ if (shutdownNow) return -1;
+
+ switch (fdTable[fd].type)
+ {
case FD_FILE_SYNC:
case FD_FILE_ASYNC:
case FD_PIPE_SYNC:
case FD_PIPE_ASYNC:
- bytesRead = fd;
- /*
- * ReadFile returns: TRUE success, FALSE failure
- */
- if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
- NULL)) {
- fdTable[fd].Errno = GetLastError();
- return -1;
+
+ if (ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead, NULL))
+ {
+ ret = bytesRead;
+ }
+ else
+ {
+ fdTable[fd].Errno = GetLastError();
}
- return bytesRead;
+
+ break;
case FD_SOCKET_SYNC:
case FD_SOCKET_ASYNC:
- /* winsock recv returns n bytes recv'ed, SOCKET_ERROR failure */
- /*
- * XXX: Test this with ReadFile. If it works, remove this code
- * to simplify the routine.
- */
- if ((ret = recv(fdTable[fd].fid.sock, buf, len, 0)) ==
- SOCKET_ERROR) {
- fdTable[fd].Errno = WSAGetLastError();
- return -1;
+
+ ret = recv(fdTable[fd].fid.sock, buf, len, 0);
+ if (ret == SOCKET_ERROR)
+ {
+ fdTable[fd].Errno = WSAGetLastError();
+ ret = -1;
}
- return ret;
- default:
- return -1;
+
+ break;
+
+ default:
+
+ ASSERT(0);
}
+
+ return ret;
}
-\f
+
/*
*--------------------------------------------------------------
*
int OS_Write(int fd, char * buf, size_t len)
{
DWORD bytesWritten;
- int ret;
+ int ret = -1;
- /*
- * Catch any bogus fd values
- */
- ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
- ASSERT((fdTable[fd].type > FD_UNUSED) &&
- (fdTable[fd].type <= FD_PIPE_ASYNC));
+ ASSERT(fd >= 0 && fd < WIN32_OPEN_MAX);
- switch (fdTable[fd].type) {
+ if (shutdownNow) return -1;
+
+ switch (fdTable[fd].type)
+ {
case FD_FILE_SYNC:
case FD_FILE_ASYNC:
case FD_PIPE_SYNC:
case FD_PIPE_ASYNC:
- bytesWritten = fd;
- /*
- * WriteFile returns: TRUE success, FALSE failure
- */
- if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len,
- &bytesWritten, NULL)) {
- fdTable[fd].Errno = GetLastError();
- return -1;
+
+ if (WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten, NULL))
+ {
+ ret = bytesWritten;
+ }
+ else
+ {
+ fdTable[fd].Errno = GetLastError();
}
- return bytesWritten;
+
+ break;
+
case FD_SOCKET_SYNC:
case FD_SOCKET_ASYNC:
- /* winsock send returns n bytes written, SOCKET_ERROR failure */
- /*
- * XXX: Test this with WriteFile. If it works, remove this code
- * to simplify the routine.
- */
- if ((ret = send(fdTable[fd].fid.sock, buf, len, 0)) ==
- SOCKET_ERROR) {
- fdTable[fd].Errno = WSAGetLastError();
- return -1;
+
+ ret = send(fdTable[fd].fid.sock, buf, len, 0);
+ if (ret == SOCKET_ERROR)
+ {
+ fdTable[fd].Errno = WSAGetLastError();
+ ret = -1;
}
- return ret;
- default:
- return -1;
+
+ break;
+
+ default:
+
+ ASSERT(0);
}
+
+ return ret;
}
-\f
/*
*----------------------------------------------------------------------
*
}
}
-\f
/*
*--------------------------------------------------------------
*
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
}
return 0;
}
-\f
+
/*
*--------------------------------------------------------------
*
return 0;
}
-\f
/*
*--------------------------------------------------------------
*
*
*--------------------------------------------------------------
*/
-int OS_Close(int fd)
+int OS_Close(int fd, int shutdown_ok)
{
int ret = 0;
case FD_PIPE_ASYNC:
case FD_FILE_SYNC:
case FD_FILE_ASYNC:
- /*
- * CloseHandle returns: TRUE success, 0 failure
- */
- if (CloseHandle(fdTable[fd].fid.fileHandle) == FALSE)
- ret = -1;
- break;
- case FD_SOCKET_SYNC:
+
+ break;
+
+ case FD_SOCKET_SYNC:
case FD_SOCKET_ASYNC:
- /*
- * Closing a socket that has an async read outstanding causes a
- * tcp reset and possible data loss. The shutdown call seems to
- * prevent this.
- */
- shutdown(fdTable[fd].fid.sock, 2);
- /*
- * closesocket returns: 0 success, SOCKET_ERROR failure
- */
- if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
- ret = -1;
- break;
+
+ /*
+ * shutdown() the send side and then read() from client until EOF
+ * or a timeout expires. This is done to minimize the potential
+ * that a TCP RST will be sent by our TCP stack in response to
+ * receipt of additional data from the client. The RST would
+ * cause the client to discard potentially useful response data.
+ */
+
+ if (shutdown_ok)
+ {
+ if (shutdown(fdTable[fd].fid.sock, SD_SEND) == 0)
+ {
+ 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:
- return -1; /* fake failure */
+
+ ret = -1; /* fake failure */
}
Win32FreeDescriptor(fd);
return ret;
}
-\f
+
/*
*--------------------------------------------------------------
*
ret = -1;
return ret;
}
-\f
+
/*
*--------------------------------------------------------------
*
*/
int OS_DoIo(struct timeval *tmo)
{
- int fd;
- int bytes;
+ unsigned long fd;
+ unsigned long bytes;
POVERLAPPED_REQUEST pOv;
struct timeb tb;
int ms;
return 0;
}
-\f
+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_WSAACEPT
+static 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;
+}
+#endif
+
+static 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_FcgiIpcAccept --
+ * OS_Accept --
+ *
+ * Accepts a new FastCGI connection. This routine knows whether
+ * we're dealing with TCP based sockets or NT Named Pipes for IPC.
*
- * 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.
*
- * Side effects:
- * New IPC connection is accepted.
- *
*----------------------------------------------------------------------
*/
-int OS_FcgiIpcAccept(char *serverHostList)
+int OS_Accept(int listen_sock, int fail_on_intr, const char *webServerAddrs)
{
- struct sockaddr_in sa;
- int isNewConnection;
int ipcFd = -1;
- BOOL pConnected;
- HANDLE hDup;
- SOCKET hSock;
- int clilen = sizeof(sa);
- DWORD waitForStatus;
- switch(listenType) {
+ // Touch args to prevent warnings
+ listen_sock = 0; fail_on_intr = 0;
- case FD_PIPE_SYNC:
- waitForStatus = WaitForSingleObject(hPipeMutex,INFINITE);
- switch(waitForStatus) {
- case WAIT_OBJECT_0:
- case WAIT_ABANDONED:
- break;
+ // @todo Muliple listen sockets and sockets other than 0 are not
+ // supported due to the use of globals.
- case WAIT_FAILED:
- default:
- return -1;
- }
+ if (shutdownPending)
+ {
+ OS_LibShutdown();
+ return -1;
+ }
- /*
- * We have the mutex, go for the connection.
- */
- pConnected = ConnectNamedPipe(hListen, NULL) ?
- TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
-
- ReleaseMutex(hPipeMutex);
- if(pConnected) {
- /*
- * Success...
- */
- if (!DuplicateHandle(GetCurrentProcess(), hListen,
- GetCurrentProcess(), &hDup, 0,
- TRUE, /* allow inheritance */
- DUPLICATE_SAME_ACCESS)) {
- return -1;
- }
- ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hDup, -1);
- if(ipcFd == -1) {
- DisconnectNamedPipe(hListen);
- CloseHandle(hDup);
- }
- return ipcFd;
- } else {
+ // 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)
+ {
+ if (WaitForSingleObject(acceptMutex, INFINITE) == WAIT_FAILED)
+ {
+ printLastError("WaitForSingleObject() failed");
return -1;
+ }
}
- break;
-
- case FD_SOCKET_SYNC:
- hSock = accept((int)hListen, (struct sockaddr *) &sa, &clilen);
- if(hSock == -1) {
- return -1;
- } else if (sa.sin_family != AF_INET) { /* What are we? */
- closesocket(hSock);
- hSock = (SOCKET)-1;
- return -1;
- } else {
- char *tp1, *tp2;
- int match = 0;
- if (serverHostList == NULL)
- isNewConnection = TRUE;
- else {
- tp1 = (char *) malloc(strlen(serverHostList)+1);
- ASSERT(tp1 != NULL);
- strcpy(tp1, serverHostList);
- while(tp1) {
- if ((tp2 = strchr(tp1, ',')) != NULL)
- *tp2++ = 0;
-
- if (inet_addr(tp1) == sa.sin_addr.s_addr) {
- match = 1;
- break;
- }
- tp1 = tp2;
- }
- free(tp1);
- if (match)
- isNewConnection = TRUE;
- else {
- closesocket(hSock);
- hSock = (SOCKET)-1;
- return -1;
- }
- }
- }
-
- ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
- if(ipcFd == -1) {
- closesocket(hSock);
- }
- return ipcFd;
- break;
-
- case FD_UNUSED:
- default:
- exit(101);
- break;
-
+
+ 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;
}
-\f
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-int OS_IpcClose(int ipcFd)
+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) {
-
+ 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)) {
- OS_Close(ipcFd);
- return 0;
- } else {
- return -1;
- }
- break;
+ /*
+ * 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;
+
+ /* fall through */
case FD_SOCKET_SYNC:
- OS_Close(ipcFd);
- break;
+
+ OS_Close(ipcFd, shutdown);
+ break;
case FD_UNUSED:
default:
- exit(106);
- break;
+
+ exit(106);
+ break;
}
+ return 0;
}
-\f
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
-int OS_IsFcgi()
+int OS_IsFcgi(int sock)
{
- if(listenType == FD_UNUSED) {
- isCGI = TRUE;
- return 0;
- } else {
- isCGI = FALSE;
- return 1;
- }
+ // Touch args to prevent warnings
+ sock = 0;
+
+ /* XXX This is broken for sock */
+
+ return (listenType != FD_UNUSED);
}
-\f
/*
*----------------------------------------------------------------------
*
*/
void OS_SetFlags(int fd, int flags)
{
- long int pLong = 1L;
+ unsigned long pLong = 1L;
int err;
- if(fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
+ if (fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
SOCKET_ERROR) {
exit(WSAGetLastError());