From: Vlad S. <ser...@us...> - 2005-02-16 15:06:00
|
Update of /cvsroot/naviserver/naviserver/nsd In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13754/nsd Modified Files: binder.c tclsock.c Log Message: Binder suppport for different protocols added, supported TCP/UDP/ICMP/UNIX protocols. Added Ns_SockListenUdp,Ns_SockListenRaw,Ns_SockListenUnix functions. Backported sockopen command from 4.1 tree with -localhost/-localport options. db select will reuse exception which driver set otherwise will set standard error about wrong query. Index: tclsock.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/tclsock.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** tclsock.c 16 Feb 2005 08:40:17 -0000 1.1.1.1 --- tclsock.c 16 Feb 2005 15:05:46 -0000 1.2 *************** *** 105,140 **** { Ns_DString ds; - char *opt, *addr; - int all = 0; int status; ! if (byaddr) { ! if (objc < 2 || objc > 3) { ! Tcl_WrongNumArgs(interp, 1, objv, "?-all? address"); ! return TCL_ERROR; ! } ! } else { ! if (objc != 2) { ! Tcl_WrongNumArgs(interp, 1, objv, "address"); ! return TCL_ERROR; ! } ! } ! opt = Tcl_GetString(objv[1]); ! if (objc >= 3 && STREQ(opt, "-all")) { ! all = 1; ! addr = Tcl_GetString(objv[2]); ! } else { ! addr = opt; } - Ns_DStringInit(&ds); if (byaddr) { ! if (all) { ! status = Ns_GetAllAddrByHost(&ds, addr); ! } else { ! status = Ns_GetAddrByHost(&ds, addr); ! } } else { ! status = Ns_GetHostByAddr(&ds, addr); } if (status == NS_TRUE) { --- 105,119 ---- { Ns_DString ds; int status; ! if (objc != 2) { ! Tcl_WrongNumArgs(interp, 1, objv, "address"); ! return TCL_ERROR; } Ns_DStringInit(&ds); if (byaddr) { ! status = Ns_GetAddrByHost(&ds, Tcl_GetString(objv[1])); } else { ! status = Ns_GetHostByAddr(&ds, Tcl_GetString(objv[1])); } if (status == NS_TRUE) { *************** *** 143,147 **** Ns_DStringFree(&ds); if (status != NS_TRUE) { ! Tcl_AppendResult(interp, "could not lookup ", addr, NULL); return TCL_ERROR; } --- 122,128 ---- Ns_DStringFree(&ds); if (status != NS_TRUE) { ! Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not lookup ", ! Tcl_GetString(objv[1]), ! NULL); return TCL_ERROR; } *************** *** 393,441 **** int ! NsTclSockOpenObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { SOCKET sock; ! int port; ! int timeout; ! int first; ! int async; ! if (objc < 3 || objc > 5) { ! Tcl_WrongNumArgs(interp, 1, objv, "?-nonblock|-timeout seconds? host port"); return TCL_ERROR; } ! first = 1; ! async = 0; ! timeout = -1; ! if (objc == 4) { ! /* ! * open -nonblock host port ! */ ! ! if (!STREQ(Tcl_GetString(objv[1]), "-nonblock") && ! !STREQ(Tcl_GetString(objv[1]), "-async")) { ! Tcl_WrongNumArgs(interp, 1, objv, "?-nonblock|-timeout seconds? host port"); ! return TCL_ERROR; } ! first = 2; ! async = 1; ! } else if (objc == 5) { ! /* ! * open -timeout seconds host port ! */ ! if (!STREQ(Tcl_GetString(objv[1]), "-timeout")) { ! Tcl_WrongNumArgs(interp, 1, objv, "?-nonblock|-timeout seconds? host port"); ! return TCL_ERROR; ! } ! if (Tcl_GetIntFromObj(interp, objv[2], &timeout) != TCL_OK) { ! return TCL_ERROR; ! } ! first = 3; } ! if (Tcl_GetIntFromObj(interp, objv[first + 1], &port) != TCL_OK) { return TCL_ERROR; } --- 374,473 ---- int ! NsTclSockOpenObjCmd( ! ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ! ) { SOCKET sock; ! char *host, *lhost = NULL, *opt, *val; ! int lport = 0, port, first, async = 0, timeout = -1; ! if (objc < 3 || objc > 9) { ! syntax: ! Tcl_WrongNumArgs(interp, 1, objv, ! "?(-nonblock | -async) | -timeout seconds? " ! "?-localhost host? ?-localport port? host port"); return TCL_ERROR; } ! ! /* ! * Parse optional arguments. Note that either the: ! * -nonblock | -async ! * or ! * -timeout seconds ! * combinations are accepted. ! */ ! for (first = 1; first < objc; first++) { ! opt= Tcl_GetString(objv[first]); ! if (*opt != '-') { ! break; /* End of options */ } + if (STREQ(opt, "-nonblock") || STREQ(opt, "-async")) { + if (timeout >= 0) { + goto syntax; + } + async = 1; + } else if (STREQ(opt, "-localhost")) { + if (++first >= objc) { + goto syntax; + } + lhost = Tcl_GetString(objv[first]); + if (*lhost == 0) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "invalid hostname: must not be empty", NULL); + return TCL_ERROR; + } + } else if (STREQ(opt, "-timeout")) { + if (++first >= objc || async) { + goto syntax; + } + if (Tcl_GetIntFromObj(interp, objv[first], &timeout) != TCL_OK) { + return TCL_ERROR; + } + } else if (STREQ(opt, "-localport")) { + if (++first >= objc) { + goto syntax; + } + if (Tcl_GetIntFromObj(interp, objv[first], &lport) != TCL_OK) { + return TCL_ERROR; + } + if (lport < 0) { + val = Tcl_GetString(objv[first]); + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "invalid port: ", val, "; must be > 0", NULL); + return TCL_ERROR; + } + } else { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "invalid option: \"", opt, "\"", NULL); + return TCL_ERROR; + } + } ! if ((objc - first) != 2) { ! goto syntax; ! } ! /* ! * Get the host to connect to. Bark on invalid entry. ! */ ! host = Tcl_GetString(objv[first]); ! if (*host == 0) { ! Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), ! "invalid hostname: must not be empty", NULL); ! return TCL_ERROR; } ! ! /* ! * Get the port to connect to. Bark on invalid entry. ! */ ! ! if (Tcl_GetIntFromObj(interp, objv[first+1], &port) != TCL_OK) { ! return TCL_ERROR; ! } else if (port < 0) { ! val = Tcl_GetString(objv[first+1]); ! Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), ! "invalid port: ", val, "; must be > 0", NULL); return TCL_ERROR; } *************** *** 444,461 **** * Perform the connection. */ ! if (async) { ! sock = Ns_SockAsyncConnect(Tcl_GetString(objv[first]), port); } else if (timeout < 0) { ! sock = Ns_SockConnect(Tcl_GetString(objv[first]), port); } else { ! sock = Ns_SockTimedConnect(Tcl_GetString(objv[first]), port, timeout); } if (sock == INVALID_SOCKET) { ! Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not connect to \"", ! Tcl_GetString(objv[first]), ":", ! Tcl_GetString(objv[first + 1]), "\"", NULL); return TCL_ERROR; } return EnterDupedSocks(interp, sock); } --- 476,496 ---- * Perform the connection. */ ! if (async) { ! sock = Ns_SockAsyncConnect2(host, port, lhost, lport); } else if (timeout < 0) { ! sock = Ns_SockConnect2(host, port, lhost, lport); } else { ! sock = Ns_SockTimedConnect2(host, port, lhost, lport, timeout); } + if (sock == INVALID_SOCKET) { ! char *why = Tcl_GetErrno() ? Tcl_PosixError(interp) : "reason unknown"; ! Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), ! "can't connect to \"", host, ":", ! Tcl_GetString(objv[first+1]), "\"; ", why, NULL); return TCL_ERROR; } + return EnterDupedSocks(interp, sock); } Index: binder.c =================================================================== RCS file: /cvsroot/naviserver/naviserver/nsd/binder.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** binder.c 16 Feb 2005 08:39:19 -0000 1.1.1.1 --- binder.c 16 Feb 2005 15:05:46 -0000 1.2 *************** *** 38,42 **** #include "nsd.h" ! /* * Locals defined in this file --- 38,42 ---- #include "nsd.h" ! #include <sys/un.h> /* * Locals defined in this file *************** *** 44,51 **** static void PreBind(char *line); ! static Tcl_HashTable prebound; static Ns_Mutex lock; /* *---------------------------------------------------------------------- --- 44,55 ---- static void PreBind(char *line); ! static Tcl_HashTable preboundTcp; ! static Tcl_HashTable preboundUdp; ! static Tcl_HashTable preboundRaw; ! static Tcl_HashTable preboundUnix; static Ns_Mutex lock; + /* *---------------------------------------------------------------------- *************** *** 76,80 **** } Ns_MutexLock(&lock); ! hPtr = Tcl_FindHashEntry(&prebound, (char *) &sa); if (hPtr != NULL) { sock = (int) Tcl_GetHashValue(hPtr); --- 80,84 ---- } Ns_MutexLock(&lock); ! hPtr = Tcl_FindHashEntry(&preboundTcp, (char *) &sa); if (hPtr != NULL) { sock = (int) Tcl_GetHashValue(hPtr); *************** *** 94,97 **** --- 98,279 ---- } + /* + *---------------------------------------------------------------------- + * + * Ns_SockBindUdp -- + * + * Create a UDP socket and bind it to the passed-in address. + * + * Results: + * Socket descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_SockBindUdp(struct sockaddr_in *saPtr) + { + int sock, err, n = 1; + + if((sock = socket(AF_INET,SOCK_DGRAM,0)) < 0 || + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) < 0 || + bind(sock,(struct sockaddr *)saPtr,sizeof(struct sockaddr_in)) < 0) { + err = errno; + close(sock); + Ns_SetSockErrno(err); + sock = -1; + } + return sock; + } + + /* + *---------------------------------------------------------------------- + * + * Ns_SockRaw -- + * + * Helper routine for creating a raw socket + * + * Results: + * Socket descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_SockRaw(int proto) + { + int sock, err; + + if((sock = socket(AF_INET,SOCK_RAW,proto)) < 0) { + err = errno; + close(sock); + Ns_SetSockErrno(err); + sock = -1; + } + return sock; + } + + /* + *---------------------------------------------------------------------- + * + * Ns_SockListenUdp -- + * + * Create a new UDP socket bound to the specified port and listening + * for new connections. + * + * Results: + * Socket descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_SockListenUdp(char *address, int port) + { + int sock = -1; + struct sockaddr_in sa; + Tcl_HashEntry *hPtr; + + if (Ns_GetSockAddr(&sa, address, port) != NS_OK) { + return -1; + } + Ns_MutexLock(&lock); + hPtr = Tcl_FindHashEntry(&preboundUdp, (char *) &sa); + if (hPtr != NULL) { + sock = (int) Tcl_GetHashValue(hPtr); + Tcl_DeleteHashEntry(hPtr); + } + Ns_MutexUnlock(&lock); + if (hPtr == NULL) { + sock = Ns_SockBindUdp(&sa); + } + return sock; + } + + /* + *---------------------------------------------------------------------- + * + * Ns_SockListenRaw -- + * + * Create a new RAW socket + * + * Results: + * Socket descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + int + Ns_SockListenRaw(int proto) + { + int sock = -1; + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + + Ns_MutexLock(&lock); + hPtr = Tcl_FirstHashEntry(&preboundRaw, &search); + while (hPtr != NULL) { + if(proto == (int)Tcl_GetHashValue(hPtr)) { + sock = (int)Tcl_GetHashKey(&preboundRaw, hPtr); + Tcl_DeleteHashEntry(hPtr); + break; + } + hPtr = Tcl_NextHashEntry(&search); + } + Ns_MutexUnlock(&lock); + if (hPtr == NULL) { + sock = Ns_SockRaw(proto); + } + return sock; + } + + /* + *---------------------------------------------------------------------- + * + * ListenUnix -- + * + * Helper routine for creating a listening UNIX domain socket. + * + * Results: + * Socket descriptor or -1 on error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + static int + Ns_SockListenUnix(char *path) + { + int sock, err; + struct sockaddr_un addr; + + memset(&addr,0,sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path,path,sizeof(addr.sun_path)-1); + unlink(path); + if((sock = socket(AF_UNIX,SOCK_STREAM,0)) < 0 || + bind(sock,(struct sockaddr*)&addr,sizeof(addr)) < 0) { + err = errno; + close(sock); + Ns_SetSockErrno(err); + sock = -1; + } + return sock; + } + /* *************** *** 114,118 **** NsInitBinder(void) { ! Tcl_InitHashTable(&prebound, sizeof(struct sockaddr_in)/sizeof(int)); } --- 296,303 ---- NsInitBinder(void) { ! Tcl_InitHashTable(&preboundTcp, sizeof(struct sockaddr_in)/sizeof(int)); ! Tcl_InitHashTable(&preboundUdp, sizeof(struct sockaddr_in)/sizeof(int)); ! Tcl_InitHashTable(&preboundRaw, TCL_ONE_WORD_KEYS); ! Tcl_InitHashTable(&preboundUnix, TCL_STRING_KEYS); } *************** *** 178,193 **** Ns_MutexLock(&lock); ! hPtr = Tcl_FirstHashEntry(&prebound, &search); while (hPtr != NULL) { ! saPtr = (struct sockaddr_in *) Tcl_GetHashKey(&prebound, hPtr); addr = ns_inet_ntoa(saPtr->sin_addr); port = htons(saPtr->sin_port); ! sock = (int) Tcl_GetHashValue(hPtr); ! Ns_Log(Warning, "prebind: closed unused: %s:%d = %d", addr, port, sock); close(sock); hPtr = Tcl_NextHashEntry(&search); } ! Tcl_DeleteHashTable(&prebound); ! Tcl_InitHashTable(&prebound, sizeof(struct sockaddr_in)/sizeof(int)); Ns_MutexUnlock(&lock); } --- 363,410 ---- Ns_MutexLock(&lock); ! hPtr = Tcl_FirstHashEntry(&preboundTcp, &search); while (hPtr != NULL) { ! saPtr = (struct sockaddr_in *) Tcl_GetHashKey(&preboundTcp, hPtr); addr = ns_inet_ntoa(saPtr->sin_addr); port = htons(saPtr->sin_port); ! sock = (int)Tcl_GetHashValue(hPtr); ! Ns_Log(Warning, "prebind: closed unused TCP: %s:%d = %d", addr, port, sock); close(sock); hPtr = Tcl_NextHashEntry(&search); } ! Tcl_DeleteHashTable(&preboundTcp); ! Tcl_InitHashTable(&preboundTcp, sizeof(struct sockaddr_in)/sizeof(int)); ! hPtr = Tcl_FirstHashEntry(&preboundUdp, &search); ! while (hPtr != NULL) { ! saPtr = (struct sockaddr_in *) Tcl_GetHashKey(&preboundUdp, hPtr); ! addr = ns_inet_ntoa(saPtr->sin_addr); ! port = htons(saPtr->sin_port); ! sock = (int)Tcl_GetHashValue(hPtr); ! Ns_Log(Warning, "prebind: closed unused UDP: %s:%d = %d", addr, port, sock); ! close(sock); ! hPtr = Tcl_NextHashEntry(&search); ! } ! Tcl_DeleteHashTable(&preboundUdp); ! Tcl_InitHashTable(&preboundUdp, sizeof(struct sockaddr_in)/sizeof(int)); ! hPtr = Tcl_FirstHashEntry(&preboundRaw, &search); ! while (hPtr != NULL) { ! sock = (int)Tcl_GetHashKey(&preboundRaw, hPtr); ! port = (int)Tcl_GetHashValue(hPtr); ! Ns_Log(Warning, "prebind: closed unused RAW: %d = %d", port, sock); ! close(sock); ! hPtr = Tcl_NextHashEntry(&search); ! } ! Tcl_DeleteHashTable(&preboundRaw); ! Tcl_InitHashTable(&preboundRaw, TCL_ONE_WORD_KEYS); ! hPtr = Tcl_FirstHashEntry(&preboundUnix, &search); ! while (hPtr != NULL) { ! addr = (char *) Tcl_GetHashKey(&preboundUnix, hPtr); ! sock = (int)Tcl_GetHashValue(hPtr); ! Ns_Log(Warning, "prebind: closed unused Unix: %s = %d", addr, sock); ! close(sock); ! hPtr = Tcl_NextHashEntry(&search); ! } ! Tcl_DeleteHashTable(&preboundUnix); ! Tcl_InitHashTable(&preboundUnix, TCL_STRING_KEYS); Ns_MutexUnlock(&lock); } *************** *** 200,204 **** * * Pre-bind to one or more ports in a comma-separated list. ! * * Results: * None. --- 417,424 ---- * * Pre-bind to one or more ports in a comma-separated list. ! * addr:port[/protocol] ! * port[/protocol] ! * 0/icmp[/count] ! * /path * Results: * None. *************** *** 217,266 **** int new, sock, port; struct sockaddr_in sa; ! char *err, *ent, *p, *q, *addr, *baddr; ! ent = line; ! do { ! p = strchr(ent, ','); ! if (p != NULL) { ! *p = '\0'; ! } ! baddr = NULL; ! addr = "0.0.0.0"; ! q = strchr(ent, ':'); ! if (q == NULL) { ! port = atoi(ent); ! } else { ! *q = '\0'; ! port = atoi(q+1); ! baddr = addr = ent; ! } ! if (port == 0) { ! err = "invalid port"; ! } else if (Ns_GetSockAddr(&sa, baddr, port) != NS_OK) { ! err = "invalid address"; ! } else { ! hPtr = Tcl_CreateHashEntry(&prebound, (char *) &sa, &new); ! if (!new) { ! err = "duplicate entry"; ! } else if ((sock = Ns_SockBind(&sa)) == -1) { ! Tcl_DeleteHashEntry(hPtr); ! err = strerror(errno); ! } else { ! Tcl_SetHashValue(hPtr, sock); ! err = NULL; ! } ! } ! if (q != NULL) { ! *q = ':'; ! } ! if (p != NULL) { ! *p++ = ','; ! } ! if (err != NULL) { ! Ns_Log(Error, "prebind: invalid entry: %s: %s", ent, err); ! } else { ! Ns_Log(Notice, "prebind: bound: %s", ent); ! } ! ent = p; ! } while (ent != NULL); } --- 437,539 ---- int new, sock, port; struct sockaddr_in sa; ! char *next, *str, *addr, *proto; ! for(;line != NULL;line = next) { ! if((next = strchr(line, ','))) { ! *next++ = '\0'; ! } ! proto = "tcp"; ! addr = "0.0.0.0"; ! /* Parse port */ ! if((str = strchr(line, ':'))) { ! *str++ = '\0'; ! port = atoi(str); ! addr = line; ! line = str; ! } else { ! port = atoi(line); ! } ! /* Parse protocol */ ! if(*line != '/' && (str = strchr(line,'/'))) { ! *str++ = '\0'; ! proto = str; ! } ! ! if(!strcmp(proto,"tcp") && port > 0) { ! if(Ns_GetSockAddr(&sa, addr, port) != NS_OK) { ! Ns_Log(Error, "prebind: tcp: invalid address: %s:%d",addr,port); ! continue; ! } ! hPtr = Tcl_CreateHashEntry(&preboundTcp, (char *) &sa, &new); ! if(!new) { ! Ns_Log(Error, "prebind: tcp: duplicate entry: %s:%d",addr,port); ! continue; ! } ! if((sock = Ns_SockBind(&sa)) == -1) { ! Ns_Log(Error, "prebind: tcp: %s:%d: %s",addr,port,strerror(errno)); ! Tcl_DeleteHashEntry(hPtr); ! continue; ! } ! Tcl_SetHashValue(hPtr, sock); ! Ns_Log(Notice, "prebind: tcp: %s:%d = %d", addr, port, sock); ! } ! ! if(!strcmp(proto,"udp") && port > 0) { ! if(Ns_GetSockAddr(&sa, addr, port) != NS_OK) { ! Ns_Log(Error, "prebind: udp: invalid address: %s:%d",addr,port); ! continue; ! } ! hPtr = Tcl_CreateHashEntry(&preboundUdp, (char *) &sa, &new); ! if(!new) { ! Ns_Log(Error, "prebind: udp: duplicate entry: %s:%d",addr,port); ! continue; ! } ! if((sock = Ns_SockBindUdp(&sa)) == -1) { ! Ns_Log(Error, "prebind: udp: %s:%d: %s",addr,port,strerror(errno)); ! Tcl_DeleteHashEntry(hPtr); ! continue; ! } ! Tcl_SetHashValue(hPtr, sock); ! Ns_Log(Notice, "prebind: udp: %s:%d = %d", addr, port, sock); ! } ! ! if(!strncmp(proto,"icmp",4)) { ! int count = 1; ! /* Parse count */ ! if((str = strchr(str,'/'))) { ! *(str++) = '\0'; ! count = atoi(str); ! } ! while(count--) { ! if((sock = Ns_SockRaw(IPPROTO_ICMP)) == -1) { ! Ns_Log(Error, "prebind: icmp: %s",strerror(errno)); ! continue; ! } ! hPtr = Tcl_CreateHashEntry(&preboundRaw, (char *) sock, &new); ! if(!new) { ! Ns_Log(Error, "prebind: icmp: duplicate entry"); ! close(sock); ! continue; ! } ! Tcl_SetHashValue(hPtr, IPPROTO_ICMP); ! Ns_Log(Notice, "prebind: icmp: %d", sock); ! } ! } ! ! if(*line == '/') { ! hPtr = Tcl_CreateHashEntry(&preboundUnix, (char *) line, &new); ! if(!new) { ! Ns_Log(Error, "prebind: unix: duplicate entry: %s",line); ! continue; ! } ! if((sock = Ns_SockListenUnix(line)) == -1) { ! Ns_Log(Error, "prebind: unix: %s: %s",proto,strerror(errno)); ! Tcl_DeleteHashEntry(hPtr); ! continue; ! } ! Tcl_SetHashValue(hPtr, sock); ! Ns_Log(Notice, "prebind: unix: %s = %d", line, sock); ! } ! } } + |