28ccded92f5c9db7883c643aa69b63611d9ddcc8
[catagits/fcgi2.git] / libfcgi / os_unix.c
1 /* 
2  * os_unix.c --
3  *
4  *      Description of file.
5  *
6  *
7  *  Copyright (c) 1995 Open Market, Inc.
8  *  All rights reserved.
9  *
10  *  This file contains proprietary and confidential information and
11  *  remains the unpublished property of Open Market, Inc. Use, 
12  *  disclosure, or reproduction is prohibited except as permitted by 
13  *  express written license agreement with Open Market, Inc. 
14  *
15  *  Bill Snapper
16  *  snapper@openmarket.com
17  */
18
19 #ifndef lint
20 static const char rcsid[] = "$Id: os_unix.c,v 1.3 1998/12/04 02:57:35 roberts Exp $";
21 #endif /* not lint */
22
23 #include "fcgimisc.h"
24 #include "fcgiapp.h"
25 #include "fcgiappmisc.h"
26 #include "fastcgi.h"
27
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <memory.h>     /* for memchr() */
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <math.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h> /* for getpeername */
41 #endif
42 #include <sys/un.h>
43 #include <fcntl.h>      /* for fcntl */
44 #ifdef HAVE_NETDB_H
45 #include <netdb.h>
46 #endif
47 #include <sys/time.h>
48
49 #include <sys/types.h>
50 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
53 #include <arpa/inet.h>
54
55 #include "fcgios.h"
56
57 #ifndef _CLIENTDATA
58 #   if defined(__STDC__) || defined(__cplusplus)
59     typedef void *ClientData;
60 #   else
61     typedef int *ClientData;
62 #   endif /* __STDC__ */
63 #define _CLIENTDATA
64 #endif
65
66 /*
67  * This structure holds an entry for each oustanding async I/O operation.
68  */
69 typedef struct {
70     OS_AsyncProc procPtr;           /* callout completion procedure */
71     ClientData clientData;          /* caller private data */
72     int fd;
73     int len;
74     int offset;
75     void *buf;
76     int inUse;
77 } AioInfo;
78
79 /*
80  * Entries in the async I/O table are allocated 2 per file descriptor.
81  *
82  * Read Entry Index  = fd * 2
83  * Write Entry Index = (fd * 2) + 1
84  */
85 #define AIO_RD_IX(fd) (fd * 2)
86 #define AIO_WR_IX(fd) ((fd * 2) + 1)
87
88 static int asyncIoTableSize = 16;
89 static AioInfo *asyncIoTable = NULL;
90 #define STDIN_FILENO  0
91 #define STDOUT_FILENO 1
92 #define STDERR_FILENO 2
93
94 #ifndef FALSE
95 #define FALSE 0
96 #endif
97
98 #ifndef TRUE
99 #define TRUE 1
100 #endif
101
102 static int isFastCGI = FALSE;
103 static int libInitialized = FALSE;
104
105 static fd_set readFdSet;
106 static fd_set writeFdSet;
107
108 static fd_set readFdSetPost;
109 static int numRdPosted = 0;
110 static fd_set writeFdSetPost;
111 static int numWrPosted = 0;
112 static int volatile maxFd = -1;
113
114 \f
115 /*
116  *--------------------------------------------------------------
117  *
118  * OS_LibInit --
119  *
120  *      Set up the OS library for use.
121  *
122  *      NOTE: This function is really only needed for application
123  *            asynchronous I/O.  It will most likely change in the
124  *            future to setup the multi-threaded environment.
125  *
126  * Results:
127  *      Returns 0 if success, -1 if not.
128  *
129  * Side effects:
130  *      Async I/O table allocated and initialized.
131  *
132  *--------------------------------------------------------------
133  */
134 int OS_LibInit(int stdioFds[3])
135 {
136     if(libInitialized)
137         return 0;
138     
139     asyncIoTable = malloc(asyncIoTableSize * sizeof(AioInfo));
140     if(asyncIoTable == NULL) {
141         errno = ENOMEM;
142         return -1;
143     }
144     memset((char *) asyncIoTable, 0,
145            asyncIoTableSize * sizeof(AioInfo));
146
147     FD_ZERO(&readFdSet);
148     FD_ZERO(&writeFdSet);
149     FD_ZERO(&readFdSetPost);
150     FD_ZERO(&writeFdSetPost);
151     libInitialized = TRUE;
152     return 0;
153 }
154
155 \f
156 /*
157  *--------------------------------------------------------------
158  *
159  * OS_LibShutdown --
160  *
161  *      Shutdown the OS library.
162  *
163  * Results:
164  *      None.
165  *
166  * Side effects:
167  *      Memory freed, fds closed.
168  *
169  *--------------------------------------------------------------
170  */
171 void OS_LibShutdown()
172 {
173     if(!libInitialized)
174         return;
175     
176     free(asyncIoTable);
177     asyncIoTable = NULL;
178     libInitialized = FALSE;
179     return;
180 }
181
182 \f
183 /*
184  *----------------------------------------------------------------------
185  *
186  * OS_BuildSockAddrUn --
187  *
188  *      Using the pathname bindPath, fill in the sockaddr_un structure
189  *      *servAddrPtr and the length of this structure *servAddrLen.
190  *
191  *      The format of the sockaddr_un structure changed incompatibly in
192  *      4.3BSD Reno.  Digital UNIX supports both formats, other systems
193  *      support one or the other.
194  *
195  * Results:
196  *      0 for normal return, -1 for failure (bindPath too long).
197  *
198  *----------------------------------------------------------------------
199  */
200
201 static int OS_BuildSockAddrUn(char *bindPath,
202                               struct sockaddr_un *servAddrPtr,
203                               int *servAddrLen)
204 {
205     int bindPathLen = strlen(bindPath);
206
207 #ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */
208     if(bindPathLen >= sizeof(servAddrPtr->sun_path)) {
209         return -1;
210     }
211 #else                           /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */
212     if(bindPathLen > sizeof(servAddrPtr->sun_path)) {
213         return -1;
214     }
215 #endif
216     memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr));
217     servAddrPtr->sun_family = AF_UNIX;
218     memcpy(servAddrPtr->sun_path, bindPath, bindPathLen);
219 #ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */
220     *servAddrLen = sizeof(servAddrPtr->sun_len)
221             + sizeof(servAddrPtr->sun_family)
222             + bindPathLen + 1;
223     servAddrPtr->sun_len = *servAddrLen;
224 #else                           /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */
225     *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen;
226 #endif
227     return 0;
228 }
229 \f
230 union SockAddrUnion {
231     struct  sockaddr_un unixVariant;
232     struct  sockaddr_in inetVariant;
233 };
234
235 \f
236 /*
237  * OS_CreateLocalIpcFd --
238  *
239  *   This procedure is responsible for creating the listener socket
240  *   on Unix for local process communication.  It will create a
241  *   domain socket or a TCP/IP socket bound to "localhost" and return
242  *   a file descriptor to it to the caller.
243  *
244  * Results:
245  *      Listener socket created.  This call returns either a valid
246  *      file descriptor or -1 on error.
247  *
248  * Side effects:
249  *      None.
250  *
251  *----------------------------------------------------------------------
252  */
253 int OS_CreateLocalIpcFd(char *bindPath)
254 {
255     int listenSock, servLen;
256     union   SockAddrUnion sa;
257     int     tcp = FALSE;
258     char    *tp;
259     short   port;
260     char    host[MAXPATHLEN];
261
262     strcpy(host, bindPath);
263     if((tp = strchr(host, ':')) != 0) {
264         *tp++ = 0;
265         if((port = atoi(tp)) == 0) {
266             *--tp = ':';
267          } else {
268             tcp = TRUE;
269          }
270     }
271     if(tcp && (*host && strcmp(host, "localhost") != 0)) {
272         fprintf(stderr, "To start a service on a TCP port can not "
273                         "specify a host name.\n"
274                         "You should either use \"localhost:<port>\" or "
275                         " just use \":<port>.\"\n");
276         exit(1);
277     }
278
279     if(tcp) {
280         listenSock = socket(AF_INET, SOCK_STREAM, 0);
281         if(listenSock >= 0) {
282             int flag = 1;
283             if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR,
284                           (char *) &flag, sizeof(flag)) < 0) {
285                 fprintf(stderr, "Can't set SO_REUSEADDR.\n");
286                 exit(1001);
287             }
288         }
289     } else {
290         listenSock = socket(AF_UNIX, SOCK_STREAM, 0);
291     }
292     if(listenSock < 0) {
293         return -1;
294     }
295
296     /*
297      * Bind the listening socket.
298      */
299     if(tcp) {
300         memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant));
301         sa.inetVariant.sin_family = AF_INET;
302         sa.inetVariant.sin_addr.s_addr = htonl(INADDR_ANY);
303         sa.inetVariant.sin_port = htons(port);
304         servLen = sizeof(sa.inetVariant);
305     } else {
306         unlink(bindPath);
307         if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) {
308             fprintf(stderr, "Listening socket's path name is too long.\n");
309             exit(1000);
310         }
311     }
312     if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0
313        || listen(listenSock, 5) < 0) {
314         perror("bind/listen");
315         exit(errno);
316     }
317
318     return listenSock;
319 }
320
321 \f
322 /*
323  *----------------------------------------------------------------------
324  *
325  * OS_FcgiConnect --
326  *
327  *      Create the socket and connect to the remote application if
328  *      possible.
329  *
330  *      This was lifted from the cgi-fcgi application and was abstracted
331  *      out because Windows NT does not have a domain socket and must
332  *      use a named pipe which has a different API altogether.
333  *
334  * Results:
335  *      -1 if fail or a valid file descriptor if connection succeeds.
336  *
337  * Side effects:
338  *      Remote connection established.
339  *
340  *----------------------------------------------------------------------
341  */
342 int OS_FcgiConnect(char *bindPath)
343 {
344     union   SockAddrUnion sa;
345     int servLen, resultSock;
346     int connectStatus;
347     char    *tp;
348     char    host[MAXPATHLEN];
349     short   port;
350     int     tcp = FALSE;
351
352     strcpy(host, bindPath);
353     if((tp = strchr(host, ':')) != 0) {
354         *tp++ = 0;
355         if((port = atoi(tp)) == 0) {
356             *--tp = ':';
357          } else {
358             tcp = TRUE;
359          }
360     }
361     if(tcp == TRUE) {
362         struct  hostent *hp;
363         if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) {
364             fprintf(stderr, "Unknown host: %s\n", bindPath);
365             exit(1000);
366         }
367         sa.inetVariant.sin_family = AF_INET;
368         memcpy((caddr_t)&sa.inetVariant.sin_addr, hp->h_addr, hp->h_length);
369         sa.inetVariant.sin_port = htons(port);
370         servLen = sizeof(sa.inetVariant);
371         resultSock = socket(AF_INET, SOCK_STREAM, 0);
372     } else {
373         if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) {
374             fprintf(stderr, "Listening socket's path name is too long.\n");
375             exit(1000);
376         }
377         resultSock = socket(AF_UNIX, SOCK_STREAM, 0);
378     }
379
380     assert(resultSock >= 0);
381     connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant,
382                              servLen);
383     if(connectStatus >= 0) {
384         return resultSock;
385     } else {
386         /*
387          * Most likely (errno == ENOENT || errno == ECONNREFUSED)
388          * and no FCGI application server is running.
389          */
390         close(resultSock);
391         return -1;
392     }
393 }
394      
395 \f
396 /*
397  *--------------------------------------------------------------
398  *
399  * OS_Read --
400  *
401  *      Pass through to the unix read function.
402  *
403  * Results:
404  *      Returns number of byes read, 0, or -1 failure: errno
405  *      contains actual error.
406  *
407  * Side effects:
408  *      None.
409  *
410  *--------------------------------------------------------------
411  */
412 int OS_Read(int fd, char * buf, size_t len)
413 {
414     return(read(fd, buf, len));
415 }
416 \f
417 /*
418  *--------------------------------------------------------------
419  *
420  * OS_Write --
421  *
422  *      Pass through to unix write function.
423  *
424  * Results:
425  *      Returns number of byes read, 0, or -1 failure: errno
426  *      contains actual error.
427  *
428  * Side effects:
429  *      none.
430  *
431  *--------------------------------------------------------------
432  */
433 int OS_Write(int fd, char * buf, size_t len)
434 {
435     return(write(fd, buf, len));
436 }
437
438 \f
439 /*
440  *----------------------------------------------------------------------
441  *
442  * OS_SpawnChild --
443  *
444  *      Spawns a new FastCGI listener process.
445  *
446  * Results:
447  *      0 if success, -1 if error.
448  *
449  * Side effects:
450  *      Child process spawned.
451  *
452  *----------------------------------------------------------------------
453  */
454 int OS_SpawnChild(char *appPath, int listenFd)
455 {
456     int forkResult;
457
458     forkResult = fork();
459     if(forkResult < 0) {
460         exit(errno);
461     }
462
463     if(forkResult == 0) {
464         /*
465          * Close STDIN unconditionally.  It's used by the parent
466          * process for CGI communication.  The FastCGI applciation
467          * will be replacing this with the FastCGI listenFd IF
468          * STDIN_FILENO is the same as FCGI_LISTENSOCK_FILENO
469          * (which it is on Unix).  Regardless, STDIN, STDOUT, and
470          * STDERR will be closed as the FastCGI process uses a
471          * multiplexed socket in their place.
472          */
473         close(STDIN_FILENO);
474
475         /*
476          * If the listenFd is already the value of FCGI_LISTENSOCK_FILENO
477          * we're set.  If not, change it so the child knows where to
478          * get the listen socket from.
479          */
480         if(listenFd != FCGI_LISTENSOCK_FILENO) {
481             dup2(listenFd, FCGI_LISTENSOCK_FILENO);
482             close(listenFd);
483         }
484
485         close(STDOUT_FILENO);
486         close(STDERR_FILENO);
487
488         /*
489          * We're a child.  Exec the application.
490          *
491          * XXX: entire environment passes through
492          */
493         execl(appPath, appPath, NULL);
494         /*
495          * XXX: Can't do this as we've already closed STDERR!!!
496          *
497          * perror("exec");
498          */
499         exit(errno);
500     }
501     return 0;
502 }
503
504 \f
505 /*
506  *--------------------------------------------------------------
507  *
508  * OS_AsyncReadStdin --
509  *
510  *      This initiates an asynchronous read on the standard
511  *      input handle.
512  *
513  *      The abstraction is necessary because Windows NT does not
514  *      have a clean way of "select"ing a file descriptor for
515  *      I/O.
516  *
517  * Results:
518  *      -1 if error, 0 otherwise.
519  *
520  * Side effects:
521  *      Asynchronous bit is set in the readfd variable and
522  *      request is enqueued.
523  *
524  *--------------------------------------------------------------
525  */
526 int OS_AsyncReadStdin(void *buf, int len, OS_AsyncProc procPtr, 
527                       ClientData clientData)
528 {
529     int index = AIO_RD_IX(STDIN_FILENO);
530
531     ASSERT(asyncIoTable[index].inUse == 0);
532     asyncIoTable[index].procPtr = procPtr;
533     asyncIoTable[index].clientData = clientData;
534     asyncIoTable[index].fd = STDIN_FILENO;
535     asyncIoTable[index].len = len;
536     asyncIoTable[index].offset = 0;
537     asyncIoTable[index].buf = buf;
538     asyncIoTable[index].inUse = 1;
539     FD_SET(STDIN_FILENO, &readFdSet);
540     if(STDIN_FILENO > maxFd)
541         maxFd = STDIN_FILENO;
542     return 0;
543 }
544
545 static void GrowAsyncTable(void)
546 {
547     int oldTableSize = asyncIoTableSize;
548     
549     asyncIoTableSize = asyncIoTableSize * 2;
550     asyncIoTable = realloc(asyncIoTable, asyncIoTableSize * sizeof(AioInfo));
551     if(asyncIoTable == NULL) {
552         errno = ENOMEM;
553         exit(errno);
554     }
555     memset((char *) &asyncIoTable[oldTableSize], 0,
556            oldTableSize * sizeof(AioInfo));
557
558 }
559
560 \f
561 /*
562  *--------------------------------------------------------------
563  *
564  * OS_AsyncRead --
565  *
566  *      This initiates an asynchronous read on the file
567  *      handle which may be a socket or named pipe.
568  *
569  *      We also must save the ProcPtr and ClientData, so later
570  *      when the io completes, we know who to call.
571  *
572  *      We don't look at any results here (the ReadFile may
573  *      return data if it is cached) but do all completion
574  *      processing in OS_Select when we get the io completion
575  *      port done notifications.  Then we call the callback.
576  *
577  * Results:
578  *      -1 if error, 0 otherwise.
579  *
580  * Side effects:
581  *      Asynchronous I/O operation is queued for completion.
582  *
583  *--------------------------------------------------------------
584  */
585 int OS_AsyncRead(int fd, int offset, void *buf, int len,
586                  OS_AsyncProc procPtr, ClientData clientData)
587 {
588     int index = AIO_RD_IX(fd);
589     
590     ASSERT(asyncIoTable != NULL);
591
592     if(fd > maxFd)
593         maxFd = fd;
594
595     if(index >= asyncIoTableSize) {
596         GrowAsyncTable();
597     }
598
599     ASSERT(asyncIoTable[index].inUse == 0);
600     asyncIoTable[index].procPtr = procPtr;
601     asyncIoTable[index].clientData = clientData;
602     asyncIoTable[index].fd = fd;
603     asyncIoTable[index].len = len;
604     asyncIoTable[index].offset = offset;
605     asyncIoTable[index].buf = buf;
606     asyncIoTable[index].inUse = 1;
607     FD_SET(fd, &readFdSet);
608     return 0;
609 }
610 \f
611 /*
612  *--------------------------------------------------------------
613  *
614  * OS_AsyncWrite --
615  *
616  *      This initiates an asynchronous write on the "fake" file
617  *      descriptor (which may be a file, socket, or named pipe).
618  *      We also must save the ProcPtr and ClientData, so later
619  *      when the io completes, we know who to call.
620  *
621  *      We don't look at any results here (the WriteFile generally
622  *      completes immediately) but do all completion processing
623  *      in OS_DoIo when we get the io completion port done
624  *      notifications.  Then we call the callback.
625  *
626  * Results:
627  *      -1 if error, 0 otherwise.
628  *
629  * Side effects:
630  *      Asynchronous I/O operation is queued for completion.
631  *
632  *--------------------------------------------------------------
633  */
634 int OS_AsyncWrite(int fd, int offset, void *buf, int len, 
635                   OS_AsyncProc procPtr, ClientData clientData)
636 {
637     int index = AIO_WR_IX(fd);
638
639     if(fd > maxFd)
640         maxFd = fd;
641
642     if(index >= asyncIoTableSize) {
643         GrowAsyncTable();
644     }
645
646     ASSERT(asyncIoTable[index].inUse == 0);
647     asyncIoTable[index].procPtr = procPtr;
648     asyncIoTable[index].clientData = clientData;
649     asyncIoTable[index].fd = fd;
650     asyncIoTable[index].len = len;
651     asyncIoTable[index].offset = offset;
652     asyncIoTable[index].buf = buf;
653     asyncIoTable[index].inUse = 1;
654     FD_SET(fd, &writeFdSet);
655     return 0;
656 }
657 \f
658 /*
659  *--------------------------------------------------------------
660  *
661  * OS_Close --
662  *
663  *      Closes the descriptor.  This is a pass through to the
664  *      Unix close.
665  *
666  * Results:
667  *      0 for success, -1 on failure
668  *
669  * Side effects:
670  *      None.
671  *
672  *--------------------------------------------------------------
673  */
674 int OS_Close(int fd)
675 {
676     int index = AIO_RD_IX(fd);
677     
678     FD_CLR(fd, &readFdSet);
679     FD_CLR(fd, &readFdSetPost);
680     if(asyncIoTable[index].inUse != 0) {
681         asyncIoTable[index].inUse = 0;
682     }
683     
684     FD_CLR(fd, &writeFdSet);
685     FD_CLR(fd, &writeFdSetPost);
686     index = AIO_WR_IX(fd);
687     if(asyncIoTable[index].inUse != 0) {
688         asyncIoTable[index].inUse = 0;
689     }
690     if(maxFd == fd)
691         maxFd--;
692     return close(fd);
693 }
694 \f
695 /*
696  *--------------------------------------------------------------
697  *
698  * OS_CloseRead --
699  *
700  *      Cancel outstanding asynchronous reads and prevent subsequent
701  *      reads from completing.
702  *
703  * Results:
704  *      Socket or file is shutdown. Return values mimic Unix shutdown:
705  *              0 success, -1 failure
706  *
707  *--------------------------------------------------------------
708  */
709 int OS_CloseRead(int fd)
710 {
711     if(asyncIoTable[AIO_RD_IX(fd)].inUse != 0) {
712         asyncIoTable[AIO_RD_IX(fd)].inUse = 0;
713         FD_CLR(fd, &readFdSet);
714     }
715     
716     return shutdown(fd, 0);
717 }
718
719 \f
720 /*
721  *--------------------------------------------------------------
722  *
723  * OS_DoIo --
724  *
725  *      This function was formerly OS_Select.  It's purpose is
726  *      to pull I/O completion events off the queue and dispatch
727  *      them to the appropriate place.
728  *
729  * Results:
730  *      Returns 0.
731  *
732  * Side effects:
733  *      Handlers are called.
734  *
735  *--------------------------------------------------------------
736  */
737 int OS_DoIo(struct timeval *tmo)
738 {
739     int fd, len, selectStatus;
740     OS_AsyncProc procPtr;
741     ClientData clientData;
742     AioInfo *aioPtr;
743     fd_set readFdSetCpy;
744     fd_set writeFdSetCpy;
745
746     FD_ZERO(&readFdSetCpy);
747     FD_ZERO(&writeFdSetCpy);
748
749     for(fd = 0; fd <= maxFd; fd++) {
750         if(FD_ISSET(fd, &readFdSet)) {
751             FD_SET(fd, &readFdSetCpy);
752         }
753         if(FD_ISSET(fd, &writeFdSet)) {
754             FD_SET(fd, &writeFdSetCpy);
755         }
756     }
757     
758     /*
759      * If there were no completed events from a prior call, see if there's
760      * any work to do.
761      */
762     if(numRdPosted == 0 && numWrPosted == 0) {
763         selectStatus = select((maxFd+1), &readFdSetCpy, &writeFdSetCpy,
764                               NULL, tmo);
765         if(selectStatus < 0) {
766             exit(errno);
767         }
768
769         for(fd = 0; fd <= maxFd; fd++) {
770             /*
771              * Build up a list of completed events.  We'll work off of
772              * this list as opposed to looping through the read and write
773              * fd sets since they can be affected by a callbacl routine.
774              */
775             if(FD_ISSET(fd, &readFdSetCpy)) {
776                 numRdPosted++;
777                 FD_SET(fd, &readFdSetPost);
778                 FD_CLR(fd, &readFdSet);
779             }
780
781             if(FD_ISSET(fd, &writeFdSetCpy)) {
782                 numWrPosted++;
783                 FD_SET(fd, &writeFdSetPost);
784                 FD_CLR(fd, &writeFdSet);
785             }
786         }
787     }
788
789     if(numRdPosted == 0 && numWrPosted == 0)
790         return 0;
791             
792     for(fd = 0; fd <= maxFd; fd++) {
793         /*
794          * Do reads and dispatch callback.
795          */
796         if(FD_ISSET(fd, &readFdSetPost) 
797            && asyncIoTable[AIO_RD_IX(fd)].inUse) {
798
799             numRdPosted--;
800             FD_CLR(fd, &readFdSetPost);
801             aioPtr = &asyncIoTable[AIO_RD_IX(fd)];
802             
803             len = read(aioPtr->fd, aioPtr->buf, aioPtr->len);
804
805             procPtr = aioPtr->procPtr;
806             aioPtr->procPtr = NULL;
807             clientData = aioPtr->clientData;
808             aioPtr->inUse = 0;
809
810             (*procPtr)(clientData, len);
811         }
812
813         /*
814          * Do writes and dispatch callback.
815          */
816         if(FD_ISSET(fd, &writeFdSetPost) &&
817            asyncIoTable[AIO_WR_IX(fd)].inUse) {
818
819             numWrPosted--;
820             FD_CLR(fd, &writeFdSetPost);
821             aioPtr = &asyncIoTable[AIO_WR_IX(fd)];
822             
823             len = write(aioPtr->fd, aioPtr->buf, aioPtr->len);
824
825             procPtr = aioPtr->procPtr;
826             aioPtr->procPtr = NULL;
827             clientData = aioPtr->clientData;
828             aioPtr->inUse = 0;
829             (*procPtr)(clientData, len);
830         }
831     }
832     return 0;
833 }
834
835 \f
836 /*
837  *----------------------------------------------------------------------
838  *
839  * ClientAddrOK --
840  *
841  *      Checks if a client address is in a list of allowed addresses
842  *
843  * Results:
844  *      TRUE if address list is empty or client address is present
845  *      in the list, FALSE otherwise.
846  *
847  *----------------------------------------------------------------------
848  */
849 static int ClientAddrOK(struct sockaddr_in *saPtr, char *clientList)
850 {
851     int result = FALSE;
852     char *clientListCopy, *cur, *next;
853     char *newString = NULL;
854     int strLen;
855
856     if(clientList == NULL || *clientList == '\0') {
857         return TRUE;
858     }
859
860     strLen = strlen(clientList);
861     clientListCopy = malloc(strLen + 1);
862     assert(newString != NULL);
863     memcpy(newString, clientList, strLen);
864     newString[strLen] = '\000';
865     
866     for(cur = clientListCopy; cur != NULL; cur = next) {
867         next = strchr(cur, ',');
868         if(next != NULL) {
869             *next++ = '\0';
870         }
871         if(inet_addr(cur) == saPtr->sin_addr.s_addr) {
872             result = TRUE;
873             break;
874         }
875     }
876     free(clientListCopy);
877     return result;
878 }
879
880 \f
881 /*
882  *----------------------------------------------------------------------
883  *
884  * AcquireLock --
885  *
886  *      On platforms that implement concurrent calls to accept
887  *      on a shared listening ipcFd, returns 0.  On other platforms,
888  *      acquires an exclusive lock across all processes sharing a
889  *      listening ipcFd, blocking until the lock has been acquired.
890  *
891  * Results:
892  *      0 for successful call, -1 in case of system error (fatal).
893  *
894  * Side effects:
895  *      This process now has the exclusive lock.
896  *
897  *----------------------------------------------------------------------
898  */
899 static int AcquireLock(int blocking)
900 {
901 #ifdef USE_LOCKING
902     struct flock lock;
903     lock.l_type = F_WRLCK;
904     lock.l_start = 0;
905     lock.l_whence = SEEK_SET;
906     lock.l_len = 0;
907
908     if(fcntl(FCGI_LISTENSOCK_FILENO, 
909              blocking ? F_SETLKW : F_SETLK, &lock) < 0) {
910         if (errno != EINTR)
911             return -1;
912     }
913 #endif /* USE_LOCKING */
914     return 0;
915 }
916 \f
917 /*
918  *----------------------------------------------------------------------
919  *
920  * ReleaseLock --
921  *
922  *      On platforms that implement concurrent calls to accept
923  *      on a shared listening ipcFd, does nothing.  On other platforms,
924  *      releases an exclusive lock acquired by AcquireLock.
925  *
926  * Results:
927  *      0 for successful call, -1 in case of system error (fatal).
928  *
929  * Side effects:
930  *      This process no longer holds the lock.
931  *
932  *----------------------------------------------------------------------
933  */
934 static int ReleaseLock(void)
935 {
936 #ifdef USE_LOCKING
937     struct flock lock;
938     lock.l_type = F_UNLCK;
939     lock.l_start = 0;
940     lock.l_whence = SEEK_SET;
941     lock.l_len = 0;
942
943     if(fcntl(FCGI_LISTENSOCK_FILENO, F_SETLK, &lock) < 0) {
944         return -1;
945     }
946 #endif /* USE_LOCKING */
947     return 0;
948 }
949
950 \f
951 /*
952  *----------------------------------------------------------------------
953  *
954  * OS_FcgiIpcAccept --
955  *
956  *      Accepts a new FastCGI connection.  This routine knows whether
957  *      we're dealing with TCP based sockets or NT Named Pipes for IPC.
958  *
959  * Results:
960  *      -1 if the operation fails, otherwise this is a valid IPC fd.
961  *
962  * Side effects:
963  *      New IPC connection is accepted.
964  *
965  *----------------------------------------------------------------------
966  */
967 int OS_FcgiIpcAccept(char *clientAddrList)
968 {
969     int socket;
970     union u_sockaddr {
971         struct sockaddr_un un;
972         struct sockaddr_in in;
973     } sa;
974     int clilen;
975     
976     if (AcquireLock(TRUE) < 0) {
977         return (-1);
978     }
979     for (;;) {
980         do {
981             clilen = sizeof(sa);
982             socket = accept(FCGI_LISTENSOCK_FILENO,
983                             (struct sockaddr *) &sa.un,
984                             &clilen);
985         } while ((socket < 0) && (errno == EINTR));
986
987         if (socket >= 0) {
988             /*
989             * If the new connection uses TCP/IP, check the client IP address;
990             * if the address isn't valid, close the connection and
991             * try again.
992             */
993             if ((sa.in.sin_family == AF_INET)
994                     && (!ClientAddrOK(&sa.in, clientAddrList))) {
995                 close(socket);
996                 continue;
997             } 
998             break;
999         }
1000
1001         /* Based on Apache's (v1.3.1) http_main.c accept() handling and 
1002          * Stevens' Unix Network Programming Vol 1, 2nd Ed, para. 15.6
1003          */
1004         switch (errno) {
1005 #ifdef EPROTO
1006             /* EPROTO on certain older kernels really means
1007              * ECONNABORTED, so we need to ignore it for them.
1008              * See discussion in new-httpd archives nh.9701
1009              * search for EPROTO.
1010              *
1011              * Also see nh.9603, search for EPROTO:
1012              * There is potentially a bug in Solaris 2.x x<6,
1013              * and other boxes that implement tcp sockets in
1014              * userland (i.e. on top of STREAMS).  On these
1015              * systems, EPROTO can actually result in a fatal
1016              * loop.  See PR#981 for example.  It's hard to
1017              * handle both uses of EPROTO.
1018              */
1019             case EPROTO:
1020 #endif
1021 #ifdef ECONNABORTED
1022             case ECONNABORTED:
1023 #endif
1024             /* Linux generates the rest of these, other tcp
1025              * stacks (i.e. bsd) tend to hide them behind
1026              * getsockopt() interfaces.  They occur when
1027              * the net goes sour or the client disconnects
1028              * after the three-way handshake has been done
1029              * in the kernel but before userland has picked
1030              * up the socket.
1031              */
1032 #ifdef ECONNRESET
1033             case ECONNRESET:
1034 #endif
1035 #ifdef ETIMEDOUT
1036             case ETIMEDOUT:
1037 #endif
1038 #ifdef EHOSTUNREACH
1039             case EHOSTUNREACH:
1040 #endif
1041 #ifdef ENETUNREACH
1042             case ENETUNREACH:
1043 #endif
1044                 break;  /* switch(errno) */
1045
1046             default: {
1047                     int errnoSave = errno;
1048                     ReleaseLock();
1049                     errno = errnoSave;
1050                 }
1051                 return (-1);
1052         }  /* switch(errno) */
1053     }  /* for(;;) */
1054
1055     if (ReleaseLock() < 0) {
1056         return (-1);
1057     }
1058     return (socket);
1059 }
1060 \f
1061 /*
1062  *----------------------------------------------------------------------
1063  *
1064  * OS_IpcClose
1065  *
1066  *      OS IPC routine to close an IPC connection.
1067  *
1068  * Results:
1069  *
1070  *
1071  * Side effects:
1072  *      IPC connection is closed.
1073  *
1074  *----------------------------------------------------------------------
1075  */
1076 int OS_IpcClose(int ipcFd)
1077 {
1078     return OS_Close(ipcFd);
1079 }
1080
1081 \f
1082 /*
1083  *----------------------------------------------------------------------
1084  *
1085  * OS_IsFcgi --
1086  *
1087  *      Determines whether this process is a FastCGI process or not.
1088  *
1089  * Results:
1090  *      Returns 1 if FastCGI, 0 if not.
1091  *
1092  * Side effects:
1093  *      None.
1094  *
1095  *----------------------------------------------------------------------
1096  */
1097 int OS_IsFcgi()
1098 {
1099         union {
1100         struct sockaddr_in in;
1101         struct sockaddr_un un;
1102     } sa;
1103     int len = sizeof(sa);
1104
1105     if (getpeername(FCGI_LISTENSOCK_FILENO, (struct sockaddr *)&sa, &len) != 0 
1106             && errno == ENOTCONN)
1107         isFastCGI = TRUE;
1108     else
1109         isFastCGI = FALSE;
1110         
1111     return (isFastCGI);
1112 }
1113 \f
1114 /*
1115  *----------------------------------------------------------------------
1116  *
1117  * OS_SetFlags --
1118  *
1119  *      Sets selected flag bits in an open file descriptor.
1120  *
1121  *----------------------------------------------------------------------
1122  */
1123 void OS_SetFlags(int fd, int flags)
1124 {
1125     int val;
1126     if((val = fcntl(fd, F_GETFL, 0)) < 0) {
1127         exit(errno);
1128     }
1129     val |= flags;
1130     if(fcntl(fd, F_SETFL, val) < 0) {
1131         exit(errno);
1132     }
1133 }