diff --git a/src/sbbs3/execnet.cpp b/src/sbbs3/execnet.cpp index bda3041be4f6e0b9c5a9c54133f61cba01fc2627..effeae4fadc4b6c10e9efd0baaad80fd3894f9b4 100644 --- a/src/sbbs3/execnet.cpp +++ b/src/sbbs3/execnet.cpp @@ -643,15 +643,12 @@ bool sbbs_t::ftp_get(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest, bool d char rsp[512]; char buf[4097]; int rd; - int result; BOOL data_avail; ulong total=0; SOCKET data_sock; union xp_sockaddr addr; socklen_t addr_len; FILE* fp=NULL; - struct timeval tv; - fd_set socket_set; if((data_sock=ftp_data_sock(csi, ctrl_sock, &addr.in))==INVALID_SOCKET) return(false); @@ -684,16 +681,7 @@ bool sbbs_t::ftp_get(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest, bool d } if(!(csi->ftp_mode&CS_FTP_PASV)) { /* Normal (Active) FTP */ - - /* Setup for select() */ - tv.tv_sec=TIMEOUT_SOCK_LISTEN; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(data_sock,&socket_set); - - result=select(data_sock+1,&socket_set,NULL,NULL,&tv); - if(result<1) { + if(!socket_readable(data_sock, TIMEOUT_SOCK_LISTEN * 1000)) { csi->socket_error=ERROR_VALUE; closesocket(data_sock); return(false); @@ -770,15 +758,12 @@ bool sbbs_t::ftp_put(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest) char path[MAX_PATH+1]; char buf[4097]; int rd; - int result; ulong total=0; SOCKET data_sock; union xp_sockaddr addr; socklen_t addr_len; FILE* fp=NULL; bool error=false; - struct timeval tv; - fd_set socket_set; SAFECOPY(path,src); @@ -823,16 +808,7 @@ bool sbbs_t::ftp_put(csi_t* csi, SOCKET ctrl_sock, char* src, char* dest) } if(!(csi->ftp_mode&CS_FTP_PASV)) { /* Normal (Active) FTP */ - - /* Setup for select() */ - tv.tv_sec=TIMEOUT_SOCK_LISTEN; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(data_sock,&socket_set); - - result=select(data_sock+1,&socket_set,NULL,NULL,&tv); - if(result<1) { + if(!socket_readable(data_sock, TIMEOUT_SOCK_LISTEN * 1000)) { csi->socket_error=ERROR_VALUE; closesocket(data_sock); fclose(fp); diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c index 7e086b041cd0a09118b29e2db730bc7537c1efe5..5ae915ec5489c5d93b8a4364bd72d87a15fcf92b 100644 --- a/src/sbbs3/ftpsrvr.c +++ b/src/sbbs3/ftpsrvr.c @@ -310,8 +310,6 @@ static int sockprintf(SOCKET sock, CRYPT_SESSION sess, char *fmt, ...) int result; va_list argptr; char sbuf[1024]; - fd_set socket_set; - struct timeval tv; char *estr; va_start(argptr,fmt); @@ -330,20 +328,9 @@ static int sockprintf(SOCKET sock, CRYPT_SESSION sess, char *fmt, ...) return(0); } - /* Check socket for writability (using select) */ - tv.tv_sec=300; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) { - if(result==0) - lprintf(LOG_WARNING,"%04d !TIMEOUT selecting socket for send" - ,sock); - else - lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket for send" - ,sock, ERROR_VALUE); + /* Check socket for writability */ + if(!socket_writable(sock, 300000)) { + lprintf(LOG_WARNING,"%04d !WARNING socket not ready for write" ,sock); return(0); } @@ -458,8 +445,6 @@ void recverror(SOCKET socket, int rd, int line) static int sock_recvbyte(SOCKET sock, CRYPT_SESSION sess, char *buf, time_t *lastactive) { int len=0; - fd_set socket_set; - struct timeval tv; int ret; int i; char *estr; @@ -476,7 +461,7 @@ static int sock_recvbyte(SOCKET sock, CRYPT_SESSION sess, char *buf, time_t *las GCES(ret, sock, sess, estr, "setting read timeout"); while (1) { ret = cryptPopData(sess, buf, 1, &len); - /* Successive reads will be with the full timeout after a select() */ + /* Successive reads will be with the full timeout after a socket_readable() */ cryptSetAttribute(sess, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity); switch(ret) { case CRYPT_OK: @@ -506,50 +491,26 @@ static int sock_recvbyte(SOCKET sock, CRYPT_SESSION sess, char *buf, time_t *las return(0); } - tv.tv_sec=startup->max_inactivity; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,&socket_set,NULL,NULL,&tv); - - if(i<1) { - if(i==0) { - if((time(NULL)-(*lastactive))>startup->max_inactivity) { - lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock); - sockprintf(sock,sess,"421 Disconnecting due to inactivity (%u seconds)." - ,startup->max_inactivity); - return(0); - } - continue; + if (!socket_readable(sock, startup->max_inactivity * 1000)) { + if((time(NULL)-(*lastactive))>startup->max_inactivity) { + lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock); + sockprintf(sock,sess,"421 Disconnecting due to inactivity (%u seconds)." + ,startup->max_inactivity); + return(0); } - recverror(sock,i,__LINE__); - return(i); } } } else { while (1) { - tv.tv_sec=startup->max_inactivity; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,&socket_set,NULL,NULL,&tv); - - if(i<1) { - if(i==0) { - if((time(NULL)-(*lastactive))>startup->max_inactivity) { - lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock); - sockprintf(sock,sess,"421 Disconnecting due to inactivity (%u seconds)." - ,startup->max_inactivity); - return(0); - } - continue; + if (!socket_readable(sock, startup->max_inactivity * 1000)) { + if((time(NULL)-(*lastactive))>startup->max_inactivity) { + lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock); + sockprintf(sock,sess,"421 Disconnecting due to inactivity (%u seconds)." + ,startup->max_inactivity); + return(0); } - return(i); + continue; } #ifdef SOCKET_DEBUG_RECV_CHAR socket_debug[sock]|=SOCKET_DEBUG_RECV_CHAR; @@ -661,8 +622,6 @@ static void send_thread(void* arg) user_t uploader; union xp_sockaddr addr; socklen_t addr_len; - fd_set socket_set; - struct timeval tv; char *estr; xfer=*(xfer_t*)arg; @@ -742,22 +701,8 @@ static void send_thread(void* arg) break; } - /* Check socket for writability (using select) */ - tv.tv_sec=1; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(*xfer.data_sock,&socket_set); - - i=select((*xfer.data_sock)+1,NULL,&socket_set,NULL,&tv); - if(i==SOCKET_ERROR) { - lprintf(LOG_WARNING,"%04d <%s> !DATA ERROR %d selecting socket %d for send" - ,xfer.ctrl_sock, xfer.user->alias, ERROR_VALUE, *xfer.data_sock); - sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 Transfer error."); - error=TRUE; - break; - } - if(i<1) + /* Check socket for writability */ + if (!socket_writable(*xfer.data_sock, 1000)) continue; (void)fseek(fp,xfer.filepos+total,SEEK_SET); @@ -954,8 +899,6 @@ static void receive_thread(void* arg) time_t now; time_t start; time_t last_report; - fd_set socket_set; - struct timeval tv; CRYPT_SESSION sess = -1; char *estr; @@ -1029,22 +972,8 @@ static void receive_thread(void* arg) break; } - /* Check socket for readability (using select) */ - tv.tv_sec=1; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(*xfer.data_sock,&socket_set); - - i=select((*xfer.data_sock)+1,&socket_set,NULL,NULL,&tv); - if(i==SOCKET_ERROR) { - lprintf(LOG_WARNING,"%04d <%s> !DATA ERROR %d selecting socket %d for receive" - ,xfer.ctrl_sock, xfer.user->alias, ERROR_VALUE, *xfer.data_sock); - sockprintf(xfer.ctrl_sock,sess,"426 Transfer error."); - error=TRUE; - break; - } - if(i<1) + /* Check socket for readability */ + if (!socket_readable(*xfer.data_sock, 1000)) continue; #if defined(SOCKET_DEBUG_RECV_BUF) @@ -1333,8 +1262,6 @@ static void filexfer(union xp_sockaddr* addr, SOCKET ctrl_sock, CRYPT_SESSION ct union xp_sockaddr server_addr; BOOL reuseaddr; xfer_t* xfer; - struct timeval tv; - fd_set socket_set; char host_ip[INET6_ADDRSTRLEN]; if((*inprogress)==TRUE) { @@ -1434,23 +1361,9 @@ static void filexfer(union xp_sockaddr* addr, SOCKET ctrl_sock, CRYPT_SESSION ct ,ctrl_sock, user->alias,pasv_sock,host_ip,inet_addrport(addr)); } - /* Setup for select() */ - tv.tv_sec=TIMEOUT_SOCKET_LISTEN; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(pasv_sock,&socket_set); - -#if defined(SOCKET_DEBUG_SELECT) - socket_debug[ctrl_sock]|=SOCKET_DEBUG_SELECT; -#endif - result=select(pasv_sock+1,&socket_set,NULL,NULL,&tv); -#if defined(SOCKET_DEBUG_SELECT) - socket_debug[ctrl_sock]&=~SOCKET_DEBUG_SELECT; -#endif - if(result<1) { - lprintf(LOG_WARNING,"%04d <%s> PASV !DATA select returned %d (error: %d)" - ,ctrl_sock, user->alias,result,ERROR_VALUE); + if (!socket_readable(pasv_sock, TIMEOUT_SOCKET_LISTEN * 1000)) { + lprintf(LOG_WARNING,"%04d <%s> PASV !WARNING socket not readable" + ,ctrl_sock, user->alias); sockprintf(ctrl_sock,ctrl_sess,"425 Error %d selecting socket for connection",ERROR_VALUE); if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES)) (void)ftp_remove(ctrl_sock, __LINE__, filename, user->alias); diff --git a/src/sbbs3/ident.c b/src/sbbs3/ident.c index 7c1d24b6fc9ec53c50dc9b158b786ba6723c774e..6fe4e4e6dff17c17cf58c8821f0485be126521ab 100644 --- a/src/sbbs3/ident.c +++ b/src/sbbs3/ident.c @@ -42,14 +42,11 @@ BOOL identify(union xp_sockaddr *client_addr, u_short local_port, char* buf ,size_t maxlen, int timeout) { char req[128]; - int i; int result; int rd; ulong val; SOCKET sock=INVALID_SOCKET; union xp_sockaddr addr; - struct timeval tv; - fd_set socket_set; BOOL success=FALSE; if(client_addr->addr.sa_family != AF_INET && client_addr->addr.sa_family != AF_INET6) @@ -73,12 +70,7 @@ BOOL identify(union xp_sockaddr *client_addr, u_short local_port, char* buf if(result==SOCKET_ERROR && (ERROR_VALUE==EWOULDBLOCK || ERROR_VALUE==EINPROGRESS)) { - tv.tv_sec=timeout; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - if(select(sock+1,NULL,&socket_set,NULL,&tv)==1) + if (socket_writable(sock, timeout * 1000)) result=0; /* success */ } if(result!=0) { @@ -89,14 +81,7 @@ BOOL identify(union xp_sockaddr *client_addr, u_short local_port, char* buf val=0; ioctlsocket(sock,FIONBIO,&val); - tv.tv_sec=10; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,NULL,&socket_set,NULL,&tv); - if(i<1) { + if(!socket_writable(sock, 10000)) { sprintf(buf,"ERROR %d selecting socket for send",ERROR_VALUE); break; } @@ -107,14 +92,7 @@ BOOL identify(union xp_sockaddr *client_addr, u_short local_port, char* buf break; } - tv.tv_sec=10; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,&socket_set,NULL,NULL,&tv); - if(i<1) { + if(!socket_readable(sock, 10000)) { sprintf(buf,"ERROR %d detecting response",ERROR_VALUE); break; } diff --git a/src/sbbs3/js_file.c b/src/sbbs3/js_file.c index 9c395972dd12f964deabed9b18479d638b2acd3a..fe05c0474750034eb958133526b0eadd595ca3c9 100644 --- a/src/sbbs3/js_file.c +++ b/src/sbbs3/js_file.c @@ -287,10 +287,6 @@ js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist) private_t* p; jsrefcount rc; int32 timeout = -1; -#ifdef __unix__ - fd_set rd; - struct timeval tv = {0, 0}; -#endif if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) { return(JS_FALSE); @@ -307,13 +303,11 @@ js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist) JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE)); rc=JS_SUSPENDREQUEST(cx); #ifdef __unix__ - if (timeout >= 0) { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout%1000)*1000; - } - FD_ZERO(&rd); - FD_SET(fileno(p->fp), &rd); - if (select(fileno(p->fp)+1, &rd, NULL, NULL, timeout < 0 ? NULL : &tv) == 1) + /* + * TODO: macOS poll() page has the ominous statement that "The poll() system call currently does not support devices." + * But, since we don't support OS X in Synchronet that's likely OK? + */ + if (socket_readable(fileno(p->fp), timeout)) JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE)); #else while(timeout) { diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c index 96413cee194cb351f68e8776283d4f226b035eaa..ee90b87355f9dcd3dda3c83f7fa6a2749f7ece59 100644 --- a/src/sbbs3/js_global.c +++ b/src/sbbs3/js_global.c @@ -3695,12 +3695,21 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) JSObject* robj; JSObject* rarray; BOOL poll_for_write=FALSE; +#ifdef _WIN32 fd_set socket_set[3]; fd_set* sets[3] = {NULL, NULL, NULL}; - uintN argn; - SOCKET sock; SOCKET maxsock=0; struct timeval tv = {0, 0}; + SOCKET sock; +#else + struct pollfd *fds; + int poll_timeout = 0; + nfds_t nfds; + short events; + int scount; + int k; +#endif + uintN argn; jsuint i; jsuint j; jsuint limit[3]; @@ -3717,8 +3726,13 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) poll_for_write=JSVAL_TO_BOOLEAN(argv[argn]); else if(JSVAL_IS_OBJECT(argv[argn])) inarray[inarray_cnt++] = JSVAL_TO_OBJECT(argv[argn]); +#ifdef _WIN32 else if(JSVAL_IS_NUMBER(argv[argn])) js_timeval(cx,argv[argn],&tv); +#else + else if(JSVAL_IS_NUMBER(argv[argn])) + poll_timeout = js_polltimeout(cx, argv[argn]); +#endif } if(inarray_cnt == 0) @@ -3739,6 +3753,7 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) /* Return array */ if((robj = JS_NewArrayObject(cx, 0, NULL))==NULL) return(JS_FALSE); +#ifdef _WIN32 FD_ZERO(&socket_set[0]); if(poll_for_write) sets[1]=&socket_set[0]; @@ -3773,6 +3788,56 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(robj)); } +#else + // First, count the number of sockets... + nfds = 0; + for (i = 0; i < limit[0]; i++) { + if(!JS_GetElement(cx, inarray[0], i, &val)) + break; + nfds += js_socket_numsocks(cx, val); + } + if (nfds == 0) + return JS_TRUE; + + fds = calloc(nfds, sizeof(*fds)); + if (fds == NULL) { + JS_ReportError(cx, "Error allocating %d elements of %lu bytes at %s:%d" + , nfds, sizeof(*fds), getfname(__FILE__), __LINE__); + return JS_FALSE; + } + nfds = 0; + for (i = 0; i < limit[0]; i++) { + if(!JS_GetElement(cx, inarray[0], i, &val)) + break; + nfds += js_socket_add(cx, val, &fds[nfds], poll_for_write ? POLLOUT : POLLIN); + } + + rc = JS_SUSPENDREQUEST(cx); + if (poll(fds, nfds, poll_timeout) >= 0) { + nfds = 0; + for (i = 0; i < limit[0]; i++) { + if(!JS_GetElement(cx, inarray[0], i, &val)) + break; + scount = js_socket_numsocks(cx, val); + for (k = 0; k < scount; k++) { + if (fds[nfds + k].revents & (poll_for_write ? POLLOUT : POLLIN | POLLHUP)) { + val=INT_TO_JSVAL(i); + JS_RESUMEREQUEST(cx, rc); + if(!JS_SetElement(cx, robj, len++, &val)) { + rc=JS_SUSPENDREQUEST(cx); + break; + } + rc=JS_SUSPENDREQUEST(cx); + break; + } + } + nfds += scount; + } + + JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(robj)); + } + free(fds); +#endif JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); @@ -3781,6 +3846,7 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) /* Return object */ if((robj = JS_NewObject(cx, NULL, NULL, NULL))==NULL) return(JS_FALSE); +#ifdef _WIN32 for (j = 0; j < inarray_cnt; j++) { if (limit[j] > 0) { FD_ZERO(&socket_set[j]); @@ -3830,6 +3896,122 @@ js_socket_select(JSContext *cx, uintN argc, jsval *arglist) } JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(robj)); } +#else + /* + * So, we need to collapse all the FDs into a list with flags set... + * readfd corresponds to POLLIN + * writefd corresponds to POLLOUT + * and exceptfd corresponds to POLLPRI + * + * We don't want duplicates, and we don't want to set things that + * weren't requested. + * + * Brute-force method is to add them all to an array, sort the array, + * then remove duplicates after ORing the events together. + * + * NOTE that some of the socket objects may actually be duplicates + * themselves, and all of them should set with the appropriate status. + * + * Alternatively, we can just add them all in-order and pass a larger + * array to poll(). This will certainly be more efficient when + * generating the returned arrays. + */ + nfds = 0; + for (j = 0; j < inarray_cnt; j++) { + if (limit[j] > 0) { + for (i = 0; i < limit[j]; i++) { + if(!JS_GetElement(cx, inarray[0], i, &val)) + break; + nfds += js_socket_numsocks(cx, val); + } + } + } + if (nfds == 0) + return JS_TRUE; + + fds = calloc(nfds, sizeof(*fds)); + if (fds == NULL) { + JS_ReportError(cx, "Error allocating %d elements of %lu bytes at %s:%d" + , nfds, sizeof(*fds), getfname(__FILE__), __LINE__); + return JS_FALSE; + } + nfds = 0; + for (j = 0; j < inarray_cnt; j++) { + if (limit[j] > 0) { + switch (j) { + case 0: + events = POLLIN; + break; + case 1: + events = POLLOUT; + break; + case 2: + events = POLLPRI; + break; + } + for (i = 0; i < limit[j]; i++) { + if(!JS_GetElement(cx, inarray[j], i, &val)) + break; + nfds += js_socket_add(cx, val, &fds[nfds], poll_for_write ? POLLOUT : POLLIN); + } + } + } + + rc = JS_SUSPENDREQUEST(cx); + if (poll(fds, nfds, poll_timeout) >= 0) { + nfds = 0; + for (j = 0; j < inarray_cnt; j++) { + if (limit[j] > 0) { + switch (j) { + case 0: + events = POLLIN | POLLHUP; + break; + case 1: + events = POLLOUT; + break; + case 2: + events = POLLPRI; + break; + } + len = 0; + JS_RESUMEREQUEST(cx, rc); + if((rarray = JS_NewArrayObject(cx, 0, NULL))==NULL) { + free(fds); + return(JS_FALSE); + } + val = OBJECT_TO_JSVAL(rarray); + if (!JS_SetProperty(cx, robj, props[j], &val)) { + free(fds); + return JS_FALSE; + } + rc=JS_SUSPENDREQUEST(cx); + for(i=0;i<limit[j];i++) { + JS_RESUMEREQUEST(cx, rc); + if(!JS_GetElement(cx, inarray[j], i, &val)) { + rc=JS_SUSPENDREQUEST(cx); + break; + } + rc=JS_SUSPENDREQUEST(cx); + scount = js_socket_numsocks(cx, val); + for (k = 0; k < scount; k++) { + if(fds[nfds + k].revents & (events | POLLERR | POLLNVAL)) { + val=INT_TO_JSVAL(i); + JS_RESUMEREQUEST(cx, rc); + if(!JS_SetElement(cx, rarray, len++, &val)) { + rc=JS_SUSPENDREQUEST(cx); + break; + } + rc=JS_SUSPENDREQUEST(cx); + } + } + nfds += scount; + } + } + } + JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(robj)); + } + free(fds); +#endif JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c index 779cf04da598c89f85d6715566711c06dc4c3827..4d732b24f65206fc5d00e6c15e6ca434e0647c6c 100644 --- a/src/sbbs3/js_socket.c +++ b/src/sbbs3/js_socket.c @@ -196,8 +196,6 @@ static ptrdiff_t js_socket_recv(js_socket_private_t *p, void *buf, size_t len, i { ptrdiff_t total=0; int copied,ret; - fd_set socket_set; - struct timeval tv = {0, 0}; char *estr; time_t now = time(NULL); int status; @@ -227,10 +225,8 @@ static ptrdiff_t js_socket_recv(js_socket_private_t *p, void *buf, size_t len, i if (p->sock == INVALID_SOCKET) ret = -1; else { - FD_ZERO(&socket_set); - FD_SET(p->sock,&socket_set); - tv.tv_sec = timeout; - if((ret = select(p->sock+1,&socket_set,NULL,NULL,&tv))==1) + ret = 0; + if (socket_readable(p->sock, timeout * 1000)) ret = recv(p->sock, buf, len, flags); } } @@ -476,6 +472,7 @@ SOCKET DLLCALL js_socket(JSContext *cx, jsval val) return(sock); } +#ifdef _WIN32 SOCKET DLLCALL js_socket_add(JSContext *cx, jsval val, fd_set *fds) { js_socket_private_t *p; @@ -562,6 +559,98 @@ void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv) } } } +#else +size_t DLLCALL js_socket_numsocks(JSContext *cx, jsval val) +{ + js_socket_private_t *p; + JSClass* cl; + SOCKET sock=INVALID_SOCKET; + size_t i; + int32_t intval; + size_t ret = 0; + + if(JSVAL_IS_OBJECT(val) && (cl=JS_GetClass(cx,JSVAL_TO_OBJECT(val)))!=NULL) { + if(cl->flags&JSCLASS_HAS_PRIVATE) { + if((p=(js_socket_private_t *)JS_GetInstancePrivate(cx,JSVAL_TO_OBJECT(val),&js_socket_class,NULL))!=NULL) { + if(p->set) { + for(i=0; i<p->set->sock_count; i++) { + if(p->set->socks[i].sock == INVALID_SOCKET) + continue; + ret++; + } + } + else { + sock = p->sock; + if(sock != INVALID_SOCKET) + ret = 1; + } + } + } + } else if(val!=JSVAL_VOID) { + if(JS_ValueToInt32(cx,val,&intval)) { + if (intval != INVALID_SOCKET) + ret = 1; + } + } + return ret; +} + +size_t DLLCALL js_socket_add(JSContext *cx, jsval val, struct pollfd *fds, short events) +{ + js_socket_private_t *p; + JSClass* cl; + SOCKET sock=INVALID_SOCKET; + size_t i; + int32_t intval; + size_t ret = 0; + + if(JSVAL_IS_OBJECT(val) && (cl=JS_GetClass(cx,JSVAL_TO_OBJECT(val)))!=NULL) { + if(cl->flags&JSCLASS_HAS_PRIVATE) { + if((p=(js_socket_private_t *)JS_GetInstancePrivate(cx,JSVAL_TO_OBJECT(val),&js_socket_class,NULL))!=NULL) { + if(p->set) { + for(i=0; i<p->set->sock_count; i++) { + if(p->set->socks[i].sock == INVALID_SOCKET) + continue; + fds[ret].events = events; + fds[ret++].fd = p->set->socks[i].sock; + } + } + else { + sock = p->sock; + if(sock != INVALID_SOCKET) { + fds[ret].events = events; + fds[ret++].fd = sock; + } + } + } + } + } else if(val!=JSVAL_VOID) { + if(JS_ValueToInt32(cx,val,&intval)) { + sock = intval; + if(sock != INVALID_SOCKET) { + fds[ret].events = events; + fds[ret++].fd = sock; + } + } + } + return ret; +} +#endif + +int DLLCALL js_polltimeout(JSContext* cx, jsval val) +{ + jsdouble jsd; + + if(JSVAL_IS_INT(val)) + return JSVAL_TO_INT(val) * 1000; + + if(JSVAL_IS_DOUBLE(val)) { + if(JS_ValueToNumber(cx,val,&jsd)) + return jsd * 1000; + } + + return 0; +} static JSBool js_bind(JSContext *cx, uintN argc, jsval *arglist) @@ -730,11 +819,10 @@ js_connect(JSContext *cx, uintN argc, jsval *arglist) ushort port; JSString* str; js_socket_private_t* p; - fd_set socket_set; - struct timeval tv = {0, 0}; jsrefcount rc; char ip_str[256]; struct addrinfo hints,*res,*cur; + int timeout = 10000; /* Default time-out */ if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) { return(JS_FALSE); @@ -764,10 +852,8 @@ js_connect(JSContext *cx, uintN argc, jsval *arglist) ioctlsocket(p->sock,FIONBIO,&val); result = SOCKET_ERROR; for(cur=res; cur != NULL; cur=cur->ai_next) { - tv.tv_sec = 10; /* default time-out */ - if(argc>2) /* time-out value specified */ - js_timeval(cx,argv[2],&tv); + timeout = js_polltimeout(cx, argv[2]); inet_addrtop((void *)cur->ai_addr, ip_str, sizeof(ip_str)); dbprintf(FALSE, p, "connecting to %s on port %u at %s", ip_str, port, p->hostname); @@ -778,10 +864,8 @@ js_connect(JSContext *cx, uintN argc, jsval *arglist) if(result == SOCKET_ERROR) { result = ERROR_VALUE; if(result == EWOULDBLOCK || result == EINPROGRESS) { - FD_ZERO(&socket_set); - FD_SET(p->sock,&socket_set); result = ETIMEDOUT; - if(select(p->sock+1,NULL,&socket_set,NULL,&tv)==1) { + if (socket_readable(p->sock, timeout)) { int so_error = -1; socklen_t optlen = sizeof(so_error); if(getsockopt(p->sock, SOL_SOCKET, SO_ERROR, (void*)&so_error, &optlen) == 0 && so_error == 0) @@ -1569,6 +1653,8 @@ js_setsockopt(JSContext *cx, uintN argc, jsval *arglist) if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) { return(JS_FALSE); } + if (p->sock == INVALID_SOCKET) + return JS_TRUE; JSVALUE_TO_ASTRING(cx, argv[0], optname, 64, NULL); rc=JS_SUSPENDREQUEST(cx); @@ -1641,15 +1727,22 @@ js_poll(JSContext *cx, uintN argc, jsval *arglist) jsval *argv=JS_ARGV(cx, arglist); js_socket_private_t* p; BOOL poll_for_write=FALSE; - fd_set socket_set; - fd_set* rd_set=NULL; - fd_set* wr_set=NULL; uintN argn; int result; - struct timeval tv = {0, 0}; jsrefcount rc; +#ifdef _WIN32 size_t i; SOCKET high=0; + fd_set socket_set; + fd_set* rd_set=NULL; + fd_set* wr_set=NULL; + struct timeval tv = {0, 0}; +#else + int timeout = 0; + struct pollfd *fds; + nfds_t nfds; + jsval objval = OBJECT_TO_JSVAL(obj); +#endif JS_SET_RVAL(cx, arglist, JSVAL_VOID); @@ -1666,11 +1759,17 @@ js_poll(JSContext *cx, uintN argc, jsval *arglist) for(argn=0;argn<argc;argn++) { if(JSVAL_IS_BOOLEAN(argv[argn])) poll_for_write=JSVAL_TO_BOOLEAN(argv[argn]); - else if(JSVAL_IS_NUMBER(argv[argn])) + else if(JSVAL_IS_NUMBER(argv[argn])) { +#ifdef _WIN32 js_timeval(cx,argv[argn],&tv); +#else + timeout = js_polltimeout(cx, argv[argn]); +#endif + } } rc=JS_SUSPENDREQUEST(cx); +#ifdef _WIN32 FD_ZERO(&socket_set); if(p->set) { for(i=0; i<p->set->sock_count; i++) { @@ -1692,10 +1791,28 @@ js_poll(JSContext *cx, uintN argc, jsval *arglist) result = 1; else result = select(high+1,rd_set,wr_set,NULL,&tv); +#else + if (p->peeked && !poll_for_write) { + result = 1; + } + else { + nfds = js_socket_numsocks(cx, objval); + fds = calloc(nfds, sizeof(*fds)); + if (fds == NULL) { + JS_RESUMEREQUEST(cx, rc); + JS_ReportError(cx, "Error allocating %d elements of %lu bytes at %s:%d" + , nfds, sizeof(*fds), getfname(__FILE__), __LINE__); + return JS_FALSE; + } + nfds = js_socket_add(cx, objval, fds, poll_for_write ? POLLOUT : POLLIN); + result = poll(fds, nfds, timeout); + free(fds); + } +#endif p->last_error=ERROR_VALUE; - dbprintf(FALSE, p, "poll: select returned %d (errno %d)" + dbprintf(FALSE, p, "poll: select/poll returned %d (errno %d)" ,result,p->last_error); JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(result)); @@ -2415,9 +2532,6 @@ js_connected_socket_constructor(JSContext *cx, uintN argc, jsval *arglist) char pstr[6]; jsrefcount rc; int nonblock; - struct timeval tv; - fd_set wfd; - fd_set efd; scfg_t *scfg; char error[256]; uint16_t bindport = 0; @@ -2623,35 +2737,17 @@ js_connected_socket_constructor(JSContext *cx, uintN argc, jsval *arglist) #endif for(;p->sock!=INVALID_SOCKET;) { // TODO: Do clever timeout stuff here. - tv.tv_sec=timeout; - tv.tv_usec=0; - - FD_ZERO(&wfd); - FD_SET(p->sock, &wfd); - FD_ZERO(&efd); - FD_SET(p->sock, &efd); - switch(select(p->sock+1, NULL, &wfd, &efd, &tv)) { - case 0: - // fall-through - case -1: - closesocket(p->sock); - p->sock=INVALID_SOCKET; - continue; - case 1: - if(FD_ISSET(p->sock, &efd)) { - closesocket(p->sock); - p->sock=INVALID_SOCKET; - continue; - } - else { - if(socket_check(p->sock, NULL, NULL, 0)) - goto connected; - closesocket(p->sock); - p->sock=INVALID_SOCKET; - continue; - } - default: - break; + if (socket_writable(p->sock, timeout * 1000)) { + if(!socket_recvdone(p->sock, 0)) + goto connected; + closesocket(p->sock); + p->sock=INVALID_SOCKET; + continue; + } + else { + closesocket(p->sock); + p->sock=INVALID_SOCKET; + continue; } } diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c index 37edaa93a6a3934586eaac8ba2a54dc548f39b91..17295323c8a22759d4fde304ac6ab7630365d1f0 100644 --- a/src/sbbs3/mailsrvr.c +++ b/src/sbbs3/mailsrvr.c @@ -338,8 +338,6 @@ int sockprintf(SOCKET sock, const char* prot, CRYPT_SESSION sess, char *fmt, ... int result; va_list argptr; char sbuf[1024]; - fd_set socket_set; - struct timeval tv; va_start(argptr,fmt); len=vsnprintf(sbuf,maxlen=sizeof(sbuf)-2,fmt,argptr); @@ -357,20 +355,10 @@ int sockprintf(SOCKET sock, const char* prot, CRYPT_SESSION sess, char *fmt, ... return(0); } - /* Check socket for writability (using select) */ - tv.tv_sec=300; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) { - if(result==0) - lprintf(LOG_NOTICE,"%04d %s !TIMEOUT selecting socket for send" - ,sock, prot); - else - lprintf(LOG_NOTICE,"%04d %s !ERROR %d selecting socket for send" - ,sock, prot, ERROR_VALUE); + /* Check socket for writability */ + if (!socket_writable(sock, 300000)) { + lprintf(LOG_NOTICE,"%04d %s !NOTICE socket did not become writable" + ,sock, prot); return(0); } @@ -436,8 +424,6 @@ static void sockerror(SOCKET socket, const char* prot, int rd, const char* actio static int sock_recvbyte(SOCKET sock, const char* prot, CRYPT_SESSION sess, char *buf, time_t start) { int len=0; - fd_set socket_set; - struct timeval tv; int ret; int i; @@ -467,24 +453,12 @@ static int sock_recvbyte(SOCKET sock, const char* prot, CRYPT_SESSION sess, char } } else { - tv.tv_sec=startup->max_inactivity; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,&socket_set,NULL,NULL,&tv); - - if(i<1) { - if(i==0) { - if(startup->max_inactivity && (time(NULL)-start)>startup->max_inactivity) { - lprintf(LOG_WARNING,"%04d %s !TIMEOUT in sock_recvbyte (%u seconds): INACTIVE SOCKET" - ,sock, prot, startup->max_inactivity); - return(-1); - } - return 0; + if (!socket_readable(sock, startup->max_inactivity * 1000)) { + if(startup->max_inactivity && (time(NULL)-start)>startup->max_inactivity) { + lprintf(LOG_WARNING,"%04d %s !TIMEOUT in sock_recvbyte (%u seconds): INACTIVE SOCKET" + ,sock, prot, startup->max_inactivity); + return(-1); } - sockerror(sock,prot,i,"select"); return 0; } i=recv(sock, buf, 1, 0); diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp index 255613b664425b7dfb943e520e0c9a54be042041..f8b46fa74519c4d929adb793341d7c458f84c5e6 100644 --- a/src/sbbs3/main.cpp +++ b/src/sbbs3/main.cpp @@ -1868,11 +1868,12 @@ void input_thread(void *arg) int i,rd,wr,avail; ulong total_recv=0; ulong total_pkts=0; - fd_set socket_set; sbbs_t* sbbs = (sbbs_t*) arg; - struct timeval tv; - SOCKET high_socket; - SOCKET sock; + SOCKET sock; +#ifndef _WIN32 + struct pollfd fds[2]; + int nfds; +#endif SetThreadName("sbbs/termInput"); thread_up(TRUE /* setuid */); @@ -1889,55 +1890,32 @@ void input_thread(void *arg) if(pthread_mutex_lock(&sbbs->input_thread_mutex)!=0) sbbs->errormsg(WHERE,ERR_LOCK,"input_thread_mutex",0); - FD_ZERO(&socket_set); - FD_SET(sbbs->client_socket,&socket_set); - high_socket=sbbs->client_socket; -#ifdef __unix__ - if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET) { - FD_SET(uspy_socket[sbbs->cfg.node_num-1],&socket_set); - if(uspy_socket[sbbs->cfg.node_num-1] > high_socket) - high_socket=uspy_socket[sbbs->cfg.node_num-1]; +#ifdef _WIN32 + if (!socket_readable(sbbs->client_socket, 1000)) { + if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0) + sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0); + YIELD(); /* This kludge is necessary on some Linux distros */ + continue; /* to allow other threads to lock the input_thread_mutex */ } -#endif - - tv.tv_sec=1; - tv.tv_usec=0; - - if((i=select(high_socket+1,&socket_set,NULL,NULL,&tv))<1) { +#else + fds[0].fd = sbbs->client_socket; + fds[0].events = POLLIN; + fds[0].revents = 0; + nfds = 1; + if (uspy_socket[sbbs->cfg.node_num-1] != INVALID_SOCKET) { + fds[0].fd = uspy_socket[sbbs->cfg.node_num-1]; + fds[0].events = POLLIN; + fds[0].revents = 0; + nfds++; + } + + if (poll(fds, nfds, 1000) < 1) { if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0) sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0); - if(i==0) { - YIELD(); /* This kludge is necessary on some Linux distros */ - continue; /* to allow other threads to lock the input_thread_mutex */ - } - - if(sbbs->client_socket==INVALID_SOCKET) - break; -#ifdef __unix__ - if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET) { - if(!socket_check(uspy_socket[sbbs->cfg.node_num-1],NULL,NULL,0)) { - close_socket(uspy_socket[sbbs->cfg.node_num-1]); - lprintf(LOG_NOTICE,"Closing local spy socket: %d",uspy_socket[sbbs->cfg.node_num-1]); - uspy_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET; - continue; - } - } -#endif - if(ERROR_VALUE == ENOTSOCK) - lprintf(LOG_NOTICE,"Node %d socket closed by peer on input->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==ESHUTDOWN) - lprintf(LOG_NOTICE,"Node %d socket shutdown on input->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==EINTR) - lprintf(LOG_DEBUG,"Node %d input thread interrupted",sbbs->cfg.node_num); - else if(ERROR_VALUE==ECONNRESET) - lprintf(LOG_NOTICE,"Node %d connection reset by peer on input->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==ECONNABORTED) - lprintf(LOG_NOTICE,"Node %d connection aborted by peer on input->select", sbbs->cfg.node_num); - else - lprintf(LOG_WARNING,"Node %d !ERROR %d input->select socket %d" - ,sbbs->cfg.node_num, ERROR_VALUE, sbbs->client_socket); - break; + YIELD(); /* This kludge is necessary on some Linux distros */ + continue; /* to allow other threads to lock the input_thread_mutex */ } +#endif if(sbbs->client_socket==INVALID_SOCKET) { if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0) @@ -1956,12 +1934,13 @@ void input_thread(void *arg) * ------------ */ - if(FD_ISSET(sbbs->client_socket,&socket_set)) - sock=sbbs->client_socket; -#ifdef __unix__ - else if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET - && FD_ISSET(uspy_socket[sbbs->cfg.node_num-1],&socket_set)) { - if(!socket_check(uspy_socket[sbbs->cfg.node_num-1],NULL,NULL,0)) { +#ifdef _WIN32 + sock=sbbs->client_socket; +#else + if (fds[0].revents | POLLIN) + sock = sbbs->client_socket; + else if(uspy_socket[sbbs->cfg.node_num - 1] != INVALID_SOCKET && fds[1].revents | POLLIN) { + if(socket_recvdone(uspy_socket[sbbs->cfg.node_num-1], 0)) { close_socket(uspy_socket[sbbs->cfg.node_num-1]); lprintf(LOG_NOTICE,"Closing local spy socket: %d",uspy_socket[sbbs->cfg.node_num-1]); uspy_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET; @@ -1971,12 +1950,12 @@ void input_thread(void *arg) } sock=uspy_socket[sbbs->cfg.node_num-1]; } -#endif else { if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0) sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0); continue; } +#endif rd=RingBufFree(&sbbs->inbuf); @@ -2168,10 +2147,7 @@ void sbbs_t::passthru_socket_activate(bool activate) */ void passthru_thread(void* arg) { - fd_set r_set; sbbs_t *sbbs = (sbbs_t*) arg; - struct timeval tv; - int i; int rd; char inbuf[IO_THREAD_BUF_SIZE / 2]; @@ -2179,34 +2155,14 @@ void passthru_thread(void* arg) thread_up(FALSE /* setuid */); while(sbbs->online && sbbs->passthru_socket!=INVALID_SOCKET && !terminate_server) { - tv.tv_sec=1; - tv.tv_usec=0; - - FD_ZERO(&r_set); - FD_SET(sbbs->passthru_socket,&r_set); - if((i=select(sbbs->passthru_socket+1,&r_set,NULL,NULL,&tv))<1) { - if(i==0) { - YIELD(); /* This kludge is necessary on some Linux distros */ - continue; /* to allow other threads to lock the input_thread_mutex */ - } + if (!socket_readable(sbbs->passthru_socket, 1000)) { + YIELD(); /* This kludge is necessary on some Linux distros */ + continue; /* to allow other threads to lock the input_thread_mutex */ + } - if(sbbs->passthru_socket==INVALID_SOCKET) - break; - if(ERROR_VALUE == ENOTSOCK) - lprintf(LOG_NOTICE,"Node %d socket closed by peer on passthru->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==ESHUTDOWN) - lprintf(LOG_NOTICE,"Node %d socket shutdown on passthru->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==EINTR) - lprintf(LOG_DEBUG,"Node %d passthru thread interrupted",sbbs->cfg.node_num); - else if(ERROR_VALUE==ECONNRESET) - lprintf(LOG_NOTICE,"Node %d connection reset by peer on passthru->select", sbbs->cfg.node_num); - else if(ERROR_VALUE==ECONNABORTED) - lprintf(LOG_NOTICE,"Node %d connection aborted by peer on passthru->select", sbbs->cfg.node_num); - else - lprintf(LOG_WARNING,"Node %d !ERROR %d passthru->select socket %d" - ,sbbs->cfg.node_num, ERROR_VALUE, sbbs->passthru_socket); + if(sbbs->passthru_socket==INVALID_SOCKET) break; - } + rd = RingBufFree(&sbbs->outbuf) / 2; if(rd > (int)sizeof(inbuf)) rd = sizeof(inbuf); @@ -2281,8 +2237,6 @@ void output_thread(void* arg) ulong bufbot=0; ulong buftop=0; sbbs_t* sbbs = (sbbs_t*) arg; - fd_set socket_set; - struct timeval tv; ulong mss=IO_THREAD_BUF_SIZE; ulong ssh_errors = 0; @@ -2400,27 +2354,8 @@ void output_thread(void* arg) continue; } - /* Check socket for writability (using select) */ - tv.tv_sec=0; - tv.tv_usec=1000; - - FD_ZERO(&socket_set); - if(sbbs->client_socket==INVALID_SOCKET) // Make the race condition less likely to actually happen... TODO: Fix race - continue; - FD_SET(sbbs->client_socket,&socket_set); - - i=select(sbbs->client_socket+1,NULL,&socket_set,NULL,&tv); - if(i==SOCKET_ERROR) { - if(sbbs->client_socket!=INVALID_SOCKET) - lprintf(LOG_WARNING,"%s !ERROR %d selecting socket %u for send" - ,node,ERROR_VALUE,sbbs->client_socket); - if(sbbs->cfg.node_num) /* Only break if node output (not server) */ - break; - RingBufReInit(&sbbs->outbuf); /* Purge output ring buffer */ - bufbot=buftop=0; /* Purge linear buffer */ - continue; - } - if(i<1) { + /* Check socket for writability */ + if (!socket_writable(sbbs->client_socket, 1)) { continue; } diff --git a/src/sbbs3/mxlookup.c b/src/sbbs3/mxlookup.c index 20c719bca475f5daecb8ef027f9821028e23db9e..94620c944600f33933dd4fa90f446c460992b7b9 100644 --- a/src/sbbs3/mxlookup.c +++ b/src/sbbs3/mxlookup.c @@ -184,8 +184,6 @@ int dns_getmx(char* name, char* mx, char* mx2 dns_msghdr_t msghdr; dns_query_t query; dns_rr_t* rr; - struct timeval tv; - fd_set socket_set; int sess = -1; mx[0]=0; @@ -255,19 +253,9 @@ int dns_getmx(char* name, char* mx, char* mx2 len-=sizeof(msghdr.length); } - /* check for writability (using select) */ - tv.tv_sec=timeout; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,NULL,&socket_set,NULL,&tv); - if(i<1) { - if(i==SOCKET_ERROR) - result=ERROR_VALUE; - else - result=-1; + /* check for writability */ + if (!socket_writable(sock, timeout * 1000)) { + result =- 1; mail_close_socket(&sock, &sess); return(result); } @@ -287,19 +275,9 @@ int dns_getmx(char* name, char* mx, char* mx2 return(result); } - /* check for readability (using select) */ - tv.tv_sec=timeout; - tv.tv_usec=0; - - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - - i=select(sock+1,&socket_set,NULL,NULL,&tv); - if(i<1) { - if(i==SOCKET_ERROR) - result=ERROR_VALUE; - else - result=-1; + /* check for readability */ + if (!socket_readable(sock, timeout * 1000)) { + result = -1; mail_close_socket(&sock, &sess); return(result); } diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h index aa495d10fd27e0b51442c771aa2590cc47c9c643..de4db437bc56992439a41af619503881e418a1fc 100644 --- a/src/sbbs3/sbbs.h +++ b/src/sbbs3/sbbs.h @@ -1352,10 +1352,16 @@ extern "C" { DLLEXPORT JSObject* DLLCALL js_CreateSocketObjectFromSet(JSContext* cx, JSObject* parent ,char *name, struct xpms_set *set); - DLLEXPORT void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv); DLLEXPORT SOCKET DLLCALL js_socket(JSContext *cx, jsval val); + DLLEXPORT int js_polltimeout(JSContext* cx, jsval val); +#ifdef _WIN32 + DLLEXPORT void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv); DLLEXPORT SOCKET DLLCALL js_socket_add(JSContext *cx, jsval val, fd_set *fds); DLLEXPORT BOOL DLLCALL js_socket_isset(JSContext *cx, jsval val, fd_set *fds); +#else + DLLEXPORT size_t js_socket_numsocks(JSContext *cx, jsval val); + DLLEXPORT size_t js_socket_add(JSContext *cx, jsval val, struct pollfd *fds, short events); +#endif /* js_queue.c */ DLLEXPORT JSObject* DLLCALL js_CreateQueueClass(JSContext* cx, JSObject* parent); diff --git a/src/sbbs3/sbbs_status.c b/src/sbbs3/sbbs_status.c index 842b615a46c4d53ea9396271adc90561bc846556..6a86bb3b64c9eb031a6e5469fabb0f097d3f50c2 100644 --- a/src/sbbs3/sbbs_status.c +++ b/src/sbbs3/sbbs_status.c @@ -434,8 +434,6 @@ void status_thread(void *arg) SOCKET sock; struct sockaddr_un addr; socklen_t addrlen; - fd_set fd; - struct timeval tv; SOCKET *csock; char auth[1024]; ssize_t len; @@ -542,11 +540,7 @@ void status_thread(void *arg) pthread_mutex_lock(&status_thread_mutex); while (!status_thread_terminated) { pthread_mutex_unlock(&status_thread_mutex); - FD_ZERO(&fd); - FD_SET(sock, &fd); - memset(&tv, 0, sizeof(tv)); - tv.tv_sec = 1; - if (select(sock+1, &fd, NULL, NULL, &tv) == 1) { + if (socket_readable(sock, 1000)) { csock = malloc(sizeof(SOCKET)); if (csock == NULL) { lprintf(LOG_CRIT, "Error allocating memory!"); @@ -558,11 +552,7 @@ void status_thread(void *arg) if (*csock != INVALID_SOCKET) { nb = 1; ioctlsocket(*csock, FIONBIO, &nb); - FD_ZERO(&fd); - FD_SET(*csock, &fd); - memset(&tv, 0, sizeof(tv)); - tv.tv_sec = 5; - if (select((*csock)+1, &fd, NULL, NULL, &tv) == 1) { + if (socket_readable(*csock, 5000)) { len = recv(*csock, auth, sizeof(auth), 0); if (len <= 0) { closesocket(*csock); @@ -712,7 +702,7 @@ void status_thread(void *arg) else { closesocket(*csock); free(csock); - lprintf(LOG_WARNING, "select() for recv() failed"); + lprintf(LOG_WARNING, "socket did not become readable"); pthread_mutex_lock(&status_thread_mutex); continue; } diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c index aa7741fd205f5b5af9e93e1a23d7ef96b0f827e9..618dd8cc9593615a527c56d5548a1c1705432359 100644 --- a/src/sbbs3/services.c +++ b/src/sbbs3/services.c @@ -1722,6 +1722,43 @@ void service_udp_sock_cb(SOCKET sock, void *cbdata) #endif } +#ifndef _WIN32 +/* + * Sets up the fds for poll, and returns the total sockets + */ +static nfds_t setup_poll(struct pollfd **fds) +{ + int i, j; + nfds_t nfds = 0; + + free(*fds); + for(i=0;i<(int)services;i++) { + if(service[i].options&SERVICE_OPT_STATIC) + continue; + if(service[i].set==NULL) + continue; + nfds += service[i].set->sock_count; + } + + *fds = calloc(nfds, sizeof(**fds)); + if (*fds == NULL) + return 0; + nfds = 0; + for(i=0;i<(int)services;i++) { + if(service[i].options&SERVICE_OPT_STATIC) + continue; + if(service[i].set==NULL) + continue; + for(j=0; j<service[i].set->sock_count; j++) { + (*fds)[nfds].fd = service[i].set->socks[j].sock; + (*fds)[nfds].events = POLLIN; + nfds++; + } + } + return nfds; +} +#endif + void DLLCALL services_thread(void* arg) { char* p; @@ -1745,14 +1782,20 @@ void DLLCALL services_thread(void* arg) ulong total_running; time_t t; time_t initialized=0; - fd_set socket_set; - SOCKET high_socket; ulong total_sockets; - struct timeval tv; service_client_t* client; char *ssl_estr; int level; BOOL need_cert = FALSE; +#ifdef _WIN32 + fd_set socket_set; + SOCKET high_socket; + struct timeval tv; +#else + struct pollfd *fds = NULL; + nfds_t nfds; + nfds_t nfdsi; +#endif startup=(services_startup_t*)arg; @@ -1958,6 +2001,14 @@ void DLLCALL services_thread(void* arg) lprintf(LOG_INFO,"0000 Services thread started (%lu service sockets bound)", total_sockets); +#ifndef _WIN32 + nfds = setup_poll(&fds); + if (nfds == 0) { + lprintf(LOG_CRIT, "!ERROR setting up poll() data"); + cleanup(1); + return; + } +#endif /* Main Server Loop */ while(!terminated) { YIELD(); @@ -1983,6 +2034,7 @@ void DLLCALL services_thread(void* arg) } } +#ifdef _WIN32 /* Setup select() parms */ FD_ZERO(&socket_set); high_socket=0; @@ -2027,7 +2079,49 @@ void DLLCALL services_thread(void* arg) for(j=0; j<service[i].set->sock_count; j++) { if(!FD_ISSET(service[i].set->socks[j].sock,&socket_set)) continue; +#else + /* Clear poll FDs where necessary (ie: when !SERVICE_OPT_FULL_ACCEPT) */ + nfdsi = 0; + for(i=0;i<(int)services;i++) { + if(service[i].options&SERVICE_OPT_STATIC) + continue; + if(service[i].set==NULL) + continue; + if(!(service[i].options&SERVICE_OPT_FULL_ACCEPT)) { + if (service[i].max_clients && protected_uint32_value(service[i].clients) >= service[i].max_clients) { + for(j=0; j<service[i].set->sock_count; j++) + fds[nfdsi + j].fd = -1; + } + else { + for(j=0; j<service[i].set->sock_count; j++) + fds[nfdsi + j].fd = service[i].set->socks[j].sock; + } + } + nfdsi += service[i].set->sock_count; + } + + if ((result = poll(fds, nfds, startup->sem_chk_freq * 1000)) < 1) { + if(result==0) + continue; + if(ERROR_VALUE==EINTR) + lprintf(LOG_DEBUG,"0000 Services listening interrupted"); + else + lprintf(LOG_WARNING,"0000 !ERROR %d polling sockets: %s" + , ERROR_VALUE, socket_strerror(socket_errno,error,sizeof(error))); + continue; + } + nfdsi = 0; + for(i=0;i<(int)services;i++) { + if(service[i].options&SERVICE_OPT_STATIC) + continue; + if(service[i].set==NULL) + continue; + + for(j=0; j<service[i].set->sock_count; j++) { + if ((fds[nfdsi + j].revents & POLLIN) == 0) + continue; +#endif client_addr_len = sizeof(client_addr); udp_len=0; @@ -2202,8 +2296,14 @@ void DLLCALL services_thread(void* arg) service[i].served++; served++; } +#ifndef _WIN32 + nfdsi += service[i].set->sock_count; +#endif } } +#ifndef _WIN32 + free(fds); +#endif /* Close Service Sockets */ lprintf(LOG_DEBUG,"0000 Closing service sockets"); diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c index 26d40e4444320041a321635e0d253ebded3009fd..37ad91bf57a0cb072742f2ac40183944c4413007 100644 --- a/src/sbbs3/websrvr.c +++ b/src/sbbs3/websrvr.c @@ -626,9 +626,6 @@ static int sess_sendbuf(http_session_t *session, const char *buf, size_t len, BO size_t sent=0; int tls_sent; int result; - int sel; - fd_set wr_set; - struct timeval tv; int status; BOOL local_failed = FALSE; @@ -636,67 +633,56 @@ static int sess_sendbuf(http_session_t *session, const char *buf, size_t len, BO failed = &local_failed; while(sent<len && session->socket!=INVALID_SOCKET && *failed == FALSE) { - FD_ZERO(&wr_set); - FD_SET(session->socket,&wr_set); - /* Convert timeout from ms to sec/usec */ - tv.tv_sec=startup->max_inactivity; - tv.tv_usec=0; - sel=select(session->socket+1,NULL,&wr_set,NULL,&tv); - switch(sel) { - case 1: - if (session->is_tls) { - /* - * Limit as per js_socket.c. - * Sure, this is TLS, not SSH, but we see weird stuff here in sz file transfers. - */ - size_t sendbytes = len-sent; - if (sendbytes > 0x2000) - sendbytes = 0x2000; - status = cryptPushData(session->tls_sess, buf+sent, sendbytes, &tls_sent); - GCES(status, session, "pushing data"); - if (status == CRYPT_ERROR_TIMEOUT) { - tls_sent = 0; - if(!cryptStatusOK(status=cryptPopData(session->tls_sess, "", 0, &status))) { - if (status != CRYPT_ERROR_TIMEOUT && status != CRYPT_ERROR_PARAM2) - GCES(status, session, "popping data after timeout"); - } - status = CRYPT_OK; - } - if(cryptStatusOK(status)) { - HANDLE_CRYPT_CALL_EXCEPT(status = cryptFlushData(session->tls_sess), session, "flushing data", CRYPT_ERROR_COMPLETE); - if (cryptStatusError(status)) - *failed=TRUE; - return tls_sent; + if (socket_writable(session->socket, startup->max_inactivity * 1000)) { + if (session->is_tls) { + /* + * Limit as per js_socket.c. + * Sure, this is TLS, not SSH, but we see weird stuff here in sz file transfers. + */ + size_t sendbytes = len-sent; + if (sendbytes > 0x2000) + sendbytes = 0x2000; + status = cryptPushData(session->tls_sess, buf+sent, sendbytes, &tls_sent); + GCES(status, session, "pushing data"); + if (status == CRYPT_ERROR_TIMEOUT) { + tls_sent = 0; + if(!cryptStatusOK(status=cryptPopData(session->tls_sess, "", 0, &status))) { + if (status != CRYPT_ERROR_TIMEOUT && status != CRYPT_ERROR_PARAM2) + GCES(status, session, "popping data after timeout"); } - *failed=TRUE; - result = tls_sent; + status = CRYPT_OK; } - else { - result=sendsocket(session->socket,buf+sent,len-sent); - if(result==SOCKET_ERROR) { - if(ERROR_VALUE==ECONNRESET) - lprintf(LOG_NOTICE,"%04d Connection reset by peer on send",session->socket); - else if(ERROR_VALUE==ECONNABORTED) - lprintf(LOG_NOTICE,"%04d Connection aborted by peer on send",session->socket); -#ifdef EPIPE - else if(ERROR_VALUE==EPIPE) - lprintf(LOG_NOTICE,"%04d Unable to send to peer",session->socket); -#endif - else - lprintf(LOG_WARNING,"%04d !ERROR %d sending on socket",session->socket,ERROR_VALUE); + if(cryptStatusOK(status)) { + HANDLE_CRYPT_CALL_EXCEPT(status = cryptFlushData(session->tls_sess), session, "flushing data", CRYPT_ERROR_COMPLETE); + if (cryptStatusError(status)) *failed=TRUE; - return(sent); - } + return tls_sent; } - break; - case 0: - lprintf(LOG_WARNING,"%04d Timeout selecting socket for write",session->socket); *failed=TRUE; - return(sent); - case -1: - lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket for write",session->socket,ERROR_VALUE); - *failed=TRUE; - return(sent); + result = tls_sent; + } + else { + result=sendsocket(session->socket,buf+sent,len-sent); + if(result==SOCKET_ERROR) { + if(ERROR_VALUE==ECONNRESET) + lprintf(LOG_NOTICE,"%04d Connection reset by peer on send",session->socket); + else if(ERROR_VALUE==ECONNABORTED) + lprintf(LOG_NOTICE,"%04d Connection aborted by peer on send",session->socket); +#ifdef EPIPE + else if(ERROR_VALUE==EPIPE) + lprintf(LOG_NOTICE,"%04d Unable to send to peer",session->socket); +#endif + else + lprintf(LOG_WARNING,"%04d !ERROR %d sending on socket",session->socket,ERROR_VALUE); + *failed=TRUE; + return(sent); + } + } + } + else { + lprintf(LOG_WARNING,"%04d Timeout waiting for socket to become writable",session->socket); + *failed=TRUE; + return(sent); } sent+=result; } @@ -977,11 +963,9 @@ static int close_socket(SOCKET *sock) /* required to ensure all data is sent */ shutdown(*sock,SHUT_WR); - while(socket_check(*sock, &rd, NULL, startup->max_inactivity*1000)) { - if (rd) { - if (recv(*sock,&ch,1,0) <= 0) - break; - } + while(socket_readable(*sock, startup->max_inactivity * 1000)) { + if (recv(*sock,&ch,1,0) <= 0) + break; if (time(NULL) >= end) break; } @@ -2097,35 +2081,21 @@ static int sess_recv(http_session_t *session, char *buf, size_t length, int flag static int sockreadline(http_session_t * session, char *buf, size_t length) { char ch; - int sel; DWORD i; DWORD chucked=0; - fd_set rd_set; - struct timeval tv; for(i=0;TRUE;) { if(session->socket==INVALID_SOCKET) return(-1); if ((!session->is_tls) || (!session->tls_pending)) { - FD_ZERO(&rd_set); - FD_SET(session->socket,&rd_set); - /* Convert timeout from ms to sec/usec */ - tv.tv_sec=startup->max_inactivity; - tv.tv_usec=0; - sel=select(session->socket+1,&rd_set,NULL,NULL,&tv); - switch(sel) { - case 1: - if (session->is_tls) - session->tls_pending=TRUE; - break; - case -1: - close_session_socket(session); - lprintf(LOG_DEBUG,"%04d !ERROR %d selecting socket for read",session->socket,ERROR_VALUE); - return(-1); - default: - /* Timeout */ - lprintf(LOG_NOTICE,"%04d Session timeout due to inactivity (%d seconds)",session->socket,startup->max_inactivity); - return(-1); + if (socket_readable(session->socket, startup->max_inactivity * 1000)) { + if (session->is_tls) + session->tls_pending=TRUE; + } + else { + /* Timeout */ + lprintf(LOG_NOTICE,"%04d Session timeout due to inactivity (%d seconds)",session->socket,startup->max_inactivity); + return(-1); } } @@ -2179,10 +2149,6 @@ static int pipereadline(int pipe, char *buf, size_t length, char *fullbuf, size_ char ch; DWORD i; int ret=0; -#ifndef _WIN32 - struct timeval tv={0,0}; - fd_set read_set; -#endif /* Terminate buffers */ if(buf != NULL) @@ -2194,11 +2160,7 @@ static int pipereadline(int pipe, char *buf, size_t length, char *fullbuf, size_ ret=0; ReadFile(pipe, &ch, 1, (DWORD*)&ret, NULL); #else - tv.tv_sec=startup->max_cgi_inactivity; - tv.tv_usec=0; - FD_ZERO(&read_set); - FD_SET(pipe, &read_set); - if(select(pipe+1, &read_set, NULL, NULL, &tv)<1) + if (!socket_readable(pipe, startup->max_cgi_inactivity * 1000)) return(-1); ret=read(pipe, &ch, 1); #endif @@ -3824,10 +3786,8 @@ static SOCKET fastcgi_connect(const char *orig_path, SOCKET client_sock) char *path = strdup(orig_path); char *port = split_port_part(path); ulong val; - fd_set socket_set; SOCKET sock; struct addrinfo hints,*res,*cur; - struct timeval tv; // TODO: UNIX-domain sockets... if (strncmp(path, "unix:", 5) == 0) { @@ -3847,9 +3807,6 @@ static SOCKET fastcgi_connect(const char *orig_path, SOCKET client_sock) return INVALID_SOCKET; } for(cur=res,result=1; result && cur; cur=cur->ai_next) { - tv.tv_sec = 1; /* TODO: Make configurable! */ - tv.tv_usec = 0; - sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); if (sock == INVALID_SOCKET) continue; @@ -3859,9 +3816,7 @@ static SOCKET fastcgi_connect(const char *orig_path, SOCKET client_sock) if (result==SOCKET_ERROR) { if((ERROR_VALUE==EWOULDBLOCK || ERROR_VALUE==EINPROGRESS)) { - FD_ZERO(&socket_set); - FD_SET(sock,&socket_set); - if(select(sock+1,NULL,&socket_set,NULL,&tv)==1) + if (socket_writable(sock, 1000 /* TODO: Make configurable! */)) result=0; /* success */ } else @@ -4064,54 +4019,52 @@ static int fastcgi_read_wait_timeout(void *arg) break; } - if (socket_check(cd->sock, &rd, NULL, startup->max_cgi_inactivity*1000)) { - if (rd) { - if (recv(cd->sock, (void *)&cd->header, offsetof(struct fastcgi_header, len), MSG_WAITALL) != offsetof(struct fastcgi_header, len)) { - lprintf(LOG_ERR, "FastCGI failed to read header"); - return ret; - } - if (cd->header.ver != FCGI_VERSION_1) { - lprintf(LOG_ERR, "Unknown FastCGI version %d", cd->header.ver); - return ret; - } - if (htons(cd->header.id) != 1) { - lprintf(LOG_ERR, "Unknown FastCGI session ID %d", htons(cd->header.id)); - return ret; - } - switch(cd->header.type) { - case FCGI_STDOUT: - ret |= CGI_OUTPUT_READY; - break; - case FCGI_STDERR: - ret |= CGI_OUTPUT_READY; - break; - case FCGI_END_REQUEST: - ret |= CGI_PROCESS_TERMINATED; - cd->request_ended = 1; - // Fall-through - case FCGI_BEGIN_REQUEST: - case FCGI_ABORT_REQUEST: - case FCGI_PARAMS: - case FCGI_STDIN: - case FCGI_DATA: - case FCGI_GET_VALUES: - case FCGI_GET_VALUES_RESULT: - case FCGI_UNKNOWN_TYPE: - // Read and discard the entire message... - body = fastcgi_read_body(cd->sock); - if (body == NULL) - return ret; - free(body); - break; - default: - lprintf(LOG_ERR, "Unhandled FastCGI message type %d", cd->header.type); - // Read and discard the entire message... - body = fastcgi_read_body(cd->sock); - if (body == NULL) - return ret; - free(body); - break; - } + if (socket_readable(cd->sock, startup->max_cgi_inactivity*1000)) { + if (recv(cd->sock, (void *)&cd->header, offsetof(struct fastcgi_header, len), MSG_WAITALL) != offsetof(struct fastcgi_header, len)) { + lprintf(LOG_ERR, "FastCGI failed to read header"); + return ret; + } + if (cd->header.ver != FCGI_VERSION_1) { + lprintf(LOG_ERR, "Unknown FastCGI version %d", cd->header.ver); + return ret; + } + if (htons(cd->header.id) != 1) { + lprintf(LOG_ERR, "Unknown FastCGI session ID %d", htons(cd->header.id)); + return ret; + } + switch(cd->header.type) { + case FCGI_STDOUT: + ret |= CGI_OUTPUT_READY; + break; + case FCGI_STDERR: + ret |= CGI_OUTPUT_READY; + break; + case FCGI_END_REQUEST: + ret |= CGI_PROCESS_TERMINATED; + cd->request_ended = 1; + // Fall-through + case FCGI_BEGIN_REQUEST: + case FCGI_ABORT_REQUEST: + case FCGI_PARAMS: + case FCGI_STDIN: + case FCGI_DATA: + case FCGI_GET_VALUES: + case FCGI_GET_VALUES_RESULT: + case FCGI_UNKNOWN_TYPE: + // Read and discard the entire message... + body = fastcgi_read_body(cd->sock); + if (body == NULL) + return ret; + free(body); + break; + default: + lprintf(LOG_ERR, "Unhandled FastCGI message type %d", cd->header.type); + // Read and discard the entire message... + body = fastcgi_read_body(cd->sock); + if (body == NULL) + return ret; + free(body); + break; } } else @@ -4219,41 +4172,28 @@ static int fastcgi_done_wait(void *arg) if (cd->request_ended) return 1; - return (!socket_check(cd->sock, NULL, NULL, /* timeout: */0)); + return (socket_recvdone(cd->sock, 0)); } #ifdef __unix__ struct cgi_data { - int out_pipe; // out_pipe[0] - int err_pipe; // err_pipe[0] pid_t child; // child + struct pollfd fds[2]; }; static int cgi_read_wait_timeout(void *arg) { int ret = 0; int status=0; - int high_fd; - fd_set read_set; - fd_set write_set; struct cgi_data *cd = (struct cgi_data *)arg; - struct timeval tv; - - high_fd = cd->err_pipe; - if (cd->out_pipe > cd->err_pipe) - high_fd = cd->out_pipe; - tv.tv_sec=startup->max_cgi_inactivity; - tv.tv_usec=0; - FD_ZERO(&read_set); - FD_SET(cd->out_pipe,&read_set); - FD_SET(cd->err_pipe,&read_set); - FD_ZERO(&write_set); + cd->fds[0].events = POLLIN; + cd->fds[1].events = POLLIN; - if(select(high_fd+1,&read_set,&write_set,NULL,&tv)>0) { - if (FD_ISSET(cd->out_pipe,&read_set)) + if (poll(cd->fds, 2, startup->max_cgi_inactivity * 1000) > 0) { + if (cd->fds[0].revents & POLLIN) ret |= CGI_OUTPUT_READY; - if(FD_ISSET(cd->err_pipe,&read_set)) + if (cd->fds[1].revents & POLLIN) ret |= CGI_ERROR_READY; } @@ -4266,21 +4206,21 @@ static int cgi_read_out(void *arg, char *buf, size_t sz) { struct cgi_data *cd = (struct cgi_data *)arg; - return read(cd->out_pipe,buf,sz); + return read(cd->fds[0].fd, buf, sz); } static int cgi_read_err(void *arg, char *buf, size_t sz) { struct cgi_data *cd = (struct cgi_data *)arg; - return read(cd->err_pipe,buf,sz); + return read(cd->fds[1].fd, buf, sz); } static int cgi_readln_out(void *arg, char *buf, size_t bufsz, char *fbuf, size_t fbufsz) { struct cgi_data *cd = (struct cgi_data *)arg; - return pipereadline(cd->out_pipe, buf, bufsz, fbuf, fbufsz); + return pipereadline(cd->fds[0].fd, buf, bufsz, fbuf, fbufsz); } static int cgi_write_in(void *arg, char *buf, size_t bufsz) @@ -4717,10 +4657,6 @@ static BOOL exec_cgi(http_session_t *session) int in_pipe[2]; int out_pipe[2]; int err_pipe[2]; - struct timeval tv={0,0}; - fd_set read_set; - fd_set write_set; - int high_fd=0; char buf[1024]; BOOL done_parsing_headers=FALSE; BOOL done_wait=FALSE; @@ -4836,16 +4772,15 @@ static BOOL exec_cgi(http_session_t *session) // TODO: For TLS-CGI, write each separate read... if (session->tls_sess && session->req.post_len && session->req.post_data) { - tv.tv_sec=1; - tv.tv_usec=0; - FD_ZERO(&read_set); - high_fd = in_pipe[1]; - FD_SET(in_pipe[1], &write_set); sent = 0; + cd.fds[0].fd = in_pipe[1]; + cd.fds[0].events = POLLOUT; while(sent < session->req.post_len) { - if (select(high_fd+1, NULL, &write_set, NULL, &tv) > 0) { - if (FD_ISSET(in_pipe[1], &write_set)) + if (poll(cd.fds, 1, 1000) > 0) { + if (cd.fds[0].revents & POLLIN) i = write(in_pipe[1], &session->req.post_data[sent], session->req.post_len - sent); + else + i = 0; if (i > 0) sent += i; else { @@ -4857,7 +4792,7 @@ static BOOL exec_cgi(http_session_t *session) } } else { - lprintf(LOG_INFO, "%04d FAILED selecting CGI stding for write", session->socket); + lprintf(LOG_INFO, "%04d FAILED polling CGI stding for write", session->socket); close(in_pipe[1]); close(out_pipe[0]); close(err_pipe[0]); @@ -4866,12 +4801,8 @@ static BOOL exec_cgi(http_session_t *session) } } - high_fd=out_pipe[0]; - if(err_pipe[0]>high_fd) - high_fd=err_pipe[0]; - - cd.out_pipe = out_pipe[0]; - cd.err_pipe = err_pipe[0]; + cd.fds[0].fd = out_pipe[0]; + cd.fds[1].fd = err_pipe[0]; cd.child = child; int ret = do_cgi_stuff(session, &cgi, orig_keep); @@ -4902,13 +4833,8 @@ static BOOL exec_cgi(http_session_t *session) if (session->tls_sess) close(in_pipe[1]); /* close excess file descriptor */ /* Drain STDERR & STDOUT */ - tv.tv_sec=1; - tv.tv_usec=0; - FD_ZERO(&read_set); - FD_SET(err_pipe[0],&read_set); - FD_SET(out_pipe[0],&read_set); - while(select(high_fd+1,&read_set,NULL,NULL,&tv)>0) { - if(FD_ISSET(err_pipe[0],&read_set)) { + while(poll(cd.fds, 2, 1000) > 0) { + if(cd.fds[1].revents & POLLIN) { i=read(err_pipe[0],buf,sizeof(buf)-1); if(i!=-1 && i!=0) { buf[i]=0; @@ -4916,8 +4842,8 @@ static BOOL exec_cgi(http_session_t *session) } } - if(FD_ISSET(out_pipe[0],&read_set)) { - i=read(out_pipe[0],buf,sizeof(buf)); + if(cd.fds[0].revents & POLLIN) { + i=read(cd.fds[0].fd, buf, sizeof(buf)); if(i!=-1 && i!=0) { int snt=0; snt=writebuf(session,buf,i); @@ -4928,12 +4854,6 @@ static BOOL exec_cgi(http_session_t *session) if(i==0 || i==-1) break; - - tv.tv_sec=1; - tv.tv_usec=0; - FD_ZERO(&read_set); - FD_SET(err_pipe[0],&read_set); - FD_SET(out_pipe[0],&read_set); } close(out_pipe[0]); /* close read-end of pipe */ diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp index 43c2de570df87f8acd0ff0f466bec9d46b3db36d..e4039fe179f3feffbe29af5722cf77db0cea2d76 100644 --- a/src/sbbs3/xtrn.cpp +++ b/src/sbbs3/xtrn.cpp @@ -1069,12 +1069,10 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) int in_pipe[2]; int out_pipe[2]; int err_pipe[2]; - fd_set ibits; - int high_fd; - struct timeval timeout; BYTE wwiv_buf[XTRN_IO_BUF_LEN*2]; bool wwiv_flag=false; char* p; + struct pollfd fds[2]; xtrn_mode = mode; lprintf(LOG_DEBUG, "Executing external: %s", cmdline); @@ -1689,6 +1687,11 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) if(mode&EX_STDOUT) { if(!(mode&EX_STDIN)) close(out_pipe[1]); /* close write-end of pipe */ + fds[0].fd = out_pipe[0]; + fds[0].events = POLLIN; + fds[1].fd = err_pipe[0]; + fds[1].events = POLLIN; + fds[1].revents = 0; while(!terminated) { if(waitpid(pid, &i, WNOHANG)!=0) /* child exited */ break; @@ -1707,26 +1710,13 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) write(in_pipe[1],buf,wr); } - /* Error Output */ - FD_ZERO(&ibits); - if(!(mode&EX_NOLOG)) { - FD_SET(err_pipe[0],&ibits); - high_fd=err_pipe[0]; - } - FD_SET(out_pipe[0],&ibits); - if(!(mode&EX_NOLOG)) { - if(out_pipe[0]>err_pipe[0]) - high_fd=out_pipe[0]; - } else - high_fd=out_pipe[0]; - timeout.tv_sec=0; - timeout.tv_usec=1000; bp=buf; i=0; if(mode&EX_NOLOG) - select(high_fd+1,&ibits,NULL,NULL,&timeout); + poll(fds, (mode & EX_NOLOG) ? 1 : 2, 1); else { - while ((select(high_fd+1,&ibits,NULL,NULL,&timeout)>0) && FD_ISSET(err_pipe[0],&ibits) && (i<(int)sizeof(buf)-1)) { + while (poll(fds, (mode & EX_NOLOG) ? 1 : 2, 1) > 0 && (fds[1].revents & POLLIN) + && (i < (int)sizeof(buf) - 1)) { if((rd=read(err_pipe[0],bp,1))>0) { i+=rd; bp++; @@ -1735,11 +1725,6 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) } else break; - FD_ZERO(&ibits); - FD_SET(err_pipe[0],&ibits); - FD_SET(out_pipe[0],&ibits); - timeout.tv_sec=0; - timeout.tv_usec=1000; } if(i > 0) { buf[i] = '\0'; @@ -1757,7 +1742,7 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) } } - data_waiting=FD_ISSET(out_pipe[0],&ibits); + data_waiting=fds[0].revents & POLLIN; if(i==0 && data_waiting==0) continue; @@ -1846,13 +1831,9 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir) waitpid(pid, &i, 0); else { while(waitpid(pid, &i, WNOHANG)==0) { - FD_ZERO(&ibits); - FD_SET(err_pipe[0],&ibits); - timeout.tv_sec=1; - timeout.tv_usec=0; bp=buf; i=0; - while ((select(err_pipe[0]+1,&ibits,NULL,NULL,&timeout)>0) && (i<XTRN_IO_BUF_LEN-1)) { + while (socket_readable(err_pipe[0], 1000) && (i<XTRN_IO_BUF_LEN-1)) { if((rd=read(err_pipe[0],bp,1))>0) { i+=rd; if(*bp=='\n') {