rem: drvPtr->name, drvPtr->address ? drvPtr->address : "*", drvPtr->port, ns_sockstrerror(ns_sockerrno)); return NS_ERROR; } Ns_SockSetNonBlocking(drvPtr->sock);
add: drvPtr->name, drvPtr->address, drvPtr->port, ns_sockstrerror(ns_sockerrno)); } else { Ns_Log(Notice, "%s: listening on %s:%d", drvPtr->name, drvPtr->address, drvPtr->port); Ns_SockSetNonBlocking(drvPtr->sock); }
context: static Ns_ConnPortProc SockPort;static Ns_ConnHostProc SockHost;static Ns_ConnDriverNameProc SockName;static Ns_ConnInitProc SockInit; #ifdef HAVE_SENDVstatic Ns_ConnSendFdProc SockSendFd;#endif/* * Driver structure passed to Ns_RegisterDriver. */static Ns_DrvProc sockProcs[] = {    {Ns_DrvIdStart,        (void *) SockStart},    {Ns_DrvIdStop,         (void *) SockStop},    {Ns_DrvIdRead,         (void *) SockRead},    {Ns_DrvIdWrite,        (void *) SockWrite},    {Ns_DrvIdClose,        (void *) SockClose},    {Ns_DrvIdHost,         (void *) SockHost},    {Ns_DrvIdPort,         (void *) SockPort},    {Ns_DrvIdName,         (void *) SockName},    {Ns_DrvIdPeer,         (void *) SockPeer},    {Ns_DrvIdPeerPort,     (void *) SockPeerPort},    {Ns_DrvIdLocation,     (void *) SockLocation},    {Ns_DrvIdConnectionFd, (void *) SockConnectionFd},    {Ns_DrvIdDetach,       (void *) SockDetach},    {Ns_DrvIdInit,         (void *) SockInit}, #ifdef HAVE_SENDV    {Ns_DrvIdSendFd,       (void *) SockSendFd},#endif    {0,                    NULL}};/* * Static functions and variables defined in this file. */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);}/* *---------------------------------------------------------------------- * * SockThread -- * *	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. * *---------------------------------------------------------------------- */static intSockQueue(Conn *connPtr){    if (Ns_QueueConn(connPtr->drvPtr->driver, connPtr) != NS_OK) {	return 0;    }    return 1;}static intSockAccept(SOCKET lsock, SOCKET *sockPtr, struct sockaddr_in *saPtr){    SOCKET sock;    int slen;    slen = sizeof(struct sockaddr_in);    sock = Ns_SockAccept(lsock, (struct sockaddr *) saPtr, &slen);    if (sock == INVALID_SOCKET) {	return 0;    }    *sockPtr = sock;    return 1;}static voidSockThread(void *ignored){    fd_set set;    char c;    int n, nactive, stopping;    Conn *connPtr, *closePtr, *nextPtr, *waitPtr;    Driver *activeDrvPtr;    Driver *drvPtr, *nextDrvPtr, *idleDrvPtr, *acceptDrvPtr;    struct sockaddr_in sa;    SOCKET max, sock;    time_t now, timeout;    struct timeval tv, *tvPtr;    char drain[1024];        Ns_ThreadSetName("-" DRIVER_NAME "-");    Ns_Log(Notice, "%s: waiting for startup", DRIVER_NAME);    Ns_WaitForStartup();    Ns_Log(Notice, "%s: starting", DRIVER_NAME);    /*     * 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, "%s: accepting connections", DRIVER_NAME);    nactive = 0;    closePtr = waitPtr = NULL;    time(&now);    while (activeDrvPtr || nactive || closePtr || waitPtr) {	/*	 * Set trigger pipe bit.	 */	FD_ZERO(&set);	FD_SET(trigPipe[0], &set);	max = trigPipe[0];	/*	 * Set the bits for all active drivers if a connection	 * isn't already pending.	 */	if (waitPtr == NULL) {    	    drvPtr = activeDrvPtr;	    while (drvPtr != NULL) {		FD_SET(drvPtr->sock, &set);		if (max < drvPtr->sock) {		    max = drvPtr->sock;		}		drvPtr = drvPtr->nextPtr;	    }	}	/*	 * If there are any closing sockets, set the bits	 * and determine the minimum relative timeout.	 */	if (closePtr == NULL) {	    tvPtr = NULL;	} else {	    timeout = INT_MAX;	    connPtr = closePtr;	    while (connPtr != NULL) {		FD_SET(connPtr->sock, &set);		if (max < connPtr->sock) {		    max = connPtr->sock;		}		if (timeout > connPtr->timeout) {		    timeout = connPtr->timeout;		}		connPtr = connPtr->nextPtr;	    }	    if (timeout > now) {		tv.tv_sec = (int) timeout - now;	    } else {		tv.tv_sec = 0;	    }	    tv.tv_usec = 0;	    tvPtr = &tv;	}	/*	 * Select and drain the trigger pipe if necessary.	 */	do {	    n = select(max+1, &set, NULL, NULL, tvPtr);	} while (n < 0  && ns_sockerrno == EINTR);	if (n < 0) {	    Ns_Fatal("%s: select() failed: %s", DRIVER_NAME,		ns_sockstrerror(ns_sockerrno));	}	if (FD_ISSET(trigPipe[0], &set) && recv(trigPipe[0], &c, 1, 0) != 1) {	    Ns_Fatal("%s: trigger recv() failed: %s", DRIVER_NAME,		ns_sockstrerror(ns_sockerrno));	}	/*	 * Update the current time and drain and/or release any	 * closing sockets.	 */	time(&now);	if (closePtr != NULL) {	    connPtr = closePtr;	    closePtr = NULL;	    while (connPtr != NULL) {		nextPtr = connPtr->nextPtr;		if (FD_ISSET(connPtr->sock, &set)) {		    n = recv(connPtr->sock, drain, sizeof(drain), 0);		    if (n <= 0) {			connPtr->timeout = now;		    }		}		if (connPtr->timeout <= now) {		    SockRelease(connPtr);		} else {		    connPtr->nextPtr = closePtr;		    closePtr = connPtr;		}		connPtr = nextPtr;	    }	}		/*	 * Attempt to queue any pending connection.  Otherwise,	 * accept new connections as long as they can be queued.	 */	if (waitPtr != NULL) {	    if (SockQueue(waitPtr)) {		waitPtr = NULL;		++nactive;	    }	} else {	    drvPtr = activeDrvPtr;	    activeDrvPtr = idleDrvPtr = acceptDrvPtr = NULL;	    while (drvPtr != NULL) {		nextDrvPtr = drvPtr->nextPtr;		if (waitPtr != NULL			|| !FD_ISSET(drvPtr->sock, &set)			|| !SockAccept(drvPtr->sock, &sock, &sa)) {		    /*		     * Add this port to the temporary idle list.		     */		    drvPtr->nextPtr = idleDrvPtr;		    idleDrvPtr = drvPtr;		} else {		    /*		     * Add this port to the temporary accepted list.		     */		    drvPtr->nextPtr = acceptDrvPtr;		    acceptDrvPtr = drvPtr;		    /*		     * Allocate and/or initialize a connection structure.		     */		    connPtr = drvPtr->firstFreeConnPtr;		    if (connPtr != NULL) {			drvPtr->firstFreeConnPtr = connPtr->nextPtr;		    } else {			connPtr = ns_malloc(sizeof(Conn) + drvPtr->bufsize);			connPtr->drvPtr = drvPtr;		    }		    connPtr->nextPtr = NULL;		    connPtr->sock = sock;		    connPtr->nrecv = connPtr->nsend = 0;#ifdef SSL		    connPtr->cssl = NULL; #else 		    connPtr->cnt = 0;		    connPtr->base = connPtr->buf;#endif		    connPtr->port = ntohs(sa.sin_port);		    strcpy(connPtr->peer, ns_inet_ntoa(sa.sin_addr));		    /*		     * Even though the socket should have inherited		     * non-blocking from the accept socket, set again		     * just to be sure.		     */		    Ns_SockSetNonBlocking(connPtr->sock);		    /*		     * Attempt to queue the socket, holding it if		     * necessary to try again later.		     */		    if (!SockQueue(connPtr)) {			waitPtr = connPtr;		    } else {			++nactive;		    }		}		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 sockets.	 */	Ns_MutexLock(&lock);	connPtr = 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 (connPtr != NULL) {	    nextPtr = connPtr->nextPtr;	    --nactive;	    if (connPtr->nrecv == 0 || shutdown(connPtr->sock, 1) != 0) {		SockRelease(connPtr);	    } else {		connPtr->nextPtr = closePtr;		closePtr = connPtr;		connPtr->timeout = now + connPtr->drvPtr->closewait;	    }	    connPtr = 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");}/* *---------------------------------------------------------------------- * * SockRelease -- * *	Close a socket and release the connection structure for *	re-use. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */static voidSockRelease(Conn *connPtr){    ns_sockclose(connPtr->sock);    connPtr->sock = INVALID_SOCKET;    connPtr->nextPtr = connPtr->drvPtr->firstFreeConnPtr;    connPtr->drvPtr->firstFreeConnPtr = connPtr;}/* *---------------------------------------------------------------------- * * SockTrigger -- * *	Wakeup SockThread from blocking select(). * * Results: *	None. * * Side effects: *	SockThread will wakeup. * *---------------------------------------------------------------------- */static voidSockTrigger(void){    if (send(trigPipe[1], "", 1, 0) != 1) {	Ns_Fatal("%s: trigger send() failed: %s", DRIVER_NAME,	    ns_sockstrerror(ns_sockerrno));    }}/*  *----------------------------------------------------------------------  *  * SockInit --  *  *      Initialize the SSL connection.  *  * Results:  *      NS_OK/NS_ERROR  *  * Side effects:  *	See NsSSLCreateConn. *  *----------------------------------------------------------------------  */ static int SockInit(void *arg) {     Conn   *connPtr = arg;  #ifdef SSL     if (connPtr->cssl == NULL) {         connPtr->cssl = NsSSLCreateConn(connPtr->sock,			    connPtr->drvPtr->timeout,			    connPtr->drvPtr->dssl);         if (connPtr->cssl == NULL) {             return NS_ERROR;         }     } #endif    return NS_OK; }/*  *---------------------------------------------------------------------- * * SockClose -- * *	Return a connction to the SockThread for closing. * * Results: *	NS_OK * * Side effects: *	SSL conn will be flushed and then destroyed. * *---------------------------------------------------------------------- */static intSockClose(void *arg){    Conn *connPtr = arg;    int trigger = 0;    #ifdef SSL     if (connPtr->cssl != NULL) {         (void) NsSSLFlush(connPtr->cssl);         NsSSLDestroyConn(connPtr->cssl);         connPtr->cssl = NULL;    }#endif    Ns_MutexLock(&lock);    if (firstClosePtr == NULL) {	trigger = 1;    }    connPtr->nextPtr = firstClosePtr;    firstClosePtr = connPtr;    Ns_MutexUnlock(&lock);    if (trigger) {	SockTrigger();    }    return NS_OK;}/* *---------------------------------------------------------------------- * * SockRead -- * *	Read from the socket  * *	NB: May block waiting for requested number of bytes! * * Results: *	Number of bytes read or -1 on timeout or error. * * Side effects: *	Either reads through SSL code or through socket buffer. * *---------------------------------------------------------------------- */static intSockRead(void *arg, void *vbuf, int len){    Conn   *connPtr = arg;    int	    nread;#ifdef SSL     nread = NsSSLRecv(connPtr->cssl, vbuf, len);#else     char       *buf = (char *) vbuf;    int         n;        nread = len;    while (len > 0) {        if (connPtr->cnt > 0) {	    /*	     * Copy bytes already in read-ahead buffer.	     */            if (connPtr->cnt > len) {                n = len;            } else {                n = connPtr->cnt;            }            memcpy(buf, connPtr->base, n);            connPtr->base += n;            connPtr->cnt -= n;            len -= n;            buf += n;        }        if (len > 0) {	    /*	     * Attempt to fill the read-ahead buffer.	     */            connPtr->base = connPtr->buf;	    connPtr->cnt = Ns_SockRecv(connPtr->sock, connPtr->buf,		connPtr->drvPtr->bufsize, connPtr->drvPtr->timeout);	    if (connPtr->cnt <= 0) {		return -1;	    }    	}    }#endif    if (nread > 0) {	connPtr->nrecv += nread;    }    return nread;}/* *---------------------------------------------------------------------- * * SockWrite -- * *	Writes data to a socket. * *	NB: May block waiting to send requested number of bytes! * * Results: *	Number of bytes written or -1 for timeout or error. * * Side effects: *	Bytes may be written to a socket * *---------------------------------------------------------------------- */static intSockWrite(void *arg, void *vbuf, int len){    Conn   *connPtr = arg;    int	    nwrote;#ifdef SSL     nwrote = NsSSLSend(connPtr->cssl, vbuf, len); #else    int     n;    char   *buf;    nwrote = len;    buf = vbuf;    while (len > 0) {	n = Ns_SockSend(connPtr->sock, buf, len,	    connPtr->drvPtr->timeout);	if (n < 0) {	    return -1;	}	len -= n;	buf += n;    }#endif    if (nwrote > 0) {	connPtr->nsend += nwrote;    }    return nwrote;}/* *---------------------------------------------------------------------- * * SockHost -- * *	Return the host (addr) I'm bound to  * * Results: *	String hostname  * * Side effects: *	None  * *---------------------------------------------------------------------- */static char *SockHost(void *arg){    Conn   *connPtr = arg;    return connPtr->drvPtr->address;}/* *---------------------------------------------------------------------- * * SockPort -- * *	Get the port I'm listening on. * * Results: *	A TCP port number  * * Side effects: *	None  * *---------------------------------------------------------------------- */static intSockPort(void *arg){    Conn   *connPtr = arg;    return connPtr->drvPtr->port;}