Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

...
 
Commits (2)
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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;
}
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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");
......
This diff is collapsed.
......@@ -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;