rem: ListenData          *ldPtr;
context: static Ns_SockProc  ListenCallback; /* * Static variables defined in this file */static Tcl_HashTable portsTable;      /* Table of per-port data. */static Ns_Mutex      lock;            /* Lock around portsTable. *//* *---------------------------------------------------------------------- * * NsInitListen -- * *	Initialize listen callback API. * * Results: *	None. * * Side effects: *	None.  * *---------------------------------------------------------------------- */voidNsInitListen(void){    Ns_MutexInit(&lock);    Ns_MutexSetName(&lock, "ns:listencallbacks");    Tcl_InitHashTable(&portsTable, TCL_ONE_WORD_KEYS);}/* *---------------------------------------------------------------------- * * Ns_SockListenCallback -- * *	Listen on an address/port and register a callback to be run  *	when connections come in on it.  * * Results: *	NS_OK/NS_ERROR  * * Side effects: *	None.  * *---------------------------------------------------------------------- */intNs_SockListenCallback(char *addr, int port, Ns_SockProc *proc, void *arg){    Tcl_HashEntry      *hPtr;    Tcl_HashTable      *tablePtr;    SOCKET              new, sock;    ListenData          *ldPtr;    int                 status;    struct sockaddr_in  sa;    if (Ns_GetSockAddr(&sa, addr, port) != NS_OK) {        return NS_ERROR;    }    if (addr != NULL) {        /*	 * Make sure we can bind to the specified interface.	 */	        sa.sin_port = 0;        sock = Ns_SockBind(&sa);        if (sock == INVALID_SOCKET) {            return NS_ERROR;        }        ns_sockclose(sock);    }    status = NS_OK;    Ns_MutexLock(&lock);    /*     * Update the global hash table that keeps track of which ports     * we're listening on.     */      hPtr = Tcl_CreateHashEntry(&portsTable, (char *) port, &new);    if (new == 0) {        tablePtr = Tcl_GetHashValue(hPtr);    } else {        sock = Ns_SockListen(NULL, port);        if (sock == INVALID_SOCKET) {            Tcl_DeleteHashEntry(hPtr);            status = NS_ERROR;        } else {            Ns_SockSetNonBlocking(sock);            tablePtr = ns_malloc(sizeof(Tcl_HashTable));            Tcl_InitHashTable(tablePtr, TCL_ONE_WORD_KEYS);            Tcl_SetHashValue(hPtr, tablePtr);            Ns_SockCallback(sock, ListenCallback, tablePtr,			    NS_SOCK_READ | NS_SOCK_EXIT);        }    }    if (status == NS_OK) {        hPtr = Tcl_CreateHashEntry(tablePtr, (char *) sa.sin_addr.s_addr, &new);        if (!new) {            status = NS_ERROR;        } else {            ldPtr = ns_malloc(sizeof(ListenData));            ldPtr->proc = proc;            ldPtr->arg = arg;            Tcl_SetHashValue(hPtr, ldPtr);        }    }    Ns_MutexUnlock(&lock);        return status;}/* *---------------------------------------------------------------------- * * Ns_SockPortBound -- * *	Determine if we're already listening on a given port on any  *	address.  * * Results: *	Boolean: true=yes, false=no.  * * Side effects: *	None.  * *---------------------------------------------------------------------- */intNs_SockPortBound(int port){    Tcl_HashEntry  *hPtr;    Ns_MutexLock(&lock);    hPtr = Tcl_FindHashEntry(&portsTable, (char *) port);    Ns_MutexUnlock(&lock);    return (hPtr != NULL ? 1 : 0);}/* *---------------------------------------------------------------------- * * ListenCallback -- * *	This is a wrapper callback that runs the user's callback iff  *	a valid socket exists.  * * Results: *	NS_TRUE or NS_FALSE  * * Side effects: *	May close the socket if no user context can be found.  * *---------------------------------------------------------------------- */static intListenCallback(SOCKET sock, void *arg, int why){    struct sockaddr_in  sa;    int                 len;    Tcl_HashTable      *tablePtr;    Tcl_HashEntry      *hPtr;    SOCKET              new;    ListenData          *ldPtr;    tablePtr = arg;    if (why == NS_SOCK_EXIT) {        ns_sockclose(sock);        return NS_FALSE;    }    new = Ns_SockAccept(sock, NULL, NULL);    if (new != INVALID_SOCKET) {        Ns_SockSetBlocking(new);        len = sizeof(sa);        getsockname(new, (struct sockaddr *) &sa, &len);        ldPtr = NULL;        Ns_MutexLock(&lock);        hPtr = Tcl_FindHashEntry(tablePtr, (char *) sa.sin_addr.s_addr);        if (hPtr == NULL) {            hPtr = Tcl_FindHashEntry(tablePtr, (char *) INADDR_ANY);        }        if (hPtr != NULL) {            ldPtr = Tcl_GetHashValue(hPtr);        }        Ns_MutexUnlock(&lock);        if (ldPtr == NULL) {            ns_sockclose(new);        } else {            (*ldPtr->proc) (new, ldPtr->arg, why);        }    }    return NS_TRUE;}