Disable Nagle algorithm for TCP based connections because
[catagits/fcgi2.git] / libfcgi / os_win32.c
CommitLineData
0198fd3c 1/*
2 * os_win32.c --
3 *
4 *
5 * Copyright (c) 1995 Open Market, Inc.
6 * All rights reserved.
7 *
8 * This file contains proprietary and confidential information and
9 * remains the unpublished property of Open Market, Inc. Use,
10 * disclosure, or reproduction is prohibited except as permitted by
11 * express written license agreement with Open Market, Inc.
12 *
13 * Bill Snapper
14 * snapper@openmarket.com
15 *
16 * (Special thanks to Karen and Bill. They made my job much easier and
17 * significantly more enjoyable.)
18 */
19#ifdef _WIN32
20#define DLLAPI __declspec(dllexport)
21#endif
22
23#ifndef lint
24static const char rcsid[] = "$Id: os_win32.c,v 1.1 1997/09/16 15:36:33 stanleyg Exp $";
25#endif /* not lint */
26
27#include <windows.h>
28#include <stdio.h>
29#include "fcgios.h"
30
31/*
32 * io.c will instantiate globals; all other
33 * modules access these variables as externs.
34 */
35#ifndef EXTRN
36#define EXTRN extern
37#endif
38
39#include <assert.h>
40#include <sys/timeb.h>
41
42#define WIN32_OPEN_MAX 32 /* XXX: Small hack */
43
44#define ASSERT assert
45
46static HANDLE hIoCompPort = INVALID_HANDLE_VALUE;
47static HANDLE hStdinCompPort = INVALID_HANDLE_VALUE;
48static HANDLE hStdinThread = INVALID_HANDLE_VALUE;
49
50static HANDLE stdioHandles[3] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
51 INVALID_HANDLE_VALUE};
52
53static HANDLE hPipeMutex = INVALID_HANDLE_VALUE;;
54static char pipeMutexEnv[80] = "";
55
56#define MUTEX_VARNAME "_FCGI_MUTEX_"
57
58/*
59 * An enumeration of the file types
60 * supported by the FD_TABLE structure.
61 *
62 * XXX: Not all currently supported. This allows for future
63 * functionality.
64 */
65typedef enum {
66 FD_UNUSED,
67 FD_FILE_SYNC,
68 FD_FILE_ASYNC,
69 FD_SOCKET_SYNC,
70 FD_SOCKET_ASYNC,
71 FD_PIPE_SYNC,
72 FD_PIPE_ASYNC
73} FILE_TYPE;
74
75typedef union {
76 HANDLE fileHandle;
77 SOCKET sock;
78 unsigned int value;
79} DESCRIPTOR;
80
81/*
82 * Structure used to map file handle and socket handle
83 * values into values that can be used to create unix-like
84 * select bitmaps, read/write for both sockets/files.
85 */
86struct FD_TABLE {
87 DESCRIPTOR fid;
88 FILE_TYPE type;
89 char *path;
90 DWORD Errno;
91 unsigned long instance;
92 int status;
93 int offset; /* only valid for async file writes */
94 LPDWORD offsetHighPtr; /* pointers to offset high and low words */
95 LPDWORD offsetLowPtr; /* only valid for async file writes (logs) */
96 HANDLE hMapMutex; /* mutex handle for multi-proc offset update */
97 LPVOID ovList; /* List of associated OVERLAPPED_REQUESTs */
98};
99
100typedef struct FD_TABLE *PFD_TABLE;
101
102static struct FD_TABLE fdTable[WIN32_OPEN_MAX];
103
104struct OVERLAPPED_REQUEST {
105 OVERLAPPED overlapped;
106 unsigned long instance; /* file instance (won't match after a close) */
107 OS_AsyncProc procPtr; /* callback routine */
108 ClientData clientData; /* callback argument */
109 ClientData clientData1; /* additional clientData */
110};
111typedef struct OVERLAPPED_REQUEST *POVERLAPPED_REQUEST;
112
113static const char *bindPathPrefix = "\\\\.\\pipe\\FastCGI\\";
114
115static int isFastCGI = FALSE;
116static int isCGI = FALSE;
117static int listenType = FD_UNUSED;
118static HANDLE hListen = INVALID_HANDLE_VALUE;
119static int libInitialized = 0;
120
121\f
122/*
123 *--------------------------------------------------------------
124 *
125 * Win32NewDescriptor --
126 *
127 * Set up for I/O descriptor masquerading.
128 *
129 * Results:
130 * Returns "fake id" which masquerades as a UNIX-style "small
131 * non-negative integer" file/socket descriptor.
132 * Win32_* routine below will "do the right thing" based on the
133 * descriptor's actual type. -1 indicates failure.
134 *
135 * Side effects:
136 * Entry in fdTable is reserved to represent the socket/file.
137 *
138 *--------------------------------------------------------------
139 */
140static int Win32NewDescriptor(FILE_TYPE type, int fd, int desiredFd)
141{
142 int index;
143
144 /*
145 * If the "desiredFd" is not -1, try to get this entry for our
146 * pseudo file descriptor. If this is not available, return -1
147 * as the caller wanted to get this mapping. This is typically
148 * only used for mapping stdio handles.
149 */
150 if ((desiredFd >= 0) &&
151 (desiredFd < WIN32_OPEN_MAX)) {
152
153 if(fdTable[desiredFd].type == FD_UNUSED) {
154 index = desiredFd;
155 goto found_entry;
156 } else {
157 return -1;
158 }
159
160 }
161
162 /*
163 * Next see if the entry that matches "fd" is available.
164 */
165 if ((fd > 0) &&
166 (fd < WIN32_OPEN_MAX) && (fdTable[fd].type == FD_UNUSED)) {
167 index = fd;
168 goto found_entry;
169 }
170
171 /*
172 * Scan entries for one we can use. Start at 1 (0 fake id fails
173 * in some cases). -K*
174 */
175 for (index = 1; index < WIN32_OPEN_MAX; index++)
176 if (fdTable[index].type == FD_UNUSED)
177 break;
178
179 /* If no table entries are available, return error. */
180 if (index == WIN32_OPEN_MAX) {
181 SetLastError(WSAEMFILE);
182 DebugBreak();
183 return -1;
184 }
185
186found_entry:
187 fdTable[index].fid.value = fd;
188 fdTable[index].type = type;
189 fdTable[index].path = NULL;
190 fdTable[index].Errno = NO_ERROR;
191 fdTable[index].status = 0;
192 fdTable[index].offset = -1;
193 fdTable[index].offsetHighPtr = fdTable[index].offsetLowPtr = NULL;
194 fdTable[index].hMapMutex = NULL;
195 fdTable[index].ovList = NULL;
196
197 return index;
198}
199\f
200/*
201 *--------------------------------------------------------------
202 *
203 * StdinThread--
204 *
205 * This thread performs I/O on stadard input. It is needed
206 * because you can't guarantee that all applications will
207 * create standard input with sufficient access to perform
208 * asynchronous I/O. Since we don't want to block the app
209 * reading from stdin we make it look like it's using I/O
210 * completion ports to perform async I/O.
211 *
212 * Results:
213 * Data is read from stdin and posted to the io completion
214 * port.
215 *
216 * Side effects:
217 * None.
218 *
219 *--------------------------------------------------------------
220 */
221static void StdinThread(LPDWORD startup){
222
223 int doIo = TRUE;
224 int fd;
225 int bytesRead;
226 POVERLAPPED_REQUEST pOv;
227
228 while(doIo) {
229 /*
230 * Block until a request to read from stdin comes in or a
231 * request to terminate the thread arrives (fd = -1).
232 */
233 if (!GetQueuedCompletionStatus(hStdinCompPort, &bytesRead, &fd,
234 (LPOVERLAPPED *)&pOv, (DWORD)-1) && !pOv) {
235 doIo = 0;
236 break;
237 }
238
239 ASSERT((fd == STDIN_FILENO) || (fd == -1));
240 if(fd == -1) {
241 doIo = 0;
242 break;
243 }
244 ASSERT(pOv->clientData1 != NULL);
245
246 if(ReadFile(stdioHandles[STDIN_FILENO], pOv->clientData1, bytesRead,
247 &bytesRead, NULL)) {
248 PostQueuedCompletionStatus(hIoCompPort, bytesRead,
249 STDIN_FILENO, (LPOVERLAPPED)pOv);
250 } else {
251 doIo = 0;
252 break;
253 }
254 }
255
256 ExitThread(0);
257}
258
259\f
260/*
261 *--------------------------------------------------------------
262 *
263 * OS_LibInit --
264 *
265 * Set up the OS library for use.
266 *
267 * Results:
268 * Returns 0 if success, -1 if not.
269 *
270 * Side effects:
271 * Sockets initialized, pseudo file descriptors setup, etc.
272 *
273 *--------------------------------------------------------------
274 */
275int OS_LibInit(int stdioFds[3])
276{
277 WORD wVersion;
278 WSADATA wsaData;
279 int err;
280 int fakeFd;
281 DWORD pipeMode;
282 DWORD threadId;
283 char *cLenPtr = NULL;
284 char *mutexPtr = NULL;
285
286 if(libInitialized)
287 return 0;
288
289 /*
290 * Initialize windows sockets library.
291 */
292 wVersion = MAKEWORD(1,1);
293 err = WSAStartup( wVersion, &wsaData );
294 if (err) {
295 fprintf(stderr, "Error starting Windows Sockets. Error: %d",
296 WSAGetLastError());
297 exit(111);
298 }
299
300 /*
301 * Create the I/O completion port to be used for our I/O queue.
302 */
303 if (hIoCompPort == INVALID_HANDLE_VALUE) {
304 hIoCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
305 0, 1);
306 if(hIoCompPort == INVALID_HANDLE_VALUE) {
307 printf("<H2>OS_LibInit Failed CreateIoCompletionPort! ERROR: %d</H2>\r\n\r\n",
308 GetLastError());
309 return -1;
310 }
311 }
312
313 /*
314 * Determine if this library is being used to listen for FastCGI
315 * connections. This is communicated by STDIN containing a
316 * valid handle to a listener object. In this case, both the
317 * "stdout" and "stderr" handles will be INVALID (ie. closed) by
318 * the starting process.
319 *
320 * The trick is determining if this is a pipe or a socket...
321 *
322 * XXX: Add the async accept test to determine socket or handle to a
323 * pipe!!!
324 */
325 if((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&
326 (GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&
327 (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) ) {
328
329 hListen = GetStdHandle(STD_INPUT_HANDLE);
330 isFastCGI = TRUE;
331
332 /*
333 * Set the pipe handle state so that it operates in wait mode.
334 *
335 * NOTE: The listenFd is not mapped to a pseudo file descriptor
336 * as all work done on it is contained to the OS library.
337 *
338 * XXX: Initial assumption is that SetNamedPipeHandleState will
339 * fail if this is an IP socket...
340 */
341 pipeMode = PIPE_READMODE_BYTE | PIPE_WAIT;
342 if(SetNamedPipeHandleState(hListen, &pipeMode, NULL, NULL)) {
343 listenType = FD_PIPE_SYNC;
344 /*
345 * Lookup the mutex. If one is found, save it and
346 * remove it from the env table if it's not already
347 * been done.
348 */
349 mutexPtr = getenv(MUTEX_VARNAME);
350 if(mutexPtr != NULL) {
351 hPipeMutex = (HANDLE)atoi(mutexPtr);
352 putenv(MUTEX_VARNAME"=");
353 }
354 } else {
355 listenType = FD_SOCKET_SYNC;
356 }
357 }
358
359 /*
360 * If there are no stdioFds passed in, we're done.
361 */
362 if(stdioFds == NULL) {
363 libInitialized = 1;
364 return 0;
365 }
366
367 /*
368 * Setup standard input asynchronous I/O. There is actually a separate
369 * thread spawned for this purpose. The reason for this is that some
370 * web servers use anonymous pipes for the connection between itself
371 * and a CGI application. Anonymous pipes can't perform asynchronous
372 * I/O or use I/O completion ports. Therefore in order to present a
373 * consistent I/O dispatch model to an application we emulate I/O
374 * completion port behavior by having the standard input thread posting
375 * messages to the hIoCompPort which look like a complete overlapped
376 * I/O structure. This keeps the event dispatching simple from the
377 * application perspective.
378 */
379 stdioHandles[STDIN_FILENO] = GetStdHandle(STD_INPUT_HANDLE);
380
381 if(!SetHandleInformation(stdioHandles[STDIN_FILENO],
382 HANDLE_FLAG_INHERIT, 0)) {
383/*
384 * XXX: Causes error when run from command line. Check KB
385 err = GetLastError();
386 DebugBreak();
387 exit(99);
388 */
389 }
390
391 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
392 (int)stdioHandles[STDIN_FILENO],
393 STDIN_FILENO)) == -1) {
394 return -1;
395 } else {
396 /*
397 * Set stdin equal to our pseudo FD and create the I/O completion
398 * port to be used for async I/O.
399 */
400 stdioFds[STDIN_FILENO] = fakeFd;
401 }
402
403 /*
404 * Create the I/O completion port to be used for communicating with
405 * the thread doing I/O on standard in. This port will carry read
406 * and possibly thread termination requests to the StdinThread.
407 */
408 if (hStdinCompPort == INVALID_HANDLE_VALUE) {
409 hStdinCompPort = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL,
410 0, 1);
411 if(hStdinCompPort == INVALID_HANDLE_VALUE) {
412 printf("<H2>OS_LibInit Failed CreateIoCompletionPort: STDIN! ERROR: %d</H2>\r\n\r\n",
413 GetLastError());
414 return -1;
415 }
416 }
417
418 /*
419 * Create the thread that will read stdin if the CONTENT_LENGTH
420 * is non-zero.
421 */
422 if((cLenPtr = getenv("CONTENT_LENGTH")) != NULL &&
423 atoi(cLenPtr) > 0) {
424 hStdinThread = CreateThread(NULL, 8192,
425 (LPTHREAD_START_ROUTINE)&StdinThread,
426 NULL, 0, &threadId);
427 if (hStdinThread == NULL) {
428 printf("<H2>OS_LibInit Failed to create STDIN thread! ERROR: %d</H2>\r\n\r\n",
429 GetLastError());
430 return -1;
431 }
432 }
433
434 /*
435 * STDOUT will be used synchronously.
436 *
437 * XXX: May want to convert this so that it could be used for OVERLAPPED
438 * I/O later. If so, model it after the Stdin I/O as stdout is
439 * also incapable of async I/O on some servers.
440 */
441 stdioHandles[STDOUT_FILENO] = GetStdHandle(STD_OUTPUT_HANDLE);
442 if(!SetHandleInformation(stdioHandles[STDOUT_FILENO],
443 HANDLE_FLAG_INHERIT, FALSE)) {
444 DebugBreak();
445 exit(99);
446 }
447
448 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
449 (int)stdioHandles[STDOUT_FILENO],
450 STDOUT_FILENO)) == -1) {
451 return -1;
452 } else {
453 /*
454 * Set stdout equal to our pseudo FD
455 */
456 stdioFds[STDOUT_FILENO] = fakeFd;
457 }
458
459 stdioHandles[STDERR_FILENO] = GetStdHandle(STD_ERROR_HANDLE);
460 if(!SetHandleInformation(stdioHandles[STDERR_FILENO],
461 HANDLE_FLAG_INHERIT, FALSE)) {
462 DebugBreak();
463 exit(99);
464 }
465 if ((fakeFd = Win32NewDescriptor(FD_PIPE_SYNC,
466 (int)stdioHandles[STDERR_FILENO],
467 STDERR_FILENO)) == -1) {
468 return -1;
469 } else {
470 /*
471 * Set stderr equal to our pseudo FD
472 */
473 stdioFds[STDERR_FILENO] = fakeFd;
474 }
475
476 return 0;
477}
478
479\f
480/*
481 *--------------------------------------------------------------
482 *
483 * OS_LibShutdown --
484 *
485 * Shutdown the OS library.
486 *
487 * Results:
488 * None.
489 *
490 * Side effects:
491 * Memory freed, handles closed.
492 *
493 *--------------------------------------------------------------
494 */
495void OS_LibShutdown()
496{
497
498 if(hIoCompPort != INVALID_HANDLE_VALUE) {
499 CloseHandle(hIoCompPort);
500 hIoCompPort = INVALID_HANDLE_VALUE;
501 }
502
503 if(hStdinCompPort != INVALID_HANDLE_VALUE) {
504 CloseHandle(hStdinCompPort);
505 hStdinCompPort = INVALID_HANDLE_VALUE;
506 }
507
508 /*
509 * Shutdown the socket library.
510 */
511 WSACleanup();
512 return;
513}
514
515\f
516/*
517 *--------------------------------------------------------------
518 *
519 * Win32FreeDescriptor --
520 *
521 * Free I/O descriptor entry in fdTable.
522 *
523 * Results:
524 * Frees I/O descriptor entry in fdTable.
525 *
526 * Side effects:
527 * None.
528 *
529 *--------------------------------------------------------------
530 */
531static void Win32FreeDescriptor(int fd)
532{
533 /* Catch it if fd is a bogus value */
534 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
535 ASSERT(fdTable[fd].type != FD_UNUSED);
536
537 switch (fdTable[fd].type) {
538 case FD_FILE_SYNC:
539 case FD_FILE_ASYNC:
540 /* Free file path string */
541 ASSERT(fdTable[fd].path != NULL);
542 free(fdTable[fd].path);
543 fdTable[fd].path = NULL;
544 break;
545 default:
546 /*
547 * Break through to generic fdTable free-descriptor code
548 */
549 break;
550
551 }
552 ASSERT(fdTable[fd].path == NULL);
553 fdTable[fd].type = FD_UNUSED;
554 fdTable[fd].path = NULL;
555 fdTable[fd].Errno = NO_ERROR;
556 fdTable[fd].offsetHighPtr = fdTable[fd].offsetLowPtr = NULL;
557 if (fdTable[fd].hMapMutex != NULL) {
558 CloseHandle(fdTable[fd].hMapMutex);
559 fdTable[fd].hMapMutex = NULL;
560 }
561 return;
562}
563
564\f
565/*
566 * OS_CreateLocalIpcFd --
567 *
568 * This procedure is responsible for creating the listener pipe
569 * on Windows NT for local process communication. It will create a
570 * named pipe and return a file descriptor to it to the caller.
571 *
572 * Results:
573 * Listener pipe created. This call returns either a valid
574 * pseudo file descriptor or -1 on error.
575 *
576 * Side effects:
577 * Listener pipe and IPC address are stored in the FCGI info
578 * structure.
579 * 'errno' will set on errors (-1 is returned).
580 *
581 *----------------------------------------------------------------------
582 */
583int OS_CreateLocalIpcFd(char *bindPath)
584{
585 int retFd = -1;
586 SECURITY_ATTRIBUTES sa;
587 HANDLE hListenPipe = INVALID_HANDLE_VALUE;
588 char *localPath;
589 SOCKET listenSock;
590 int bpLen;
591 int servLen;
592 struct sockaddr_in sockAddr;
593 char host[1024];
594 short port;
595 int tcp = FALSE;
596 int flag = 1;
597 char *tp;
598
599 strcpy(host, bindPath);
600 if((tp = strchr(host, ':')) != 0) {
601 *tp++ = 0;
602 if((port = atoi(tp)) == 0) {
603 *--tp = ':';
604 } else {
605 tcp = TRUE;
606 }
607 }
608 if(tcp && (*host && strcmp(host, "localhost") != 0)) {
609 fprintf(stderr, "To start a service on a TCP port can not "
610 "specify a host name.\n"
611 "You should either use \"localhost:<port>\" or "
612 " just use \":<port>.\"\n");
613 exit(1);
614 }
615
616 if(tcp) {
617 listenSock = socket(AF_INET, SOCK_STREAM, 0);
618 if(listenSock == SOCKET_ERROR) {
619 return -1;
620 }
621 /*
622 * Bind the listening socket.
623 */
624 memset((char *) &sockAddr, 0, sizeof(sockAddr));
625 sockAddr.sin_family = AF_INET;
626 sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
627 sockAddr.sin_port = htons(port);
628 servLen = sizeof(sockAddr);
629
630 if(bind(listenSock, (struct sockaddr *) &sockAddr, servLen) < 0
631 || listen(listenSock, 5) < 0) {
632 perror("bind/listen");
633 exit(errno);
634 }
635
636 retFd = Win32NewDescriptor(FD_SOCKET_SYNC, (int)listenSock, -1);
637 return retFd;
638 }
639
640
641 /*
642 * Initialize the SECURITY_ATTRIUBTES structure.
643 */
644 sa.nLength = sizeof(sa);
645 sa.lpSecurityDescriptor = NULL;
646 sa.bInheritHandle = TRUE; /* This will be inherited by the
647 * FastCGI process
648 */
649
650 /*
651 * Create a mutex to be used to synchronize access to accepting a
652 * connection on a named pipe. We don't want to own this at creation
653 * time but would rather let the first process that goes for it
654 * be able to acquire it.
655 */
656 hPipeMutex = CreateMutex(NULL, FALSE, NULL);
657 if(hPipeMutex == NULL) {
658 return -1;
659 }
660 if(!SetHandleInformation(hPipeMutex, HANDLE_FLAG_INHERIT,
661 TRUE)) {
662 return -1;
663 }
664 sprintf(pipeMutexEnv, "%s=%d", MUTEX_VARNAME, (int)hPipeMutex);
665 putenv(pipeMutexEnv);
666
667 /*
668 * Create a unique name to be used for the socket bind path.
669 * Make sure that this name is unique and that there's no process
670 * bound to it.
671 *
672 * Named Pipe Pathname: \\.\pipe\FastCGI\OM_WS.pid.N
673 * Where: N is the pipe instance on the machine.
674 *
675 */
676 bpLen = (int)strlen(bindPathPrefix);
677 bpLen += strlen(bindPath);
678 localPath = malloc(bpLen+2);
679 strcpy(localPath, bindPathPrefix);
680 strcat(localPath, bindPath);
681
682 /*
683 * Create and setup the named pipe to be used by the fcgi server.
684 */
685 hListenPipe = CreateNamedPipe(localPath, /* name of pipe */
686 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
687 PIPE_TYPE_BYTE | PIPE_WAIT |
688 PIPE_READMODE_BYTE, /* pipe IO type */
689 PIPE_UNLIMITED_INSTANCES, /* number of instances */
690 4096, /* size of outbuf (0 == allocate as necessary) */
691 4096, /* size of inbuf */
692 0, /*1000,*/ /* default time-out value */
693 &sa); /* security attributes */
694 free(localPath);
695 /*
696 * Can't create an instance of the pipe, fail...
697 */
698 if (hListenPipe == INVALID_HANDLE_VALUE) {
699 return -1;
700 }
701
702 retFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hListenPipe, -1);
703 return retFd;
704}
705
706\f
707/*
708 *----------------------------------------------------------------------
709 *
710 * OS_FcgiConnect --
711 *
712 * Create the pipe pathname connect to the remote application if
713 * possible.
714 *
715 * Results:
716 * -1 if fail or a valid handle if connection succeeds.
717 *
718 * Side effects:
719 * Remote connection established.
720 *
721 *----------------------------------------------------------------------
722 */
723int OS_FcgiConnect(char *bindPath)
724{
725 char *pipePath = NULL;
726 HANDLE hPipe;
727 int pseudoFd, err;
728
729 struct sockaddr_in sockAddr;
730 int servLen, resultSock;
731 int connectStatus;
732 char *tp;
733 char host[1024];
734 short port;
735 int tcp = FALSE;
736
737 strcpy(host, bindPath);
738 if((tp = strchr(host, ':')) != 0) {
739 *tp++ = 0;
740 if((port = atoi(tp)) == 0) {
741 *--tp = ':';
742 } else {
743 tcp = TRUE;
744 }
745 }
746 if(tcp == TRUE) {
747 struct hostent *hp;
748 if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
749 fprintf(stderr, "Unknown host: %s\n", bindPath);
750 exit(1000);
751 }
752 sockAddr.sin_family = AF_INET;
753 memcpy(&sockAddr.sin_addr, hp->h_addr, hp->h_length);
754 sockAddr.sin_port = htons(port);
755 servLen = sizeof(sockAddr);
756 resultSock = socket(AF_INET, SOCK_STREAM, 0);
757
758 assert(resultSock >= 0);
759 connectStatus = connect(resultSock, (struct sockaddr *)
760 &sockAddr, servLen);
761 if(connectStatus < 0) {
762 /*
763 * Most likely (errno == ENOENT || errno == ECONNREFUSED)
764 * and no FCGI application server is running.
765 */
766 closesocket(resultSock);
767 return -1;
768 }
769 pseudoFd = Win32NewDescriptor(FD_SOCKET_SYNC, resultSock, -1);
770 if(pseudoFd == -1) {
771 closesocket(resultSock);
772 }
773 return pseudoFd;
774 }
775
776 /*
777 * Not a TCP connection, create and connect to a named pipe.
778 */
779 pipePath = malloc((size_t)(strlen(bindPathPrefix) + strlen(bindPath) + 2));
780 if(pipePath == NULL) {
781 return -1;
782 }
783 strcpy(pipePath, bindPathPrefix);
784 strcat(pipePath, bindPath);
785
786 hPipe = CreateFile (pipePath,
787 /* Generic access, read/write. */
788 GENERIC_WRITE | GENERIC_READ,
789 /* Share both read and write. */
790 FILE_SHARE_READ | FILE_SHARE_WRITE ,
791 NULL, /* No security.*/
792 OPEN_EXISTING, /* Fail if not existing. */
793 FILE_FLAG_OVERLAPPED, /* Use overlap. */
794 NULL); /* No template. */
795
796 free(pipePath);
797 if(hPipe == INVALID_HANDLE_VALUE) {
798 return -1;
799 }
800
801 if ((pseudoFd = Win32NewDescriptor(FD_PIPE_ASYNC, (int)hPipe, -1)) == -1) {
802 CloseHandle(hPipe);
803 return -1;
804 } else {
805 /*
806 * Set stdin equal to our pseudo FD and create the I/O completion
807 * port to be used for async I/O.
808 */
809 if (!CreateIoCompletionPort(hPipe, hIoCompPort, pseudoFd, 1)) {
810 err = GetLastError();
811 Win32FreeDescriptor(pseudoFd);
812 CloseHandle(hPipe);
813 return -1;
814 }
815 }
816 return pseudoFd;
817}
818
819\f
820/*
821 *--------------------------------------------------------------
822 *
823 * OS_Read --
824 *
825 * Pass through to the appropriate NT read function.
826 *
827 * Results:
828 * Returns number of byes read. Mimics unix read:.
829 * n bytes read, 0 or -1 failure: errno contains actual error
830 *
831 * Side effects:
832 * None.
833 *
834 *--------------------------------------------------------------
835 */
836int OS_Read(int fd, char * buf, size_t len)
837{
838 DWORD bytesRead;
839 int ret;
840
841 /*
842 * Catch any bogus fd values
843 */
844 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
845
846 switch (fdTable[fd].type) {
847 case FD_FILE_SYNC:
848 case FD_FILE_ASYNC:
849 case FD_PIPE_SYNC:
850 case FD_PIPE_ASYNC:
851 bytesRead = fd;
852 /*
853 * ReadFile returns: TRUE success, FALSE failure
854 */
855 if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
856 NULL)) {
857 fdTable[fd].Errno = GetLastError();
858 return -1;
859 }
860 return bytesRead;
861
862 case FD_SOCKET_SYNC:
863 case FD_SOCKET_ASYNC:
864 /* winsock recv returns n bytes recv'ed, SOCKET_ERROR failure */
865 /*
866 * XXX: Test this with ReadFile. If it works, remove this code
867 * to simplify the routine.
868 */
869 if ((ret = recv(fdTable[fd].fid.sock, buf, len, 0)) ==
870 SOCKET_ERROR) {
871 fdTable[fd].Errno = WSAGetLastError();
872 return -1;
873 }
874 return ret;
875 default:
876 return -1;
877 }
878}
879\f
880/*
881 *--------------------------------------------------------------
882 *
883 * OS_Write --
884 *
885 * Perform a synchronous OS write.
886 *
887 * Results:
888 * Returns number of bytes written. Mimics unix write:
889 * n bytes written, 0 or -1 failure (??? couldn't find man page).
890 *
891 * Side effects:
892 * none.
893 *
894 *--------------------------------------------------------------
895 */
896int OS_Write(int fd, char * buf, size_t len)
897{
898 DWORD bytesWritten;
899 int ret;
900
901 /*
902 * Catch any bogus fd values
903 */
904 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
905 ASSERT((fdTable[fd].type > FD_UNUSED) &&
906 (fdTable[fd].type <= FD_PIPE_ASYNC));
907
908 switch (fdTable[fd].type) {
909 case FD_FILE_SYNC:
910 case FD_FILE_ASYNC:
911 case FD_PIPE_SYNC:
912 case FD_PIPE_ASYNC:
913 bytesWritten = fd;
914 /*
915 * WriteFile returns: TRUE success, FALSE failure
916 */
917 if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len,
918 &bytesWritten, NULL)) {
919 fdTable[fd].Errno = GetLastError();
920 return -1;
921 }
922 return bytesWritten;
923 case FD_SOCKET_SYNC:
924 case FD_SOCKET_ASYNC:
925 /* winsock send returns n bytes written, SOCKET_ERROR failure */
926 /*
927 * XXX: Test this with WriteFile. If it works, remove this code
928 * to simplify the routine.
929 */
930 if ((ret = send(fdTable[fd].fid.sock, buf, len, 0)) ==
931 SOCKET_ERROR) {
932 fdTable[fd].Errno = WSAGetLastError();
933 return -1;
934 }
935 return ret;
936 default:
937 return -1;
938 }
939}
940
941\f
942/*
943 *----------------------------------------------------------------------
944 *
945 * OS_SpawnChild --
946 *
947 * Spawns a new server listener process, and stores the information
948 * relating to the child in the supplied record. A wait handler is
949 * registered on the child's completion. This involves creating
950 * a process on NT and preparing a command line with the required
951 * state (currently a -childproc flag and the server socket to use
952 * for accepting connections).
953 *
954 * Results:
955 * 0 if success, -1 if error.
956 *
957 * Side effects:
958 * Child process spawned.
959 *
960 *----------------------------------------------------------------------
961 */
962int OS_SpawnChild(char *execPath, int listenFd)
963{
964 STARTUPINFO StartupInfo;
965 PROCESS_INFORMATION pInfo;
966 BOOL success;
967
968 memset((void *)&StartupInfo, 0, sizeof(STARTUPINFO));
969 StartupInfo.cb = sizeof (STARTUPINFO);
970 StartupInfo.lpReserved = NULL;
971 StartupInfo.lpReserved2 = NULL;
972 StartupInfo.cbReserved2 = 0;
973 StartupInfo.lpDesktop = NULL;
974
975 /*
976 * FastCGI on NT will set the listener pipe HANDLE in the stdin of
977 * the new process. The fact that there is a stdin and NULL handles
978 * for stdout and stderr tells the FastCGI process that this is a
979 * FastCGI process and not a CGI process.
980 */
981 StartupInfo.dwFlags = STARTF_USESTDHANDLES;
982 /*
983 * XXX: Do I have to dup the handle before spawning the process or is
984 * it sufficient to use the handle as it's reference counted
985 * by NT anyway?
986 */
987 StartupInfo.hStdInput = fdTable[listenFd].fid.fileHandle;
988 StartupInfo.hStdOutput = INVALID_HANDLE_VALUE;
989 StartupInfo.hStdError = INVALID_HANDLE_VALUE;
990
991 /*
992 * Make the listener socket inheritable.
993 */
994 success = SetHandleInformation(StartupInfo.hStdInput, HANDLE_FLAG_INHERIT,
995 TRUE);
996 if(!success) {
997 exit(99);
998 }
999
1000 /*
1001 * XXX: Might want to apply some specific security attributes to the
1002 * processes.
1003 */
1004 success = CreateProcess(execPath, /* LPCSTR address of module name */
1005 NULL, /* LPCSTR address of command line */
1006 NULL, /* Process security attributes */
1007 NULL, /* Thread security attributes */
1008 TRUE, /* Inheritable Handes inherited. */
1009 0, /* DWORD creation flags */
1010 NULL, /* Use parent environment block */
1011 NULL, /* Address of current directory name */
1012 &StartupInfo, /* Address of STARTUPINFO */
1013 &pInfo); /* Address of PROCESS_INFORMATION */
1014 if(success) {
1015 return 0;
1016 } else {
1017 return -1;
1018 }
1019}
1020
1021\f
1022/*
1023 *--------------------------------------------------------------
1024 *
1025 * OS_AsyncReadStdin --
1026 *
1027 * This initiates an asynchronous read on the standard
1028 * input handle. This handle is not guaranteed to be
1029 * capable of performing asynchronous I/O so we send a
1030 * message to the StdinThread to do the synchronous read.
1031 *
1032 * Results:
1033 * -1 if error, 0 otherwise.
1034 *
1035 * Side effects:
1036 * Asynchronous message is queued to the StdinThread and an
1037 * overlapped structure is allocated/initialized.
1038 *
1039 *--------------------------------------------------------------
1040 */
1041int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr,
1042 ClientData clientData)
1043{
1044 POVERLAPPED_REQUEST pOv;
1045
1046 ASSERT(fdTable[STDIN_FILENO].type != FD_UNUSED);
1047
1048 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1049 ASSERT(pOv);
1050 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1051 pOv->clientData1 = (ClientData)buf;
1052 pOv->instance = fdTable[STDIN_FILENO].instance;
1053 pOv->procPtr = procPtr;
1054 pOv->clientData = clientData;
1055
1056 PostQueuedCompletionStatus(hStdinCompPort, len, STDIN_FILENO,
1057 (LPOVERLAPPED)pOv);
1058 return 0;
1059}
1060
1061\f
1062/*
1063 *--------------------------------------------------------------
1064 *
1065 * OS_AsyncRead --
1066 *
1067 * This initiates an asynchronous read on the file
1068 * handle which may be a socket or named pipe.
1069 *
1070 * We also must save the ProcPtr and ClientData, so later
1071 * when the io completes, we know who to call.
1072 *
1073 * We don't look at any results here (the ReadFile may
1074 * return data if it is cached) but do all completion
1075 * processing in OS_Select when we get the io completion
1076 * port done notifications. Then we call the callback.
1077 *
1078 * Results:
1079 * -1 if error, 0 otherwise.
1080 *
1081 * Side effects:
1082 * Asynchronous I/O operation is queued for completion.
1083 *
1084 *--------------------------------------------------------------
1085 */
1086int OS_AsyncRead(int fd, int offset, void *buf, int len,
1087 OS_AsyncProc procPtr, ClientData clientData)
1088{
1089 DWORD bytesRead;
1090 POVERLAPPED_REQUEST pOv;
1091
1092 /*
1093 * Catch any bogus fd values
1094 */
1095 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1096 /*
1097 * Confirm that this is an async fd
1098 */
1099 ASSERT(fdTable[fd].type != FD_UNUSED);
1100 ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1101 ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1102 ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1103
1104 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1105 ASSERT(pOv);
1106 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1107 /*
1108 * Only file offsets should be non-zero, but make sure.
1109 */
1110 if (fdTable[fd].type == FD_FILE_ASYNC)
1111 if (fdTable[fd].offset >= 0)
1112 pOv->overlapped.Offset = fdTable[fd].offset;
1113 else
1114 pOv->overlapped.Offset = offset;
1115 pOv->instance = fdTable[fd].instance;
1116 pOv->procPtr = procPtr;
1117 pOv->clientData = clientData;
1118 bytesRead = fd;
1119 /*
1120 * ReadFile returns: TRUE success, FALSE failure
1121 */
1122 if (!ReadFile(fdTable[fd].fid.fileHandle, buf, len, &bytesRead,
1123 (LPOVERLAPPED)pOv)) {
1124 fdTable[fd].Errno = GetLastError();
1125 if(fdTable[fd].Errno == ERROR_NO_DATA ||
1126 fdTable[fd].Errno == ERROR_PIPE_NOT_CONNECTED) {
1127 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1128 return 0;
1129 }
1130 if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1131 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1132 return -1;
1133 }
1134 fdTable[fd].Errno = 0;
1135 }
1136 return 0;
1137}
1138\f
1139/*
1140 *--------------------------------------------------------------
1141 *
1142 * OS_AsyncWrite --
1143 *
1144 * This initiates an asynchronous write on the "fake" file
1145 * descriptor (which may be a file, socket, or named pipe).
1146 * We also must save the ProcPtr and ClientData, so later
1147 * when the io completes, we know who to call.
1148 *
1149 * We don't look at any results here (the WriteFile generally
1150 * completes immediately) but do all completion processing
1151 * in OS_DoIo when we get the io completion port done
1152 * notifications. Then we call the callback.
1153 *
1154 * Results:
1155 * -1 if error, 0 otherwise.
1156 *
1157 * Side effects:
1158 * Asynchronous I/O operation is queued for completion.
1159 *
1160 *--------------------------------------------------------------
1161 */
1162int OS_AsyncWrite(int fd, int offset, void *buf, int len,
1163 OS_AsyncProc procPtr, ClientData clientData)
1164{
1165 DWORD bytesWritten;
1166 POVERLAPPED_REQUEST pOv;
1167
1168 /*
1169 * Catch any bogus fd values
1170 */
1171 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1172 /*
1173 * Confirm that this is an async fd
1174 */
1175 ASSERT(fdTable[fd].type != FD_UNUSED);
1176 ASSERT(fdTable[fd].type != FD_FILE_SYNC);
1177 ASSERT(fdTable[fd].type != FD_PIPE_SYNC);
1178 ASSERT(fdTable[fd].type != FD_SOCKET_SYNC);
1179
1180 pOv = (POVERLAPPED_REQUEST)malloc(sizeof(struct OVERLAPPED_REQUEST));
1181 ASSERT(pOv);
1182 memset((void *)pOv, 0, sizeof(struct OVERLAPPED_REQUEST));
1183 /*
1184 * Only file offsets should be non-zero, but make sure.
1185 */
1186 if (fdTable[fd].type == FD_FILE_ASYNC)
1187 /*
1188 * Only file opened via OS_AsyncWrite with
1189 * O_APPEND will have an offset != -1.
1190 */
1191 if (fdTable[fd].offset >= 0)
1192 /*
1193 * If the descriptor has a memory mapped file
1194 * handle, take the offsets from there.
1195 */
1196 if (fdTable[fd].hMapMutex != NULL) {
1197 /*
1198 * Wait infinitely; this *should* not cause problems.
1199 */
1200 WaitForSingleObject(fdTable[fd].hMapMutex, INFINITE);
1201
1202 /*
1203 * Retrieve the shared offset values.
1204 */
1205 pOv->overlapped.OffsetHigh = *(fdTable[fd].offsetHighPtr);
1206 pOv->overlapped.Offset = *(fdTable[fd].offsetLowPtr);
1207
1208 /*
1209 * Update the shared offset values for the next write
1210 */
1211 *(fdTable[fd].offsetHighPtr) += 0; /* XXX How do I handle overflow */
1212 *(fdTable[fd].offsetLowPtr) += len;
1213
1214 ReleaseMutex(fdTable[fd].hMapMutex);
1215 } else
1216 pOv->overlapped.Offset = fdTable[fd].offset;
1217 else
1218 pOv->overlapped.Offset = offset;
1219 pOv->instance = fdTable[fd].instance;
1220 pOv->procPtr = procPtr;
1221 pOv->clientData = clientData;
1222 bytesWritten = fd;
1223 /*
1224 * WriteFile returns: TRUE success, FALSE failure
1225 */
1226 if (!WriteFile(fdTable[fd].fid.fileHandle, buf, len, &bytesWritten,
1227 (LPOVERLAPPED)pOv)) {
1228 fdTable[fd].Errno = GetLastError();
1229 if(fdTable[fd].Errno != ERROR_IO_PENDING) {
1230 PostQueuedCompletionStatus(hIoCompPort, 0, fd, (LPOVERLAPPED)pOv);
1231 return -1;
1232 }
1233 fdTable[fd].Errno = 0;
1234 }
1235 if (fdTable[fd].offset >= 0)
1236 fdTable[fd].offset += len;
1237 return 0;
1238}
1239
1240\f
1241/*
1242 *--------------------------------------------------------------
1243 *
1244 * OS_Close --
1245 *
1246 * Closes the descriptor with routine appropriate for
1247 * descriptor's type.
1248 *
1249 * Results:
1250 * Socket or file is closed. Return values mimic Unix close:
1251 * 0 success, -1 failure
1252 *
1253 * Side effects:
1254 * Entry in fdTable is marked as free.
1255 *
1256 *--------------------------------------------------------------
1257 */
1258int OS_Close(int fd)
1259{
1260 int ret = 0;
1261
1262 /*
1263 * Catch it if fd is a bogus value
1264 */
1265 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1266 ASSERT(fdTable[fd].type != FD_UNUSED);
1267
1268 switch (fdTable[fd].type) {
1269 case FD_PIPE_SYNC:
1270 case FD_PIPE_ASYNC:
1271 case FD_FILE_SYNC:
1272 case FD_FILE_ASYNC:
1273 /*
1274 * CloseHandle returns: TRUE success, 0 failure
1275 */
1276 if (CloseHandle(fdTable[fd].fid.fileHandle) == FALSE)
1277 ret = -1;
1278 break;
1279 case FD_SOCKET_SYNC:
1280 case FD_SOCKET_ASYNC:
1281 /*
1282 * Closing a socket that has an async read outstanding causes a
1283 * tcp reset and possible data loss. The shutdown call seems to
1284 * prevent this.
1285 */
1286 shutdown(fdTable[fd].fid.sock, 2);
1287 /*
1288 * closesocket returns: 0 success, SOCKET_ERROR failure
1289 */
1290 if (closesocket(fdTable[fd].fid.sock) == SOCKET_ERROR)
1291 ret = -1;
1292 break;
1293 default:
1294 return -1; /* fake failure */
1295 }
1296
1297 Win32FreeDescriptor(fd);
1298 return ret;
1299}
1300\f
1301/*
1302 *--------------------------------------------------------------
1303 *
1304 * OS_CloseRead --
1305 *
1306 * Cancel outstanding asynchronous reads and prevent subsequent
1307 * reads from completing.
1308 *
1309 * Results:
1310 * Socket or file is shutdown. Return values mimic Unix shutdown:
1311 * 0 success, -1 failure
1312 *
1313 *--------------------------------------------------------------
1314 */
1315int OS_CloseRead(int fd)
1316{
1317 int ret = 0;
1318
1319 /*
1320 * Catch it if fd is a bogus value
1321 */
1322 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1323 ASSERT(fdTable[fd].type == FD_SOCKET_ASYNC
1324 || fdTable[fd].type == FD_SOCKET_SYNC);
1325
1326 if (shutdown(fdTable[fd].fid.sock,0) == SOCKET_ERROR)
1327 ret = -1;
1328 return ret;
1329}
1330\f
1331/*
1332 *--------------------------------------------------------------
1333 *
1334 * OS_DoIo --
1335 *
1336 * This function was formerly OS_Select. It's purpose is
1337 * to pull I/O completion events off the queue and dispatch
1338 * them to the appropriate place.
1339 *
1340 * Results:
1341 * Returns 0.
1342 *
1343 * Side effects:
1344 * Handlers are called.
1345 *
1346 *--------------------------------------------------------------
1347 */
1348int OS_DoIo(struct timeval *tmo)
1349{
1350 int fd;
1351 int bytes;
1352 POVERLAPPED_REQUEST pOv;
1353 struct timeb tb;
1354 int ms;
1355 int ms_last;
1356 int err;
1357
1358 /* XXX
1359 * We can loop in here, but not too long, as wait handlers
1360 * must run.
1361 * For cgi stdin, apparently select returns when io completion
1362 * ports don't, so don't wait the full timeout.
1363 */
1364 if(tmo)
1365 ms = (tmo->tv_sec*1000 + tmo->tv_usec/1000) / 2;
1366 else
1367 ms = 1000;
1368 ftime(&tb);
1369 ms_last = tb.time*1000 + tb.millitm;
1370 while (ms >= 0) {
1371 if(tmo && (ms = tmo->tv_sec*1000 + tmo->tv_usec/1000)> 100)
1372 ms = 100;
1373 if (!GetQueuedCompletionStatus(hIoCompPort, &bytes, &fd,
1374 (LPOVERLAPPED *)&pOv, ms) && !pOv) {
1375 err = WSAGetLastError();
1376 return 0; /* timeout */
1377 }
1378
1379 ASSERT((fd >= 0) && (fd < WIN32_OPEN_MAX));
1380 /* call callback if descriptor still valid */
1381 ASSERT(pOv);
1382 if(pOv->instance == fdTable[fd].instance)
1383 (*pOv->procPtr)(pOv->clientData, bytes);
1384 free(pOv);
1385
1386 ftime(&tb);
1387 ms -= (tb.time*1000 + tb.millitm - ms_last);
1388 ms_last = tb.time*1000 + tb.millitm;
1389 }
1390 return 0;
1391}
1392
1393\f
1394/*
1395 *----------------------------------------------------------------------
1396 *
1397 * OS_FcgiIpcAccept --
1398 *
1399 * Accepts a new FastCGI connection. This routine knows whether
1400 * we're dealing with TCP based sockets or NT Named Pipes for IPC.
1401 *
1402 * Results:
1403 * -1 if the operation fails, otherwise this is a valid IPC fd.
1404 *
1405 * Side effects:
1406 * New IPC connection is accepted.
1407 *
1408 *----------------------------------------------------------------------
1409 */
1410int OS_FcgiIpcAccept(char *serverHostList)
1411{
1412 struct sockaddr_in sa;
1413 int isNewConnection;
1414 int ipcFd = -1;
1415 BOOL pConnected;
1416 HANDLE hDup;
1417 SOCKET hSock;
1418 int clilen = sizeof(sa);
1419 DWORD waitForStatus;
1420
1421 switch(listenType) {
1422
1423 case FD_PIPE_SYNC:
1424 waitForStatus = WaitForSingleObject(hPipeMutex,INFINITE);
1425 switch(waitForStatus) {
1426 case WAIT_OBJECT_0:
1427 case WAIT_ABANDONED:
1428 break;
1429
1430 case WAIT_FAILED:
1431 default:
1432 return -1;
1433 }
1434
1435 /*
1436 * We have the mutex, go for the connection.
1437 */
1438 pConnected = ConnectNamedPipe(hListen, NULL) ?
1439 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
1440
1441 ReleaseMutex(hPipeMutex);
1442 if(pConnected) {
1443 /*
1444 * Success...
1445 */
1446 if (!DuplicateHandle(GetCurrentProcess(), hListen,
1447 GetCurrentProcess(), &hDup, 0,
1448 TRUE, /* allow inheritance */
1449 DUPLICATE_SAME_ACCESS)) {
1450 return -1;
1451 }
1452 ipcFd = Win32NewDescriptor(FD_PIPE_SYNC, (int)hDup, -1);
1453 if(ipcFd == -1) {
1454 DisconnectNamedPipe(hListen);
1455 CloseHandle(hDup);
1456 }
1457 return ipcFd;
1458 } else {
1459 return -1;
1460 }
1461 break;
1462
1463 case FD_SOCKET_SYNC:
1464 hSock = accept((int)hListen, (struct sockaddr *) &sa, &clilen);
1465 if(hSock == -1) {
1466 return -1;
1467 } else if (sa.sin_family != AF_INET) { /* What are we? */
1468 closesocket(hSock);
1469 hSock = (SOCKET)-1;
1470 return -1;
1471 } else {
1472 char *tp1, *tp2;
1473 int match = 0;
1474 if (serverHostList == NULL)
1475 isNewConnection = TRUE;
1476 else {
1477 tp1 = (char *) malloc(strlen(serverHostList)+1);
1478 ASSERT(tp1 != NULL);
1479 strcpy(tp1, serverHostList);
1480 while(tp1) {
1481 if ((tp2 = strchr(tp1, ',')) != NULL)
1482 *tp2++ = 0;
1483
1484 if (inet_addr(tp1) == sa.sin_addr.s_addr) {
1485 match = 1;
1486 break;
1487 }
1488 tp1 = tp2;
1489 }
1490 free(tp1);
1491 if (match)
1492 isNewConnection = TRUE;
1493 else {
1494 closesocket(hSock);
1495 hSock = (SOCKET)-1;
1496 return -1;
1497 }
1498 }
1499 }
1500
1501 ipcFd = Win32NewDescriptor(FD_SOCKET_SYNC, hSock, -1);
1502 if(ipcFd == -1) {
1503 closesocket(hSock);
1504 }
1505 return ipcFd;
1506 break;
1507
1508 case FD_UNUSED:
1509 default:
1510 exit(101);
1511 break;
1512
1513 }
1514}
1515\f
1516/*
1517 *----------------------------------------------------------------------
1518 *
1519 * OS_IpcClose
1520 *
1521 * OS IPC routine to close an IPC connection.
1522 *
1523 * Results:
1524 *
1525 *
1526 * Side effects:
1527 * IPC connection is closed.
1528 *
1529 *----------------------------------------------------------------------
1530 */
1531int OS_IpcClose(int ipcFd)
1532{
1533
1534 /*
1535 * Catch it if fd is a bogus value
1536 */
1537 ASSERT((ipcFd >= 0) && (ipcFd < WIN32_OPEN_MAX));
1538 ASSERT(fdTable[ipcFd].type != FD_UNUSED);
1539
1540 switch(listenType) {
1541
1542 case FD_PIPE_SYNC:
1543 /*
1544 * Make sure that the client (ie. a Web Server in this case) has
1545 * read all data from the pipe before we disconnect.
1546 */
1547 if(!FlushFileBuffers(fdTable[ipcFd].fid.fileHandle))
1548 return -1;
1549 if(DisconnectNamedPipe(fdTable[ipcFd].fid.fileHandle)) {
1550 OS_Close(ipcFd);
1551 return 0;
1552 } else {
1553 return -1;
1554 }
1555 break;
1556
1557 case FD_SOCKET_SYNC:
1558 OS_Close(ipcFd);
1559 break;
1560
1561 case FD_UNUSED:
1562 default:
1563 exit(106);
1564 break;
1565 }
1566
1567}
1568
1569\f
1570/*
1571 *----------------------------------------------------------------------
1572 *
1573 * OS_IsFcgi --
1574 *
1575 * Determines whether this process is a FastCGI process or not.
1576 *
1577 * Results:
1578 * Returns 1 if FastCGI, 0 if not.
1579 *
1580 * Side effects:
1581 * None.
1582 *
1583 *----------------------------------------------------------------------
1584 */
1585int OS_IsFcgi()
1586{
1587 if(listenType == FD_UNUSED) {
1588 isCGI = TRUE;
1589 return 0;
1590 } else {
1591 isCGI = FALSE;
1592 return 1;
1593 }
1594}
1595
1596\f
1597/*
1598 *----------------------------------------------------------------------
1599 *
1600 * OS_SetFlags --
1601 *
1602 * Sets selected flag bits in an open file descriptor. Currently
1603 * this is only to put a SOCKET into non-blocking mode.
1604 *
1605 *----------------------------------------------------------------------
1606 */
1607void OS_SetFlags(int fd, int flags)
1608{
1609 long int pLong = 1L;
1610 int err;
1611
1612 if(fdTable[fd].type == FD_SOCKET_SYNC && flags == O_NONBLOCK) {
1613 if (ioctlsocket(fdTable[fd].fid.sock, FIONBIO, &pLong) ==
1614 SOCKET_ERROR) {
1615 exit(WSAGetLastError());
1616 }
1617 if (!CreateIoCompletionPort((HANDLE)fdTable[fd].fid.sock,
1618 hIoCompPort, fd, 1)) {
1619 err = GetLastError();
1620 exit(err);
1621 }
1622
1623 fdTable[fd].type = FD_SOCKET_ASYNC;
1624 }
1625 return;
1626}
1627