? nsunix/nsunix.c.20011216 Index: nsunix/nsunix.c =================================================================== RCS file: /cvsroot/aolserver/nsunix/nsunix.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 nsunix.c --- nsunix/nsunix.c 31 Jan 2001 21:02:10 -0000 1.1.1.1 +++ nsunix/nsunix.c 15 Nov 2002 05:04:19 -0000 @@ -85,14 +85,14 @@ */ typedef struct { + Ns_Driver driver; /* the Ns_Driver handle for this driver */ + char *name; /* name of this driver, e.g., "nsunix" */ char *location; /* e.g., http://www.foo.com:80 */ char *host; /* e.g., www.foo.com */ int port; /* e.g., 80 */ char *udsFilename; /* Unix domain socket file name */ int listenSocket; /* do accept() calls on this socket */ - Ns_Driver driver; /* the Ns_Driver handle for this driver */ int stopped; /* 0: drv running; 1: stopping; 2: stopped */ - Ns_Mutex lock; /* lock around 'stopped' variable */ } DriverContext; /* @@ -115,27 +115,28 @@ * Local functions defined in this file. */ -static int DrvPeerPort(void *vconnCtxPtr); -static int DrvConnectionFd(void *vconnCtxPtr); -static void *DrvDetach(void *vconnCtxPtr); +static Ns_DriverStartProc DrvStart; +static Ns_DriverStopProc DrvStop; +static Ns_ConnReadProc DrvRead; +static Ns_ConnWriteProc DrvWrite; +static Ns_ConnCloseProc DrvClose; +static Ns_ConnConnectionFdProc DrvConnectionFd; +static Ns_ConnDetachProc DrvDetach; +static Ns_ConnPeerProc DrvPeer; +static Ns_ConnPeerPortProc DrvPeerPort; +static Ns_ConnLocationProc DrvLocation; +static Ns_ConnHostProc DrvHost; +static Ns_ConnPortProc DrvPort; +static Ns_ConnDriverNameProc DrvName; +static Ns_ConnInitProc DrvInit; +static Ns_ConnSendFdProc DrvSendFd; + static int DrvSendFile(void *vconnCtxPtr, char *filename); -static int DrvSendFd(void *vconnCtxPtr, int fd, int nsend); -static int DrvPort(void *vconnCtxPtr); -static char *DrvHost(void *vconnCtxPtr); -static char *DrvLocation(void *vconnCtxPtr); -static char *DrvPeer(void *vconnCtxPtr); static void DrvFree(void *vconnCtxPtr); -static int DrvClose(void *vconnCtxPtr); -static int DrvWrite(void *vconnCtxPtr, void *vbufPtr, int toWrite); -static int DrvRead(void *vconnCtxPtr, void *vbufPtr, int toread); -static int DrvInit(void *vconnCtxPtr); -static void DrvStop(void *vdriverCtxPtr); -static int DrvAccept(void *drvCtxPtr, void **connCtxPtrPtr); -static int DrvStart(char *hServer, char *hDriver, void **driverCtxPtrPtr); -static char *DrvName(void *drvCtxPtr); +static int DrvAccept(DriverContext *drvCtxPtr, ConnContext **connCtxPtrPtr); + static int GetDataFromUDS(ConnContext *connCtxPtr); static int Listen(char *path); -static int Accept(int lsock, struct sockaddr *addrPtr, int *addrlenPtr); static int ConnWait(ConnContext *connCtxPtr, int write); /* @@ -144,25 +145,27 @@ */ static Ns_DrvProc drvProcs[] = { - { Ns_DrvIdName, (void *) DrvName }, { Ns_DrvIdStart, (void *) DrvStart }, - { Ns_DrvIdAccept, (void *) DrvAccept }, { Ns_DrvIdStop, (void *) DrvStop }, - { Ns_DrvIdInit, (void *) DrvInit }, { Ns_DrvIdRead, (void *) DrvRead }, { Ns_DrvIdWrite, (void *) DrvWrite }, { Ns_DrvIdClose, (void *) DrvClose }, - { Ns_DrvIdFree, (void *) DrvFree }, - { Ns_DrvIdPeer, (void *) DrvPeer }, - { Ns_DrvIdLocation, (void *) DrvLocation }, { Ns_DrvIdHost, (void *) DrvHost }, { Ns_DrvIdPort, (void *) DrvPort }, + { Ns_DrvIdName, (void *) DrvName }, + { Ns_DrvIdPeer, (void *) DrvPeer }, + { Ns_DrvIdPeerPort, (void *) DrvPeerPort }, + { Ns_DrvIdLocation, (void *) DrvLocation }, + { Ns_DrvIdConnectionFd, (void *) DrvConnectionFd }, + { Ns_DrvIdDetach, (void *) DrvDetach }, + { Ns_DrvIdInit, (void *) DrvInit }, + { Ns_DrvIdSendFd, (void *) DrvSendFd }, { Ns_DrvIdSendFile, (void *) DrvSendFile }, - { Ns_DrvIdDetach, (void *) DrvDetach }, - { Ns_DrvIdConnectionFd, (void *) DrvConnectionFd }, - { Ns_DrvIdPeerPort, (void *) DrvPeerPort }, + { Ns_DrvIdFree, (void *) DrvFree }, + /* { Ns_DrvIdAccept, (void *) DrvAccept }, */ + /* * SSL-specific callbacks are not supported here. */ @@ -174,7 +177,17 @@ * Global variables. */ -int Ns_ModuleVersion = 1; +static Ns_Callback DrvShutdown; +static Ns_Callback DrvReady; +static Ns_ThreadProc DrvThread; +static void DrvTrigger(); + +static DriverContext *firstDrvCtxPtr; /* First in list of all drivers. */ +static Ns_Thread drvThread; /* Running DrvThread. */ +static int shutdownPending; /* Flag to indicate shutdown. */ +static Ns_Mutex lock; /* Lock around close list and shutdown flag. */ + +NS_EXPORT int Ns_ModuleVersion = 1; /* @@ -201,18 +214,19 @@ *---------------------------------------------------------------------- */ -int +NS_EXPORT int Ns_ModuleInit(char *server, char *module) { DriverContext *drvCtxPtr; - int status = NS_ERROR; + int status = NS_ERROR; char *path; char *udsFilename; Ns_DString ds; Ns_DStringInit(&ds); - drvCtxPtr = ns_malloc(sizeof(DriverContext)); + drvCtxPtr = ns_calloc(1, sizeof(DriverContext)); + drvCtxPtr->name = module; path = Ns_ConfigGetPath(server, module, NULL); if (path == NULL) { @@ -248,16 +262,31 @@ Ns_DStringVarAppend(&ds, MODULES, "/", DRIVER_NAME, "/", udsFilename, NULL); drvCtxPtr->udsFilename = ns_strdup(Ns_DStringValue(&ds)); - Ns_DStringTrunc(&ds, 0); - drvCtxPtr->location = ns_strdup(Ns_DStringPrintf(&ds, "http://%s:%d/", - drvCtxPtr->host, drvCtxPtr->port)); - drvCtxPtr->stopped = 0; + drvCtxPtr->location = Ns_ConfigGetValue(path, "location"); + if (drvCtxPtr->location == NULL) { + drvCtxPtr->location = ns_strdup(Ns_DStringPrintf(&ds, + "http://%s:%d/", drvCtxPtr->host, drvCtxPtr->port)); + Ns_Log(Warning, "nsunix: missing Location parameter, " + "using Location: %s", drvCtxPtr->location); + } + + drvCtxPtr->stopped = 0; drvCtxPtr->driver = Ns_RegisterDriver(server, module, drvProcs, drvCtxPtr); - status = NS_OK; + if (drvCtxPtr->driver == NULL) + goto done; + + if (firstDrvCtxPtr == NULL) { + Ns_MutexSetName(&lock, DRIVER_NAME); + Ns_RegisterAtShutdown(DrvShutdown, NULL); + } + + firstDrvCtxPtr = drvCtxPtr; + status = NS_OK; + done: Ns_DStringFree(&ds); return status; @@ -287,11 +316,11 @@ */ static char * -DrvName(void *driverCtxPtr) +DrvName(void *arg) { - DriverContext *drvCtxPtr = (DriverContext *) driverCtxPtr; + ConnContext *connCtxPtr = (ConnContext *) arg; - return DRIVER_NAME; + return connCtxPtr->drvCtxPtr->name; } @@ -313,20 +342,153 @@ */ static int -DrvStart(char *hServer, char *hDriver, void **driverCtxPtrPtr) +DrvStart(char *server, char *label, void **driverCtxPtrPtr) { DriverContext *drvCtxPtr = (DriverContext *) *driverCtxPtrPtr; - int status = NS_ERROR; drvCtxPtr->listenSocket = Listen(drvCtxPtr->udsFilename); if (drvCtxPtr->listenSocket == -1) { - Ns_Log(Error, "nsunix: failed to start listening: %s", - strerror(errno)); + Ns_Log(Error, "%s: failed to listen on %s: %s", + drvCtxPtr->name, drvCtxPtr->udsFilename, strerror(errno)); + goto done; } else { - status = NS_OK; + Ns_Log(Notice, "%s: listening on %s", + drvCtxPtr->name, drvCtxPtr->udsFilename); } - - return status; + + shutdownPending = 0; + + /* + * Create the socket thread. + */ + + Ns_ThreadCreate(DrvThread, NULL, 0, &drvThread); + Ns_RegisterAtReady(DrvReady, NULL); + +done: + return (drvCtxPtr->listenSocket == -1 ? NS_ERROR : NS_OK); +} + + +/* + *---------------------------------------------------------------------- + * + * DrvStop -- + * + * Stop the accept callback because the server is shutting down. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +DrvStop(void *arg) +{ + Ns_MutexLock(&lock); + if (drvThread != NULL && !shutdownPending) { + Ns_Log(Notice, "%s: triggering shutdown", DRIVER_NAME); + shutdownPending = 1; + DrvTrigger(); + } + Ns_MutexUnlock(&lock); +} + + +/* + *---------------------------------------------------------------------- + * + * DrvReady -- + * + * Trigger the DrvThread to indicate the server is no longer + * busy. + * + * Results: + * None. + * + * Side effects: + * DrvThread will wakeup and retry Ns_QueueConn if a connection + * is pending. + * + *---------------------------------------------------------------------- + */ + +static void +DrvReady(void *arg) +{ + Ns_MutexLock(&lock); + if (drvThread != NULL) { + Ns_Log(Notice, "%s: server ready - resuming", DRIVER_NAME); + DrvTrigger(); + } + Ns_MutexUnlock(&lock); +} + + +/* + *---------------------------------------------------------------------- + * + * DrvShutdown -- + * + * Wait for exit of DrvThread. This callback is invoked later by + * the timed shutdown thread. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +DrvShutdown(void *arg) +{ + if (drvThread != NULL) { + Ns_ThreadJoin(&drvThread, NULL); + drvThread = NULL; + } + Ns_Log(Notice, "%s: shutdown complete", DRIVER_NAME); +} + + +static void +DrvThread(void *ignored) +{ + int status; + DriverContext *dData = firstDrvCtxPtr; + ConnContext *cData; + char *loc; + + loc = dData->location; + + Ns_ThreadSetName("-" DRIVER_NAME "-"); + Ns_Log(Notice, "%s: starting", DRIVER_NAME); + + Ns_Log(Notice, "%s: accepting connections", DRIVER_NAME); + + while ((status = (DrvAccept(dData, &cData))) == NS_OK) { + if (Ns_QueueConn(dData->driver, cData) != NS_OK) { + // (*dPtr->closeProc)(dData); + DrvClose(dData); + } + } + +#if 0 + if (status == NS_SHUTDOWN) { + Ns_Log(Notice, "drv: driver '%s' stopping '%s'", dPtr->label, loc); + } else { + Ns_Log(Error, "drv: driver '%s' failed for '%s': error %d", + dPtr->label, loc, status); + } +#endif + + Ns_Log(Notice, "%s: exiting", DRIVER_NAME); } @@ -348,11 +510,10 @@ */ static int -DrvAccept(void *vdrvCtxPtr, void **vconnCtxPtrPtr) +DrvAccept(DriverContext *vdrvCtxPtr, ConnContext **vconnCtxPtrPtr) { DriverContext *drvCtxPtr = (DriverContext *) vdrvCtxPtr; ConnContext *connCtxPtr = *((ConnContext **) vconnCtxPtrPtr); - int fd; int status = NS_ERROR; /* @@ -368,33 +529,47 @@ for (;;) { int len; - struct sockaddr_in sa; + size_t end; + char buf[200]; + struct sockaddr_un sa; len = sizeof(sa); - connCtxPtr->unix_sock = Accept(drvCtxPtr->listenSocket, - (struct sockaddr *) &sa, &len); + connCtxPtr->unix_sock = Ns_SockAccept(drvCtxPtr->listenSocket, + (struct sockaddr *) &sa, &len); + if (connCtxPtr->unix_sock >= 0) { - strcpy(connCtxPtr->remoteAddr, ns_inet_ntoa(sa.sin_addr)); - connCtxPtr->remotePort = ntohs(sa.sin_port); + // strcpy(connCtxPtr->remoteAddr, ns_inet_ntoa(sa.sin_addr)); + // connCtxPtr->remotePort = ntohs(sa.sin_port); connCtxPtr->drvCtxPtr = drvCtxPtr; *vconnCtxPtrPtr = (void *) connCtxPtr; - status = NS_OK; - break; - } else if (errno != EWOULDBLOCK) { - Ns_Log(Error, "nsunix: " - "accept returned error: %s", strerror(errno)); - status = NS_ERROR; - break; - } + + /* FIXME: buf[200] ... scary */ + end = len - sizeof(sa.sun_family); + memcpy(buf, sa.sun_path, end); + buf[end] = '\0'; + + assert(sa.sun_family == AF_UNIX); + + bzero(&(connCtxPtr->remoteAddr), sizeof(connCtxPtr->remoteAddr)); + connCtxPtr->remotePort = -1; + + status = NS_OK; + break; + } else if (errno != EWOULDBLOCK) { + Ns_Log(Error, "%s: accept returned error: %s", + DRIVER_NAME, strerror(errno)); + status = NS_ERROR; + break; + } } - Ns_MutexLock(&drvCtxPtr->lock); - if (drvCtxPtr->stopped != 0) { + Ns_MutexLock(&lock); + if (shutdownPending) { status = NS_SHUTDOWN; close(connCtxPtr->unix_sock); } - Ns_MutexUnlock(&drvCtxPtr->lock); + Ns_MutexUnlock(&lock); if (status != NS_OK) { ns_free(connCtxPtr->buffer); @@ -409,31 +584,27 @@ /* *---------------------------------------------------------------------- * - * DrvStop -- + * DrvTrigger -- * - * Stop the accept callback because the server is shutting down. + * Wakeup DrvThread from blocking select(). * * Results: - * None. + * None. * * Side effects: - * None. + * DrvThread will wakeup. * *---------------------------------------------------------------------- */ static void -DrvStop(void *vdriverCtxPtr) +DrvTrigger(void) { - DriverContext *drvCtxPtr = (DriverContext *) vdriverCtxPtr; + DriverContext *drvCtxPtr = (DriverContext *) firstDrvCtxPtr; struct sockaddr_un addr; int unix_sock; - int addr_len; + unsigned int addr_len; - Ns_MutexLock(&drvCtxPtr->lock); - drvCtxPtr->stopped = 1; - Ns_MutexUnlock(&drvCtxPtr->lock); - /* * Force the accept thread to break out of the blocking accept call. */ @@ -441,8 +612,8 @@ unix_sock = socket(AF_UNIX, SOCK_STREAM, 0); if (unix_sock < 0) { Ns_Log(Error, "nsunix: failed to create socket: %s", - strerror(errno)); - return; + strerror(errno)); + return; } bzero((char *) &addr, sizeof(addr)); @@ -450,11 +621,10 @@ addr.sun_family = AF_UNIX; addr_len = sizeof(addr.sun_family) + strlen(addr.sun_path); if (connect(unix_sock, (struct sockaddr *) &addr, addr_len) < 0) { - Ns_Log(Error, "nsunix: failed to connect to unix:%s: %s", - drvCtxPtr->udsFilename, strerror(errno)); + Ns_Log(Error, "%s: failed to connect to %s: %s", + DRIVER_NAME, drvCtxPtr->udsFilename, strerror(errno)); } else { - close(unix_sock); - close(drvCtxPtr->listenSocket); + close(unix_sock); } } @@ -478,10 +648,8 @@ */ static int -DrvInit(void *vconnCtxPtr) +DrvInit(void *ignored) { - ConnContext *connCtxPtr = (ConnContext *) vconnCtxPtr; - return NS_OK; } @@ -510,7 +678,7 @@ int numRead = 0; while (toread > 0) { - int toCopy; + size_t toCopy; if (connCtxPtr->count > 0) { toCopy = MIN(toread, connCtxPtr->count); @@ -531,9 +699,8 @@ connCtxPtr->base = connCtxPtr->buffer; connCtxPtr->count = recv(connCtxPtr->sock, connCtxPtr->buffer, BUFFERSIZE, 0); - Ns_Log(Debug, "nsunix: " - "received %d bytes on socket fd: %d", - numRead, connCtxPtr->sock); + Ns_Log(Debug, "%s: received %d bytes on socket fd: %d", + DRIVER_NAME, numRead, connCtxPtr->sock); if (connCtxPtr->count == -1 && errno == EWOULDBLOCK && ConnWait(connCtxPtr, 0)) { @@ -574,11 +741,11 @@ ConnContext *connCtxPtr = (ConnContext *) vconnCtxPtr; int numWrite; - numWrite = write(connCtxPtr->sock, vbufPtr, toWrite); + numWrite = write(connCtxPtr->sock, vbufPtr, (size_t) toWrite); if (numWrite == -1 && errno == EWOULDBLOCK && ConnWait(connCtxPtr, 1)) { - numWrite = write(connCtxPtr->sock, vbufPtr, toWrite); + numWrite = write(connCtxPtr->sock, vbufPtr, (size_t) toWrite); } return numWrite; @@ -686,11 +853,14 @@ */ static char * -DrvLocation(void *vdrvCtxPtr) +DrvLocation(void *arg) { - DriverContext *drvCtxPtr = (DriverContext *) vdrvCtxPtr; + ConnContext *connCtxPtr = (ConnContext *) arg; + + if (connCtxPtr->drvCtxPtr == NULL) + return "(null)"; - return drvCtxPtr->location; + return connCtxPtr->drvCtxPtr->location; } @@ -770,7 +940,7 @@ int offset; int written; - mem = (char *) mmap(NULL, nsend, PROT_READ, MAP_PRIVATE, fd, 0); + mem = (char *) mmap(NULL, (size_t) nsend, PROT_READ, MAP_PRIVATE, fd, 0); if (mem == NULL) { return -1; } @@ -779,16 +949,18 @@ towrite = nsend; while (towrite > 0) { - n = write(connCtxPtr->sock, mem+offset, towrite); - if (n <= 0) { - written = n; + n = write(connCtxPtr->sock, mem+offset, (size_t) towrite); + if (n == -1 && errno == EWOULDBLOCK) { + ConnWait(connCtxPtr, 1); /* wait then try again */ + continue; + } else if (n <= 0) { break; } written += n; offset += n; towrite -= n; } - munmap(mem, nsend); + munmap(mem, (size_t) nsend); return written; } @@ -811,9 +983,8 @@ */ static int -DrvSendFile(void *vconnCtxPtr, char *filename) +DrvSendFile(void *arg, char *filename) { - ConnContext *connCtxPtr = (ConnContext *) vconnCtxPtr; struct stat statbuf; int fd; int retval; @@ -825,7 +996,7 @@ if (fd == -1) { return -1; } - retval = DrvSendFd(vconnCtxPtr, fd, statbuf.st_size); + retval = DrvSendFd(arg, fd, statbuf.st_size); close(fd); return retval; @@ -860,7 +1031,7 @@ assert(newCtxPtr->buffer != NULL); newCtxPtr->base = newCtxPtr->buffer; newCtxPtr->count = connCtxPtr->count; - memcpy(newCtxPtr->base, connCtxPtr->base, connCtxPtr->count); + memcpy(newCtxPtr->base, connCtxPtr->base, (size_t) connCtxPtr->count); return (void *) newCtxPtr; } @@ -972,37 +1143,6 @@ /* *---------------------------------------------------------------------- * - * Accept -- - * - * Wrapper around accept(). - * - * Results: - * Result from accept(). - * - * Side effects: - * May log error. - * - *---------------------------------------------------------------------- - */ - -static int -Accept(int lsock, struct sockaddr *addr, int *addrlen) -{ - int sock; - - sock = Ns_SockAccept(lsock, addr, addrlen); - if (sock == -1) { - Ns_Log(Warning, "nsunix: accept(%d) failed: %s", - lsock, strerror(errno)); - } - - return sock; -} - - -/* - *---------------------------------------------------------------------- - * * GetDataFromUDS -- * * Receive a file descriptor and headers from the virtual host @@ -1013,7 +1153,7 @@ * * Side effects: * Fills the ConnContext read buffer with data from unix domain - * until there is no more. + * until there is no more, or the buffer is full. * *---------------------------------------------------------------------- */ @@ -1053,29 +1193,62 @@ return NS_ERROR; } + if (numRead > 0) { #ifdef HAVE_CMMSG - if (ancillary.cmsg.cmsg_len != sizeof(ancillary) || - ancillary.cmsg.cmsg_level != SOL_SOCKET || - ancillary.cmsg.cmsg_type != SCM_RIGHTS) { - - Ns_Log(Error, "nsunix: unexpected ancillary data:" - " cmsg_len: %d, cmsg_level: %d, cmsg_type: %d", - ancillary.cmsg.cmsg_len, ancillary.cmsg.cmsg_level, - ancillary.cmsg.cmsg_type); - return NS_ERROR; - } + if (msg.msg_controllen != 0) { + if (ancillary.cmsg.cmsg_len != sizeof(ancillary) || + ancillary.cmsg.cmsg_level != SOL_SOCKET || + ancillary.cmsg.cmsg_type != SCM_RIGHTS) { + + Ns_Log(Error, "nsunix: unexpected ancillary data:" + " cmsg_len: %d, cmsg_level: %d, cmsg_type: %d", + ancillary.cmsg.cmsg_len, ancillary.cmsg.cmsg_level, + ancillary.cmsg.cmsg_type); + return NS_ERROR; + } - sock = ancillary.sock; + sock = ancillary.sock; + } +#else + /* + * UNTESTED CODE + * + * ADAPTED FROM STEVENS APUE p 15.8 + * + * TESTING TO MAKE SURE THAT WE DID RECEIVE A SOCKET DESCRIPTOR + * ASSUMING ASSUMING THAT THE LENGTH FIELD WILL BE 0 IF A SOCKET + * WAS NOT INCLUDED + */ + if (msg.msg_accrightslen != sizeof(sock)) { + sock = -1; + } #endif - if (numRead > 0) { assert (numRead <= BUFFERSIZE); connCtxPtr->buffer[numRead] = '\0'; connCtxPtr->base = connCtxPtr->buffer; connCtxPtr->count = numRead; if (connCtxPtr->sock == -1) { + struct sockaddr_in sa; + int sa_size = sizeof(sa); + + if (sock == -1) { + return NS_ERROR; + } connCtxPtr->sock = sock; + + memset(&sa, 0, sizeof(sa)); + if (getpeername(sock, (struct sockaddr *) &sa, &sa_size) < 0) { + /* + * on error, go on with bogus ip addr + */ + Ns_Log(Error, "nsunix: GetDataFromUDS: getpeername returned < 0 : %s (%d)", + strerror(errno), errno); + } else { + strcpy(connCtxPtr->remoteAddr, ns_inet_ntoa(sa.sin_addr)); + connCtxPtr->remotePort = ntohl(sa.sin_port); + } } } else if (numRead == 0) { close(connCtxPtr->unix_sock);