rem: static int nfds;	     static int maxfds;
add: static unsigned int nfds;	 static unsigned int maxfds;
context: static Ns_ThreadProc DriverThread;static Sock *SockAccept(Driver *drvPtr);static void SockRelease(Sock *sockPtr);static void SockTrigger(void);static Driver *firstDrvPtr; /* First in list of all drivers. */static Sock *firstClosePtr; /* First conn ready for graceful close. */static int SockRead(Sock *sockPtr);static void SockPoll(Sock *sockPtr, Ns_Time *timeoutPtr);static void SockTimeout(Sock *sockPtr, Ns_Time *nowPtr, int timeout);static void MapServer(NsServer *servPtr, char *proto, char *host);static int  SetServer(Sock *sockPtr);/* * Static variables defined in this file. */static Request *firstReqPtr;/* Free list of request structures. */static Ns_Mutex reqLock;    /* Lock around request free list. */static Sock *firstSockPtr;  /* Free list of Sock structures. */static int shutdownPending; /* Flag to indicate shutdown. */static int stopped = 1;	    /* Flag to indicate running. */static int nactive;	    /* Active sockets. */static Ns_Thread driverThread;/* Running DriverThread. */static SOCKET trigPipe[2];  /* Trigger to wakeup DriverThread. */static Ns_Mutex lock;	    /* Lock around close list and shutdown flag. */static Ns_Cond cond;	    /* Cond for stopped flag. */static int nfds;	    /* Number of Sock to poll(). */static int maxfds;	    /* Max pollfd's in pfds. */ static struct pollfd *pfds; /* Array of pollfds to poll(). */static Tcl_HashTable hosts; /* Host header to server table. *//* *---------------------------------------------------------------------- * * NsInitDrivers -- * *	Init drivers system. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidNsInitDrivers(void){    Tcl_InitHashTable(&hosts, TCL_STRING_KEYS);}/* *---------------------------------------------------------------------- * * Ns_DriverInit -- * *	Initialize a driver. * * Results: *	NS_OK if initialized, NS_ERROR if config or other error. * * Side effects: *	Listen socket will be opened later in NsStartDrivers. * *---------------------------------------------------------------------- */intNs_DriverInit(char *server, char *module, char *name,	      Ns_DriverProc *proc, void *arg, int opts){    char *path,*address, *host, *bindaddr, *defproto;    int i, n, sockwait, defport;    Ns_DString ds;    Ns_Set *set;    struct in_addr  ia;    struct hostent *he;    Driver *drvPtr;    NsServer *servPtr = NULL;    if (server != NULL && (servPtr = NsGetServer(server)) == NULL) {	return NS_ERROR;    }    path = Ns_ConfigGetPath(server, module, NULL);    /*     * Determine the hostname used for the local address to bind     * to and/or the HTTP location string.     */    host = Ns_ConfigGetValue(path, "hostname");    bindaddr = address = Ns_ConfigGetValue(path, "address");    /*     * If the listen address was not specified, attempt to determine it     * through a DNS lookup of the specified hostname or the server's     * primary hostname.     */    if (address == NULL) {        he = gethostbyname(host ? host : Ns_InfoHostname());        /*	 * If the lookup suceeded but the resulting hostname does not	 * appear to be fully qualified, attempt a reverse lookup on the	 * address which often returns the fully qualified name.	 *	 * NB: This is a common but sloppy configuration for a Unix	 * network.	 */        if (he != NULL && he->h_name != NULL &&	    strchr(he->h_name, '.') == NULL) {            he = gethostbyaddr(he->h_addr, he->h_length, he->h_addrtype);	}	/*	 * If the lookup suceeded, use the first address in host entry list.	 */        if (he == NULL || he->h_name == NULL) {            Ns_Log(Error, "%s: could not resolve %s: %s", module,		   host ? host : Ns_InfoHostname(), strerror(errno));	    return NS_ERROR;	}        if (*(he->h_addr_list) == NULL) {            Ns_Log(Error, "%s: no addresses for %s", module, he->h_name);	    return NS_ERROR;	}        memcpy(&ia.s_addr, *(he->h_addr_list), sizeof(ia.s_addr));        address = ns_inet_ntoa(ia);	/*	 * Finally, if no hostname was specified, set it to the hostname	 * derived from the lookup(s) above.	 */ 	if (host == NULL) {	    host = he->h_name;	}    }    /*     * If the hostname was not specified and not determined by the lookup     * above, set it to the specified or derived IP address string.     */    if (host == NULL) {	host = address;    }    /*     * Set the protocol and port defaults.     */    if (opts & NS_DRIVER_SSL) {	defproto = "https";	defport = 443;    } else {	defproto = "http";	defport = 80;    }    /*     * Allocate a new driver instance and set configurable parameters.     */    drvPtr = ns_calloc(1, sizeof(Driver));    drvPtr->server = server;    drvPtr->name = name;    drvPtr->proc = proc;    drvPtr->arg = arg;    drvPtr->opts = opts;    drvPtr->servPtr = servPtr;    if (!Ns_ConfigGetInt(path, "bufsize", &n) || n < 1) {         n = 16000; 	/* ~16k */    }    drvPtr->bufsize = n;    if (!Ns_ConfigGetInt(path, "rcvbuf", &n)) {	n = 0;		/* Use OS default. */    }    drvPtr->rcvbuf = n;    if (!Ns_ConfigGetInt(path, "sndbuf", &n)) {	n = 0;		/* Use OS default. */    }    drvPtr->sndbuf = n;    if (!Ns_ConfigGetInt(path, "socktimeout", &n) || n < 1) {	n = 30;		/* 30 seconds. */    }    sockwait = n;    if (!Ns_ConfigGetInt(path, "sendwait", &n) || n < 1) {	n = sockwait; /* Use previous socktimeout option. */    }    drvPtr->sendwait = n;    if (!Ns_ConfigGetInt(path, "recvwait", &n) || n < 1) {	n = sockwait; /* Use previous socktimeout option. */    }    drvPtr->recvwait = n;    if (!Ns_ConfigGetInt(path, "closewait", &n) || n < 0) {	n = 2;		/* 2 seconds */    }    drvPtr->closewait = n;    if (!Ns_ConfigGetInt(path, "keepwait", &n) || n < 0) {	n = 30;		/* 30 seconds */    }    drvPtr->keepwait = n;    if (!Ns_ConfigGetInt(path, "backlog", &n) || n < 1) {	n = 5;		/* 5 pending connections. */    }    drvPtr->backlog = n;    /*     * Determine the port and then set the HTTP location string either     * as specified in the config file or constructed from the     * hostname and port.     */    drvPtr->bindaddr = bindaddr;    drvPtr->address = ns_strdup(address);    if (!Ns_ConfigGetInt(path, "port", &drvPtr->port)) {	drvPtr->port = defport;    }    drvPtr->location = Ns_ConfigGetValue(path, "location");    if (drvPtr->location != NULL) {	drvPtr->location = ns_strdup(drvPtr->location);    } else {    	Ns_DStringInit(&ds);	Ns_DStringVarAppend(&ds, defproto, "://", host, NULL);	if (drvPtr->port != defport) {	    Ns_DStringPrintf(&ds, ":%d", drvPtr->port);	}	drvPtr->location = Ns_DStringExport(&ds);    }    drvPtr->nextPtr = firstDrvPtr;    firstDrvPtr = drvPtr;    ++maxfds;    /*     * Map Host headers for drivers not bound to servers.     */    if (server == NULL) {	path = Ns_ConfigGetPath(NULL, module, "servers", NULL);	set = Ns_ConfigGetSection(path);	for (i = 0; set != NULL && i < Ns_SetSize(set); ++i) {	    servPtr = NsGetServer(Ns_SetKey(set, i));	    if (servPtr != NULL) {		MapServer(servPtr, defproto, Ns_SetValue(set, i));	    }	}    }    return NS_OK;}/* *---------------------------------------------------------------------- * * Ns_RegisterDriver -- * *	Register a set of communications driver procs (no longer *	supported). * * Results: *	NULL. * * Side effects: *	None. * *---------------------------------------------------------------------- */void *Ns_RegisterDriver(char *server, char *label, void *procs, void *drvData){    Ns_Log(Error, "driver: loadable drivers no longer supported");    return NULL;}/* *---------------------------------------------------------------------- * * Ns_GetDriverContext -- * *	Return the driver's context (no longer supported) * * Results: *	NULL.  * * Side effects: *	None  * *---------------------------------------------------------------------- */void *Ns_GetDriverContext(Ns_Driver drv){    return NULL;}/* *---------------------------------------------------------------------- * * NsStartDrivers -- * *	Listen on all driver address/ports and start the DriverThread. * * Results: *	None. * * Side effects: *	See DriverThread. * *---------------------------------------------------------------------- */voidNsStartDrivers(void){    Driver *drvPtr;    /*     * Listen on all drivers.     */    drvPtr = firstDrvPtr;    while (drvPtr != NULL) {	drvPtr->sock = Ns_SockListenEx(drvPtr->bindaddr, drvPtr->port,	    drvPtr->backlog);	if (drvPtr->sock == INVALID_SOCKET) {	    Ns_Log(Error, "%s: failed to listen on %s:%d: %s",		drvPtr->name, drvPtr->address, drvPtr->port,		ns_sockstrerror(ns_sockerrno));	} else {    	    Ns_SockSetNonBlocking(drvPtr->sock);    	    Ns_Log(Notice, "%s: listening on %s:%d",		drvPtr->name, drvPtr->address, drvPtr->port);	}	drvPtr = drvPtr->nextPtr;    }    /*     * Create the socket thread.     */    if (ns_sockpair(trigPipe) != 0) {	Ns_Fatal("driver: ns_sockpair() failed: %s",	    ns_sockstrerror(ns_sockerrno));    }    Ns_ThreadCreate(DriverThread, NULL, 0, &driverThread);}/* *---------------------------------------------------------------------- * * NsStopDrivers -- * *	Trigger the DriverThread to begin shutdown. * * Results: *	None. * * Side effects: *	DriverThread will close listen sockets and then exit after all *	outstanding connections are complete and closed. * *---------------------------------------------------------------------- */voidNsStopDrivers(void){    Ns_MutexLock(&lock);    if (!stopped && !shutdownPending) {    	Ns_Log(Notice, "driver: triggering shutdown");	shutdownPending = 1;	SockTrigger();    }    Ns_MutexUnlock(&lock);}/* *---------------------------------------------------------------------- * * NsWaitDriversShutdown -- * *	Wait for exit of DriverThread.  This callback is invoke later by *	the timed shutdown thread. * * Results: *	None. * * Side effects: *	Driver thread is joined and trigger pipe closed. * *---------------------------------------------------------------------- */voidNsWaitDriversShutdown(Ns_Time *toPtr){    int status = NS_OK;    Ns_MutexLock(&lock);    while (!stopped && status == NS_OK) {	status = Ns_CondTimedWait(&cond, &lock, toPtr);    }    Ns_MutexUnlock(&lock);    if (status != NS_OK) {	Ns_Log(Warning, "driver: timeout waiting for shutdown");    } else {	Ns_Log(Notice, "driver: shutdown complete");	Ns_ThreadJoin(&driverThread, NULL);	driverThread = NULL;	ns_sockclose(trigPipe[0]);	ns_sockclose(trigPipe[1]);    }}/*  *---------------------------------------------------------------------- * * NsGetRequest -- * *	Return the request buffer, reading it if necessary (i.e., if *	not an async read-ahead connection).  This function is called *	at the start of connection processing. * * Results: *	Pointer to Request structure or NULL on error. * * Side effects: *	May wait for content to arrive if necessary. * *---------------------------------------------------------------------- */Request *NsGetRequest(Sock *sockPtr){    Request *reqPtr;    int status;    if (sockPtr->reqPtr == NULL) {	do {	    status = SockRead(sockPtr);	} while (status == SOCK_MORE);	if (status != SOCK_READY) {	    if (sockPtr->reqPtr != NULL) {		NsFreeRequest(sockPtr->reqPtr);	    }	    sockPtr->reqPtr = NULL;	}    }    reqPtr = sockPtr->reqPtr;    /* NB: Sock no longer responsible for freeing request. */    sockPtr->reqPtr = NULL;    return reqPtr;}/*  *---------------------------------------------------------------------- * * NsFreeRequest -- * *	Free a connection request structure.  This routine is called *	at the end of connection processing or on a socket which *	times out during async read-ahead. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidNsFreeRequest(Request *reqPtr){    reqPtr->next = reqPtr->content = NULL;    reqPtr->length = reqPtr->avail = 0;    reqPtr->coff = reqPtr->woff = reqPtr->roff = 0;    Tcl_DStringFree(&reqPtr->buffer);    Ns_SetTrunc(reqPtr->headers, 0);    Ns_FreeRequest(reqPtr->request);    reqPtr->request = NULL;    Ns_MutexLock(&reqLock);    reqPtr->nextPtr = firstReqPtr;    firstReqPtr = reqPtr;    Ns_MutexUnlock(&reqLock);}/*  *---------------------------------------------------------------------- * * NsSockSend -- * *	Send buffers via the socket's driver callback. * * Results: *	# of bytes sent or -1 on error. * * Side effects: *	Depends on driver proc. * *---------------------------------------------------------------------- */intNsSockSend(Sock *sockPtr, struct iovec *bufs, int nbufs){    Ns_Sock *sock = (Ns_Sock *) sockPtr;    return (*sockPtr->drvPtr->proc)(DriverSend, sock, bufs, nbufs);}/*  *---------------------------------------------------------------------- * * NsSockClose -- * *	Return a connction to the DriverThread for closing or keepalive. * * Results: *	None. * * Side effects: *	Socket may be reused by a keepalive connection. * *---------------------------------------------------------------------- */voidNsSockClose(Sock *sockPtr, int keep){    Ns_Sock *sock = (Ns_Sock *) sockPtr;    int trigger = 0;    if (keep && (*sockPtr->drvPtr->proc)(DriverKeep, sock, NULL, 0) != 0) {	keep = 0;    }    if (!keep) {	(void) (*sockPtr->drvPtr->proc)(DriverClose, sock, NULL, 0);    }    sockPtr->keep = keep;    Ns_MutexLock(&lock);    if (firstClosePtr == NULL) {	trigger = 1;    }    sockPtr->keep = keep;    sockPtr->nextPtr = firstClosePtr;    firstClosePtr = sockPtr;    Ns_MutexUnlock(&lock);    if (trigger) {	SockTrigger();    }}/* *---------------------------------------------------------------------- * * DriverThread -- * *	Main listening socket driver thread. * * Results: *	None. * * Side effects: *	Connections are accepted on the configured listen sockets, *	placed on the run queue to be serviced, and gracefully *	closed when done.  Async sockets have the entire request read *	here before queuing as well. * *---------------------------------------------------------------------- */static voidDriverThread(void *ignored){    char c;    int n, stopping, pollto;    Sock *sockPtr, *closePtr, *nextPtr, *waitPtr, *readPtr;    Driver *activeDrvPtr;    Driver *drvPtr, *nextDrvPtr, *idleDrvPtr, *acceptDrvPtr;    char drain[1024];    Ns_Time timeout, now, diff;        Ns_ThreadSetName("-driver-");    Ns_Log(Notice, "starting");    /*     * Build up the list of active drivers.     */    activeDrvPtr = NULL;    drvPtr = firstDrvPtr;    firstDrvPtr = NULL;    while (drvPtr != NULL) {	nextDrvPtr = drvPtr->nextPtr;	if (drvPtr->sock != INVALID_SOCKET) {	    drvPtr->nextPtr = activeDrvPtr;	    activeDrvPtr = drvPtr;	} else {	    drvPtr->nextPtr = firstDrvPtr;	    firstDrvPtr = drvPtr;	}	drvPtr = nextDrvPtr;    }    /*     * Loop forever until signalled to shutdown and all     * connections are complete and gracefully closed.     */    Ns_Log(Notice, "driver: accepting connections");    closePtr = waitPtr = readPtr = NULL;    Ns_GetTime(&now);    stopping = 0;    maxfds += 100;    pfds = ns_malloc(sizeof(struct pollfd) * maxfds);    pfds[0].fd = trigPipe[0];    pfds[0].events = POLLIN;    while (!stopping || nactive) {	/*	 * Set the bits for all active drivers if a connection	 * isn't already pending.	 */	nfds = 1;	if (waitPtr == NULL) {    	    drvPtr = activeDrvPtr;	    while (drvPtr != NULL) {		pfds[nfds].fd = drvPtr->sock;		pfds[nfds].events = POLLIN;		drvPtr->pidx = nfds++;		drvPtr = drvPtr->nextPtr;	    }	}	/*	 * If there are any closing or read-ahead sockets, set the bits	 * and determine the minimum relative timeout.	 */	if (readPtr == NULL && closePtr == NULL) {	    pollto = -1;	} else {	    timeout.sec = INT_MAX;	    timeout.usec = LONG_MAX;	    sockPtr = readPtr;	    while (sockPtr != NULL) {		SockPoll(sockPtr, &timeout);		sockPtr = sockPtr->nextPtr;	    }	    sockPtr = closePtr;	    while (sockPtr != NULL) {		SockPoll(sockPtr, &timeout);		sockPtr = sockPtr->nextPtr;	    }	    if (Ns_DiffTime(&timeout, &now, &diff) > 0)  {		pollto = diff.sec * 1000 + diff.usec / 1000;	    } else {		pollto = 0;	    }	}	/*	 * Select and drain the trigger pipe if necessary.	 */    	pfds[0].revents = 0;	do {	    n = poll(pfds, nfds, pollto);	} while (n < 0  && errno == EINTR);	if (n < 0) {	    Ns_Fatal("driver: poll() failed: %s",		ns_sockstrerror(ns_sockerrno));	}	if ((pfds[0].revents & POLLIN) && recv(trigPipe[0], &c, 1, 0) != 1) {	    Ns_Fatal("driver: trigger recv() failed: %s",            ns_sockstrerror(ns_sockerrno));	}	/*	 * Update the current time and drain and/or release any	 * closing sockets.	 */	Ns_GetTime(&now);	if (closePtr != NULL) {	    sockPtr = closePtr;	    closePtr = NULL;	    while (sockPtr != NULL) {		nextPtr = sockPtr->nextPtr;		if (pfds[sockPtr->pidx].revents & POLLIN) {		    n = recv(sockPtr->sock, drain, sizeof(drain), 0);		    if (n <= 0) {			sockPtr->timeout = now;		    }		}		if (Ns_DiffTime(&sockPtr->timeout, &now, &diff) <= 0) {		    SockRelease(sockPtr);		} else {		    sockPtr->nextPtr = closePtr;		    closePtr = sockPtr;		}		sockPtr = nextPtr;	    }	}	/*	 * Attempt read-ahead of any new connections.	 */	sockPtr = readPtr;	readPtr = NULL;	while (sockPtr != NULL) {	    nextPtr = sockPtr->nextPtr;	    if (!(pfds[sockPtr->pidx].revents & POLLIN)) {		if (Ns_DiffTime(&sockPtr->timeout, &now, &diff) <= 0) {		    SockRelease(sockPtr);		} else {		    sockPtr->nextPtr = readPtr;		    readPtr = sockPtr;		}	    } else {		/*		 * If enabled, perform read-ahead now.		 */		sockPtr->keep = 0;		if (sockPtr->drvPtr->opts & NS_DRIVER_ASYNC) {		    n = SockRead(sockPtr);		} else {		    n = SOCK_READY;		}		/*		 * Queue for connection processing if ready.		 */		switch (n) {		case SOCK_MORE:		    SockTimeout(sockPtr, &now, sockPtr->drvPtr->recvwait);		    sockPtr->nextPtr = readPtr;		    readPtr = sockPtr;		    break;		case SOCK_READY:		    if (!SetServer(sockPtr)) {			SockRelease(sockPtr);		    } else {		    	sockPtr->nextPtr = waitPtr;			waitPtr = sockPtr;		    }		    break;		default:		    SockRelease(sockPtr);		    break;		}	    }	    sockPtr = nextPtr;	}	/*	 * Attempt to queue any pending connection	 * after reversing the list to ensure oldest	 * connections are tried first.	 */	if (waitPtr != NULL) {	    sockPtr = NULL;	    while ((nextPtr = waitPtr) != NULL) {		waitPtr = nextPtr->nextPtr;		nextPtr->nextPtr = sockPtr;		sockPtr = nextPtr;	    }	    while (sockPtr != NULL) {		nextPtr = sockPtr->nextPtr;		if (waitPtr != NULL || !NsQueueConn(sockPtr, &now)) {		    sockPtr->nextPtr = waitPtr;		    waitPtr = sockPtr;		}		sockPtr = nextPtr;	    }	}	/*	 * If no connections are waiting, attempt to accept more.	 */  	if (waitPtr == NULL) {	    drvPtr = activeDrvPtr;	    activeDrvPtr = idleDrvPtr = acceptDrvPtr = NULL;	    while (drvPtr != NULL) {		nextDrvPtr = drvPtr->nextPtr;		if (waitPtr != NULL	    		|| (!(pfds[drvPtr->pidx].revents & POLLIN))			|| ((sockPtr = SockAccept(drvPtr)) == NULL)) {		    /*		     * Add this driver to the temporary idle list.		     */		    drvPtr->nextPtr = idleDrvPtr;		    idleDrvPtr = drvPtr;		} else {		    /*		     * Add this driver to the temporary accepted list.		     */		    drvPtr->nextPtr = acceptDrvPtr;		    acceptDrvPtr = drvPtr;		    /*		     * Put the socket on the read-ahead list.		     */		    SockTimeout(sockPtr, &now, sockPtr->drvPtr->recvwait);		    sockPtr->nextPtr = readPtr;		    readPtr = sockPtr;		}		drvPtr = nextDrvPtr;	    }	    /*	     * Put the active driver list back together with the idle	     * drivers first but otherwise in the original order.  This	     * should ensure round-robin service of the drivers.	     */	    while ((drvPtr = acceptDrvPtr) != NULL) {		acceptDrvPtr = drvPtr->nextPtr;		drvPtr->nextPtr = activeDrvPtr;		activeDrvPtr = drvPtr;	    }	    while ((drvPtr = idleDrvPtr) != NULL) {		idleDrvPtr = drvPtr->nextPtr;		drvPtr->nextPtr = activeDrvPtr;		activeDrvPtr = drvPtr;	    }	}	/*	 * Check for shutdown and get the list of any closing or	 * keepalive sockets.	 */	Ns_MutexLock(&lock);	sockPtr = firstClosePtr;	firstClosePtr = NULL;	stopping = shutdownPending;	Ns_MutexUnlock(&lock);	/*	 * Update the timeout for each closing socket and add to the	 * close list if some data has been read from the socket	 * (i.e., it's not a closing keep-alive connection).	 */	while (sockPtr != NULL) {	    nextPtr = sockPtr->nextPtr;	    if (sockPtr->keep) {		SockTimeout(sockPtr, &now, sockPtr->drvPtr->keepwait);		sockPtr->nextPtr = readPtr;		readPtr = sockPtr;	    } else {		if (shutdown(sockPtr->sock, 1) != 0) {		    SockRelease(sockPtr);		} else {		    SockTimeout(sockPtr, &now, sockPtr->drvPtr->closewait);		    sockPtr->nextPtr = closePtr;		    closePtr = sockPtr;		}	    }	    sockPtr = nextPtr;	}	/*	 * Close the active drivers if shutdown is pending.	 */	if (stopping) {	    while ((drvPtr = activeDrvPtr) != NULL) {		activeDrvPtr = drvPtr->nextPtr;		ns_sockclose(drvPtr->sock);		drvPtr->sock = INVALID_SOCKET;		drvPtr->nextPtr = firstDrvPtr;		firstDrvPtr = drvPtr;	    }	}    }    Ns_Log(Notice, "exiting");    Ns_MutexLock(&lock);    stopped = 1;    Ns_CondBroadcast(&cond);    Ns_MutexUnlock(&lock);}