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