diff --git a/src/syncterm/rlogin.c b/src/syncterm/rlogin.c index f1b6f5821e6fb8e49f22e79690bdbc1aacff2533..bdcb5719c26eb483d03991e1596804334f89c687 100644 --- a/src/syncterm/rlogin.c +++ b/src/syncterm/rlogin.c @@ -17,7 +17,6 @@ SOCKET rlogin_sock=INVALID_SOCKET; #endif void rlogin_input_thread(void *args) { - fd_set rds; int rd; int buffered; size_t buffer; @@ -25,24 +24,7 @@ void rlogin_input_thread(void *args) SetThreadName("RLogin Input"); conn_api.input_thread_running=1; while(rlogin_sock != INVALID_SOCKET && !conn_api.terminate) { - FD_ZERO(&rds); - FD_SET(rlogin_sock, &rds); -#ifdef __linux__ - { - struct timeval tv; - tv.tv_sec=0; - tv.tv_usec=500000; - rd=select(rlogin_sock+1, &rds, NULL, NULL, &tv); - } -#else - rd=select(rlogin_sock+1, &rds, NULL, NULL, NULL); -#endif - if(rd==-1) { - if(errno==EBADF) - break; - rd=0; - } - if(rd==1) { + if (socket_readable(rlogin_sock, -1)) { rd=recv(rlogin_sock, conn_api.rd_buf, conn_api.rd_buf_size, 0); if(rd <= 0) break; @@ -79,24 +61,7 @@ void rlogin_output_thread(void *args) pthread_mutex_unlock(&(conn_outbuf.mutex)); sent=0; while(sent < wr) { - FD_ZERO(&wds); - FD_SET(rlogin_sock, &wds); -#ifdef __linux__ - { - struct timeval tv; - tv.tv_sec=0; - tv.tv_usec=500000; - ret=select(rlogin_sock+1, NULL, &wds, NULL, &tv); - } -#else - ret=select(rlogin_sock+1, NULL, &wds, NULL, NULL); -#endif - if(ret==-1) { - if(errno==EBADF) - break; - ret=0; - } - if(ret==1) { + if (socket_writable(rlogin_sock, -1)) { ret=sendsocket(rlogin_sock, conn_api.wr_buf+sent, wr-sent); if(ret==-1) break; @@ -173,22 +138,16 @@ int rlogin_connect(struct bbslist *bbs) if(bbs->conn_type == CONN_TYPE_MBBS_GHOST) { char sbuf[80]; char rbuf[10]; - struct timeval tv; int idx, ret; - fd_set rds; - - FD_ZERO(&rds); - FD_SET(rlogin_sock, &rds); - - tv.tv_sec=1; - tv.tv_usec=0; /* Check to make sure GHost is actually listening */ sendsocket(rlogin_sock, "\r\nMBBS: PING\r\n", 14); idx = 0; - while ((ret = select(rlogin_sock+1, &rds, NULL, NULL, &tv))==1) { - recv(rlogin_sock, rbuf+idx, 1, 0); + while (socket_readable(rlogin_sock, 1000)) { + ret = recv(rlogin_sock, rbuf+idx, 1, 0); + if (ret == -1) + break; rbuf[++idx] = 0; /* It says ERROR, but this is a good response to PING. */ @@ -216,8 +175,10 @@ int rlogin_connect(struct bbslist *bbs) sendsocket(rlogin_sock, sbuf, strlen(sbuf)); idx = 0; - while ((ret = select(rlogin_sock+1, &rds, NULL, NULL, &tv))==1) { - recv(rlogin_sock, rbuf+idx, 1, 0); + while (socket_readable(rlogin_sock, 1000)) { + ret = recv(rlogin_sock, rbuf+idx, 1, 0); + if (ret == -1) + break; rbuf[++idx] = 0; /* GHost says it's launching the program, so pass terminal to user. */ diff --git a/src/syncterm/ssh.c b/src/syncterm/ssh.c index 1dcaae8b8edd61cc671034622cadd5f148f78ea2..0b45edaac5ecb2c67fa09a37f663e3352256d986 100644 --- a/src/syncterm/ssh.c +++ b/src/syncterm/ssh.c @@ -47,28 +47,15 @@ void cryptlib_error_message(int status, const char * msg) void ssh_input_thread(void *args) { - fd_set rds; int status; int rd; size_t buffered; size_t buffer; - struct timeval tv; SetThreadName("SSH Input"); conn_api.input_thread_running=1; while(ssh_active && !conn_api.terminate) { - FD_ZERO(&rds); - FD_SET(ssh_sock, &rds); - tv.tv_sec = 0; - tv.tv_usec = 100; - - rd=select(ssh_sock+1, &rds, NULL, NULL, &tv); - if(rd==-1) { - if(errno==EBADF) - break; - rd=0; - } - if(rd == 0) + if (!socket_readable(ssh_sock, 10)) continue; pthread_mutex_lock(&ssh_mutex); diff --git a/src/xpdev/sockwrap.c b/src/xpdev/sockwrap.c index 24cd894b100ee75e0cddba03acded4b48e1d96ad..d45fd475a3bf37f4d4b5068cbec8470b4b5b70cb 100644 --- a/src/xpdev/sockwrap.c +++ b/src/xpdev/sockwrap.c @@ -329,6 +329,138 @@ BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout) return(FALSE); } +/* + * Return TRUE if recv() will not block on socket + * Will block for timeout ms or forever if timeout is negative + * + * This means it will return true if recv() will return an error + * as well as if the socket is closed (and recv() will return 0) + */ +BOOL socket_readable(SOCKET sock, int timeout) +{ +#ifdef _WIN32 + fd_set rd_set; + struct timeval tv = {0}; + struct timeval *tvp = &tv; + + FD_ZERO(&rd_set); + FD_SET(sock, &rd_set); + if (timeout < 0) + tvp = NULL; + else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + } + + switch (select(sock+1, &rd_set, NULL, NULL, tvp)) { + case 0: // Nothing to read + return FALSE; + case 1: + return TRUE; + } + // Errors and unexpected cases + return TRUE; +#else + struct pollfd pfd = {0}; + pfd.fd = sock; + pfd.events = POLLIN; + + if (poll(&pfd, 1, timeout) == 1) + return TRUE; + return FALSE; +#endif +} + +/* + * Return TRUE if send() will not block on socket + * Will block for timeout ms or forever if timeout is negative + * + * This means it will return true if send() will return an error + * as well as if the socket is closed (and send() will return 0) + */ +BOOL socket_writable(SOCKET sock, int timeout) +{ +#ifdef _WIN32 + fd_set wr_set; + struct timeval tv = {0}; + struct timeval *tvp = &tv; + + FD_ZERO(&wr_set); + FD_SET(sock, &wr_set); + if (timeout < 0) + tvp = NULL; + else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + } + + switch (select(sock+1, NULL, &wr_set, NULL, tvp)) { + case 0: // Nothing to read + return FALSE; + case 1: + return TRUE; + } + // Errors and unexpected cases + return TRUE; +#else + struct pollfd pfd = {0}; + pfd.fd = sock; + pfd.events = POLLOUT; + + if (poll(&pfd, 1, timeout) == 1) + return TRUE; + return FALSE; +#endif +} + +/* + * Return TRUE if recv() will not block and will return zero + * or an error. This is *not* a test if a socket is + * disconnected, but rather that it is disconnected *AND* all + * data has been recv()ed. + */ +BOOL socket_recvdone(SOCKET sock, int timeout) +{ +#ifdef _WIN32 + fd_set rd_set; + struct timeval tv = {0}; + struct timeval *tvp = &tv; + char ch; + int rd; + + FD_ZERO(&rd_set); + FD_SET(sock, &rd_set); + if (timeout < 0) + tvp = NULL; + else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + } + + switch (select(sock+1, &rd_set, NULL, NULL, tvp)) { + case -1: // Error, call this disconnected + return TRUE; + case 0: // Nothing to read + return FALSE; + } + rd = recv(sock,&ch,1,MSG_PEEK); + if (rd == 1 || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) + return FALSE; + return TRUE; +#else + struct pollfd pfd = {0}; + pfd.fd = sock; + pfd.events = POLLIN; + + if (poll(&pfd, 1, timeout) == 1) { + if (pfd.revents & POLLIN) + return FALSE; + return TRUE; + } + return FALSE; +#endif +} + int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen ,uint retries, uint wait_secs ,const char* prot diff --git a/src/xpdev/sockwrap.h b/src/xpdev/sockwrap.h index b1bfd0aa0445d74089a69c620f1304c7e8aadbd5..79f394669312d72e57e184a14894df07bfdf4d3f 100644 --- a/src/xpdev/sockwrap.h +++ b/src/xpdev/sockwrap.h @@ -232,6 +232,32 @@ DLLEXPORT int xp_inet_pton(int af, const char *src, void *dst); #define inet_pton xp_inet_pton #endif +/* + * Return TRUE if recv() will not block on socket + * Will block for timeout ms or forever if timeout is negative + * + * This means it will return true if recv() will return an error + * as well as if the socket is closed (and recv() will return 0) + */ +DLLEXPORT BOOL socket_readable(SOCKET sock, int timeout); + +/* + * Return TRUE if send() will not block on socket + * Will block for timeout ms or forever if timeout is negative + * + * This means it will return true if send() will return an error + * as well as if the socket is closed (and send() will return 0) + */ +DLLEXPORT BOOL socket_writable(SOCKET sock, int timeout); + +/* + * Return TRUE if recv() will not block and will return zero + * or an error. This is *not* a test if a socket is + * disconnected, but rather that it is disconnected *AND* all + * data has been recv()ed. + */ +DLLEXPORT BOOL socket_recvdone(SOCKET sock, int timeout); + #ifdef __cplusplus } #endif