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