📄 os_unix.c
字号:
/* * os_unix.c -- * * Description of file. * * * Copyright (c) 1995 Open Market, Inc. * All rights reserved. * * This file contains proprietary and confidential information and * remains the unpublished property of Open Market, Inc. Use, * disclosure, or reproduction is prohibited except as permitted by * express written license agreement with Open Market, Inc. * * Bill Snapper * snapper@openmarket.com */#ifndef lintstatic const char rcsid[] = "$Id: os_unix.c,v 1.37 2002/03/05 19:14:49 robs Exp $";#endif /* not lint */#include "fcgi_config.h"#include <sys/types.h>#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#include <arpa/inet.h>#include <assert.h>#include <errno.h>#include <fcntl.h> /* for fcntl */#include <math.h>#include <memory.h> /* for memchr() */#include <netinet/tcp.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <sys/un.h>#include <signal.h>#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h> /* for getpeername */#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "fastcgi.h"#include "fcgimisc.h"#include "fcgios.h"#ifndef INADDR_NONE#define INADDR_NONE ((unsigned long) -1)#endif/* * This structure holds an entry for each oustanding async I/O operation. */typedef struct { OS_AsyncProc procPtr; /* callout completion procedure */ ClientData clientData; /* caller private data */ int fd; int len; int offset; void *buf; int inUse;} AioInfo;/* * Entries in the async I/O table are allocated 2 per file descriptor. * * Read Entry Index = fd * 2 * Write Entry Index = (fd * 2) + 1 */#define AIO_RD_IX(fd) (fd * 2)#define AIO_WR_IX(fd) ((fd * 2) + 1)static int asyncIoInUse = FALSE;static int asyncIoTableSize = 16;static AioInfo *asyncIoTable = NULL;static int libInitialized = FALSE;static fd_set readFdSet;static fd_set writeFdSet;static fd_set readFdSetPost;static int numRdPosted = 0;static fd_set writeFdSetPost;static int numWrPosted = 0;static int volatile maxFd = -1;static int shutdownPending = FALSE;static int shutdownNow = FALSE;void OS_ShutdownPending(){ shutdownPending = TRUE;}static void OS_Sigusr1Handler(int signo){ OS_ShutdownPending();}static void OS_SigpipeHandler(int signo){ ;}static void installSignalHandler(int signo, const struct sigaction * act, int force){ struct sigaction sa; sigaction(signo, NULL, &sa); if (force || sa.sa_handler == SIG_DFL) { sigaction(signo, act, NULL); }}static void OS_InstallSignalHandlers(int force){ struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = OS_SigpipeHandler; installSignalHandler(SIGPIPE, &sa, force); sa.sa_handler = OS_Sigusr1Handler; installSignalHandler(SIGUSR1, &sa, force);}/* *-------------------------------------------------------------- * * OS_LibInit -- * * Set up the OS library for use. * * NOTE: This function is really only needed for application * asynchronous I/O. It will most likely change in the * future to setup the multi-threaded environment. * * Results: * Returns 0 if success, -1 if not. * * Side effects: * Async I/O table allocated and initialized. * *-------------------------------------------------------------- */int OS_LibInit(int stdioFds[3]){ if(libInitialized) return 0; asyncIoTable = (AioInfo *)malloc(asyncIoTableSize * sizeof(AioInfo)); if(asyncIoTable == NULL) { errno = ENOMEM; return -1; } memset((char *) asyncIoTable, 0, asyncIoTableSize * sizeof(AioInfo)); FD_ZERO(&readFdSet); FD_ZERO(&writeFdSet); FD_ZERO(&readFdSetPost); FD_ZERO(&writeFdSetPost); OS_InstallSignalHandlers(FALSE); libInitialized = TRUE; return 0;}/* *-------------------------------------------------------------- * * OS_LibShutdown -- * * Shutdown the OS library. * * Results: * None. * * Side effects: * Memory freed, fds closed. * *-------------------------------------------------------------- */void OS_LibShutdown(){ if(!libInitialized) return; free(asyncIoTable); asyncIoTable = NULL; libInitialized = FALSE; return;}/* *---------------------------------------------------------------------- * * OS_BuildSockAddrUn -- * * Using the pathname bindPath, fill in the sockaddr_un structure * *servAddrPtr and the length of this structure *servAddrLen. * * The format of the sockaddr_un structure changed incompatibly in * 4.3BSD Reno. Digital UNIX supports both formats, other systems * support one or the other. * * Results: * 0 for normal return, -1 for failure (bindPath too long). * *---------------------------------------------------------------------- */static int OS_BuildSockAddrUn(const char *bindPath, struct sockaddr_un *servAddrPtr, int *servAddrLen){ int bindPathLen = strlen(bindPath);#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ if(bindPathLen >= sizeof(servAddrPtr->sun_path)) { return -1; }#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ if(bindPathLen > sizeof(servAddrPtr->sun_path)) { return -1; }#endif memset((char *) servAddrPtr, 0, sizeof(*servAddrPtr)); servAddrPtr->sun_family = AF_UNIX; memcpy(servAddrPtr->sun_path, bindPath, bindPathLen);#ifdef HAVE_SOCKADDR_UN_SUN_LEN /* 4.3BSD Reno and later: BSDI, DEC */ *servAddrLen = sizeof(servAddrPtr->sun_len) + sizeof(servAddrPtr->sun_family) + bindPathLen + 1; servAddrPtr->sun_len = *servAddrLen;#else /* 4.3 BSD Tahoe: Solaris, HPUX, DEC, ... */ *servAddrLen = sizeof(servAddrPtr->sun_family) + bindPathLen;#endif return 0;}union SockAddrUnion { struct sockaddr_un unixVariant; struct sockaddr_in inetVariant;};/* * OS_CreateLocalIpcFd -- * * This procedure is responsible for creating the listener socket * on Unix for local process communication. It will create a * domain socket or a TCP/IP socket bound to "localhost" and return * a file descriptor to it to the caller. * * Results: * Listener socket created. This call returns either a valid * file descriptor or -1 on error. * * Side effects: * None. * *---------------------------------------------------------------------- */int OS_CreateLocalIpcFd(const char *bindPath, int backlog){ int listenSock, servLen; union SockAddrUnion sa; int tcp = FALSE; unsigned long tcp_ia = 0; char *tp; short port = 0; char host[MAXPATHLEN]; strcpy(host, bindPath); if((tp = strchr(host, ':')) != 0) { *tp++ = 0; if((port = atoi(tp)) == 0) { *--tp = ':'; } else { tcp = TRUE; } } if(tcp) { if (!*host || !strcmp(host,"*")) { tcp_ia = htonl(INADDR_ANY); } else { tcp_ia = inet_addr(host); if (tcp_ia == INADDR_NONE) { struct hostent * hep; hep = gethostbyname(host); if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) { fprintf(stderr, "Cannot resolve host name %s -- exiting!\n", host); exit(1); } if (hep->h_addr_list[1]) { fprintf(stderr, "Host %s has multiple addresses ---\n", host); fprintf(stderr, "you must choose one explicitly!!!\n"); exit(1); } tcp_ia = ((struct in_addr *) (hep->h_addr))->s_addr; } } } if(tcp) { listenSock = socket(AF_INET, SOCK_STREAM, 0); if(listenSock >= 0) { int flag = 1; if(setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(flag)) < 0) { fprintf(stderr, "Can't set SO_REUSEADDR.\n"); exit(1001); } } } else { listenSock = socket(AF_UNIX, SOCK_STREAM, 0); } if(listenSock < 0) { return -1; } /* * Bind the listening socket. */ if(tcp) { memset((char *) &sa.inetVariant, 0, sizeof(sa.inetVariant)); sa.inetVariant.sin_family = AF_INET; sa.inetVariant.sin_addr.s_addr = tcp_ia; sa.inetVariant.sin_port = htons(port); servLen = sizeof(sa.inetVariant); } else { unlink(bindPath); if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { fprintf(stderr, "Listening socket's path name is too long.\n"); exit(1000); } } if(bind(listenSock, (struct sockaddr *) &sa.unixVariant, servLen) < 0 || listen(listenSock, backlog) < 0) { perror("bind/listen"); exit(errno); } return listenSock;}/* *---------------------------------------------------------------------- * * OS_FcgiConnect -- * * Create the socket and connect to the remote application if * possible. * * This was lifted from the cgi-fcgi application and was abstracted * out because Windows NT does not have a domain socket and must * use a named pipe which has a different API altogether. * * Results: * -1 if fail or a valid file descriptor if connection succeeds. * * Side effects: * Remote connection established. * *---------------------------------------------------------------------- */int OS_FcgiConnect(char *bindPath){ union SockAddrUnion sa; int servLen, resultSock; int connectStatus; char *tp; char host[MAXPATHLEN]; short port = 0; int tcp = FALSE; strcpy(host, bindPath); if((tp = strchr(host, ':')) != 0) { *tp++ = 0; if((port = atoi(tp)) == 0) { *--tp = ':'; } else { tcp = TRUE; } } if(tcp == TRUE) { struct hostent *hp; if((hp = gethostbyname((*host ? host : "localhost"))) == NULL) { fprintf(stderr, "Unknown host: %s\n", bindPath); exit(1000); } sa.inetVariant.sin_family = AF_INET; memcpy(&sa.inetVariant.sin_addr, hp->h_addr, hp->h_length); sa.inetVariant.sin_port = htons(port); servLen = sizeof(sa.inetVariant); resultSock = socket(AF_INET, SOCK_STREAM, 0); } else { if(OS_BuildSockAddrUn(bindPath, &sa.unixVariant, &servLen)) { fprintf(stderr, "Listening socket's path name is too long.\n"); exit(1000); } resultSock = socket(AF_UNIX, SOCK_STREAM, 0); } ASSERT(resultSock >= 0); connectStatus = connect(resultSock, (struct sockaddr *) &sa.unixVariant, servLen); if(connectStatus >= 0) { return resultSock; } else { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -