rem: Ns_MutexUnlock(&lock); return NS_OK;
add: return (drvPtr->sock == INVALID_SOCKET ? NS_ERROR : NS_OK);
context: static Ns_Callback SockShutdown;static Ns_Callback SockReady;static Ns_ThreadProc SockThread;static void SockRelease(Conn *connPtr);static void SockTrigger(void);static Driver *firstDrvPtr;  /* First in list of all drivers. */static Conn *firstClosePtr; /* First conn ready for graceful close. */static Ns_Thread sockThread;/* Running SockThread. */static SOCKET trigPipe[2];  /* Trigger to wakeup SockThread select(). */static int shutdownPending; /* Flag to indicate shutdown. */static Ns_Mutex lock;	    /* Lock around close list and shutdown flag. */NS_EXPORT int Ns_ModuleVersion = 1;/* *---------------------------------------------------------------------- * * Ns_ModuleInit -- * *	Sock module init routine.  Each instance is added to the *	driver list after resolving the locaation, address, and port. * * Results: *	NS_OK if initialized ok, NS_ERROR otherwise. * * Side effects: *	Listen socket will be opened later in SockStart called by *	driver core. * *---------------------------------------------------------------------- */NS_EXPORT intNs_ModuleInit(char *server, char *name){    char *path,*address, *host, *bindaddr;    int n;    Ns_DString ds;    struct in_addr  ia;    struct hostent *he;    Driver *drvPtr;#ifdef SSL     char *cert, *key; #endif         path = Ns_ConfigGetPath(server, name, NULL);#ifdef SSL     /*     * Initialize the global and per-driver SSL.     */    if (NsSSLInitialize(server, name) != NS_OK) {         Ns_Log(Error, "%s: failed to initialize ssl driver", DRIVER_NAME);        return NS_ERROR;     }     cert = Ns_ConfigGet(path, "certfile");     if (cert == NULL) {         Ns_Log(Warning, "%s: certfile not specified", DRIVER_NAME);         return NS_OK;     } #ifdef SSL_EXPORT     n = 40;#else    n = 128;#endif    Ns_Log(Notice, "%s: initialized with %d-bit encryption", name, n);#endif         /*     * Determine the hostname used for the local address to bind     * to and/or the HTTP location string.     */    host = Ns_ConfigGet(path, "hostname");    bindaddr = address = Ns_ConfigGet(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 return 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: "		   "failed to resolve '%s': %s", DRIVER_NAME,		   name, host ? host : Ns_InfoHostname(), strerror(errno));	    return NS_ERROR;	}        if (*(he->h_addr_list) == NULL) {            Ns_Log(Error, "%s: failed to get address: "		   "null address list in (derived) host entry for '%s'",		   DRIVER_NAME, 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 loookups     * above, set it to the specified or derived IP address string.     */    if (host == NULL) {	host = address;    }    /*     * Allocate a new driver instance, initialize the SSL context,     * and set configurable parameters.     */    drvPtr = ns_calloc(1, sizeof(Driver));#ifdef SSL     key = Ns_ConfigGet(path, "keyfile");     drvPtr->dssl = NsSSLCreateServer(cert, key);     if (drvPtr->dssl == NULL) {         ns_free(drvPtr);         return NS_ERROR;     }     drvPtr->bufsize = 0;#else     if (!Ns_ConfigGetInt(path, "bufsize", &n) || n < 1) {         n = 16000;     }    drvPtr->bufsize = n;#endif     drvPtr->name = name;    if (!Ns_ConfigGetInt(path, "socktimeout", &n) || n < 1) {	n = 30;		/* NB: 30 seconds. */    }    drvPtr->timeout = n;    if (!Ns_ConfigGetInt(path, "closewait", &n) || n < 0) {	n = 2;		/* NB: 2 seconds */    }    drvPtr->closewait = 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 = DEFAULT_PORT;    }    if (!Ns_ConfigGetInt(path, "backlog", &drvPtr->backlog)) {	drvPtr->backlog = 5;    }    drvPtr->location = Ns_ConfigGet(path, "location");    if (drvPtr->location != NULL) {	drvPtr->location = ns_strdup(drvPtr->location);    } else {    	Ns_DStringInit(&ds);	Ns_DStringVarAppend(&ds, DEFAULT_PROTOCOL "://", host, NULL);	if (drvPtr->port != DEFAULT_PORT) {	    Ns_DStringPrintf(&ds, ":%d", drvPtr->port);	}	drvPtr->location = Ns_DStringExport(&ds);    }    /*     * Register the driver and add to the drivers list.     */    drvPtr->driver = Ns_RegisterDriver(server, name, sockProcs, drvPtr);    if (drvPtr->driver == NULL) {	return NS_ERROR;    }    if (firstDrvPtr == NULL) {	Ns_MutexSetName(&lock, DRIVER_NAME);	Ns_RegisterAtShutdown(SockShutdown, NULL);    }    drvPtr->nextPtr = firstDrvPtr;    firstDrvPtr = drvPtr;    return NS_OK;}/* *---------------------------------------------------------------------- * * SockStart -- * *	Listen on driver instance address/port and start SockThread *	if needed. * * Results: *	NS_OK or NS_ERROR if driver could not listen. * * Side effects: *	See SockThread. * *---------------------------------------------------------------------- */static intSockStart(char *server, char *label, void **drvDataPtr){    Driver *drvPtr = *((Driver **) drvDataPtr);    /*     * Create the listening socket and add to the Ports list.     */    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->address : "*",	    drvPtr->port, ns_sockstrerror(ns_sockerrno));	return NS_ERROR;    }    Ns_SockSetNonBlocking(drvPtr->sock);    /*     * Start the SockThread if necessary.     */    Ns_MutexLock(&lock);    if (sockThread == NULL) {	if (ns_sockpair(trigPipe) != 0) {	    Ns_Fatal("%s: ns_sockpair() failed: %s",		     DRIVER_NAME, ns_sockstrerror(ns_sockerrno));	}	Ns_ThreadCreate(SockThread, NULL, 0, &sockThread);	Ns_RegisterAtReady(SockReady, NULL);    }    Ns_MutexUnlock(&lock);    return NS_OK;}/* *---------------------------------------------------------------------- * * SockStop -- * *	Trigger the SockThread to begin shutdown.  This callback is *	invoked by the driver core at the begging of server shutdown. * * Results: *	None. * * Side effects: *	SockThread will close listen sockets and then exit after all *	outstanding connections are complete and closed. * *---------------------------------------------------------------------- */static voidSockStop(void *arg){    Ns_MutexLock(&lock);    if (sockThread != NULL && !shutdownPending) {    	Ns_Log(Notice, "%s: triggering shutdown", DRIVER_NAME);	shutdownPending = 1;	SockTrigger();    }    Ns_MutexUnlock(&lock);}/* *---------------------------------------------------------------------- * * SockReady -- * *	Trigger the SockThread to indicate the server is not longer *	busy. * * Results: *	None. * * Side effects: *	SockThread will wakeup and retry Ns_QueueConn if a connection *	is pending. * *---------------------------------------------------------------------- */static voidSockReady(void *arg){    Ns_MutexLock(&lock);    if (sockThread != NULL) {    	Ns_Log(Notice, "%s: server ready - resuming", DRIVER_NAME);	SockTrigger();    }    Ns_MutexUnlock(&lock);}/* *---------------------------------------------------------------------- * * SockShutdown -- * *	Wait for exit of SockThread.  This callback is invoke later by *	the timed shutdown thread. * * Results: *	None. * * Side effects: *	SSL context will be destroyed. * *---------------------------------------------------------------------- */static voidSockShutdown(void *arg){    Driver *drvPtr;    if (sockThread != NULL) {	Ns_ThreadJoin(&sockThread, NULL);	sockThread = NULL;	ns_sockclose(trigPipe[0]);	ns_sockclose(trigPipe[1]);    }    drvPtr = firstDrvPtr;    while (drvPtr != NULL) {#ifdef SSL         NsSSLDestroyServer(drvPtr->dssl); #endif	drvPtr = drvPtr->nextPtr;    }    Ns_Log(Notice, "%s: shutdown complete", DRIVER_NAME);}