Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Jan 2001 18:23:11 -0800 (PST)
From:      =?ISO-8859-1?Q?Mikko_Ty=F6l=E4j=E4rvi?= <mikko@dynas.se>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/24472: libc_r does not honor SO_SNDTIMEO/SO_RCVTIMEO socket options
Message-ID:  <Pine.BSF.4.21.0101191815561.520-100000@atlas.home.dynas.se>

next in thread | raw e-mail | index | archive | help

>Number:         24472
>Category:       bin
>Synopsis:       libc_r does not honor SO_SNDTIMEO/SO_RCVTIMEO socket options
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jan 19 18:30:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Mikko Tyolajarvi
>Release:        FreeBSD 4.2-STABLE i386
>Organization:
>Environment:

4.2-STABLE as of  Jan 19, 2001

>Description:

The socket options SO_SNDTIMEO and SO_RCVTIMEO which can be used to
make blocking socket I/O operations time out are ignored by libc_r.

>How-To-Repeat:

Uh, like, try to use them...  Operations will block forever.

>Fix:

The patch below adds support for the missing socket options
in the uthread library.  In short:

 - Timeout values are cached per fd
 - The timeouts are imported when data on the fd is initialised
 - They are updated when calling {set,get}sockopt()
 - When blocking on an I/O operation, and the fd is a socket, and it
   has a timeout defined, limit the time to sleep, and return an
   error code (or in some cases a short count) on timeout.

Affected functions are:

 Sets timeout values:  getsockopt, setsockopt, dup, dup2, fcntl

 I/O: read, readv, recvfrom, recvmsg, sendfile, sendmsg, sendto,
      write, writev

The patch has been somewhat tested, but I wouldn't install it in a
live system controlling nuclear power plants without some additional
review.

       $.02,
	/Mikko

diff -ru uthread.org/pthread_private.h uthread/pthread_private.h
--- uthread.org/pthread_private.h	Sat Nov 25 10:10:27 2000
+++ uthread/pthread_private.h	Fri Jan 19 17:26:49 2001
@@ -550,6 +550,8 @@
 	int			r_lockcount;	/* Count for FILE read locks.         */
 	int			w_lockcount;	/* Count for FILE write locks.        */
 	int			flags;		/* Flags used in open.                */
+	struct timespec		rcvtimeo;	/* Input timeout for sockets          */
+	struct timespec		sndtimeo;	/* Output timeout for sockets         */
 };
 
 struct pthread_poll_data {
@@ -1193,6 +1195,11 @@
 #define	_FD_LOCK(_fd,_type,_ts)		_thread_fd_lock(_fd, _type, _ts)
 #define _FD_UNLOCK(_fd,_type)		_thread_fd_unlock(_fd, _type)
 #endif
+
+/* Get a suitable argument for _thread_kern_set_timeout(), given an fd */
+#define _FD_TIMEO(_ts)		(((_ts)->tv_sec || (_ts)->tv_nsec) ? (_ts) : NULL)
+#define _FD_RCVTIMEO(_fd)	_FD_TIMEO(&_thread_fd_table[(_fd)]->rcvtimeo)
+#define _FD_SNDTIMEO(_fd)	_FD_TIMEO(&_thread_fd_table[(_fd)]->sndtimeo)
 
 /*
  * Function prototype definitions.
diff -ru uthread.org/uthread_dup.c uthread/uthread_dup.c
--- uthread.org/uthread_dup.c	Sat Jan 29 14:53:41 2000
+++ uthread/uthread_dup.c	Fri Jan 19 16:26:34 2001
@@ -59,6 +59,10 @@
 			 * checked later: 
 			 */
 			_thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags;
+
+			/* Copy socket timeouts: */
+			_thread_fd_table[ret]->rcvtimeo = _thread_fd_table[fd]->rcvtimeo;
+			_thread_fd_table[ret]->sndtimeo = _thread_fd_table[fd]->sndtimeo;
 		}
 
 		/* Unlock the file descriptor: */
diff -ru uthread.org/uthread_dup2.c uthread/uthread_dup2.c
--- uthread.org/uthread_dup2.c	Sat Jan 29 14:53:42 2000
+++ uthread/uthread_dup2.c	Fri Jan 19 16:26:53 2001
@@ -71,6 +71,10 @@
 				 * be checked     later: 
 				 */
 				_thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags;
+
+				/* Copy socket timeouts: */
+				_thread_fd_table[ret]->rcvtimeo = _thread_fd_table[fd]->rcvtimeo;
+				_thread_fd_table[ret]->sndtimeo = _thread_fd_table[fd]->sndtimeo;
 			}
 
 			/* Unlock the file descriptor: */
diff -ru uthread.org/uthread_fcntl.c uthread/uthread_fcntl.c
--- uthread.org/uthread_fcntl.c	Fri Jan 28 14:10:27 2000
+++ uthread/uthread_fcntl.c	Fri Jan 19 16:27:12 2001
@@ -78,6 +78,10 @@
 				 * be         checked later: 
 				 */
 				_thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags;
+
+				/* Copy socket timeouts: */
+				_thread_fd_table[ret]->rcvtimeo = _thread_fd_table[fd]->rcvtimeo;
+				_thread_fd_table[ret]->sndtimeo = _thread_fd_table[fd]->sndtimeo;
 			}
 			break;
 		case F_SETFD:
diff -ru uthread.org/uthread_fd.c uthread/uthread_fd.c
--- uthread.org/uthread_fd.c	Sat Nov 25 10:10:27 2000
+++ uthread/uthread_fd.c	Fri Jan 19 17:40:31 2001
@@ -39,6 +39,7 @@
 #ifdef _THREAD_SAFE
 #include <pthread.h>
 #include "pthread_private.h"
+#include <sys/socket.h>
 
 #define FDQ_INSERT(q,p)					\
 do {							\
@@ -76,6 +77,8 @@
 	int	ret = 0;
 	struct fd_table_entry *entry;
 	int	saved_errno;
+	struct timeval tv;
+	socklen_t tlen;
 
 	/* Check if the file descriptor is out of range: */
 	if (fd < 0 || fd >= _thread_dtablesize) {
@@ -112,6 +115,19 @@
 		/* Initialise the read/write queues: */
 		TAILQ_INIT(&entry->r_queue);
 		TAILQ_INIT(&entry->w_queue);
+
+		/* Initialise socket timeouts: */
+		tlen = sizeof(tv);
+		if (_thread_sys_getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &tlen) < 0) {
+			entry->rcvtimeo.tv_sec = 0;
+			entry->rcvtimeo.tv_nsec = 0;
+			entry->sndtimeo.tv_sec = 0;
+			entry->sndtimeo.tv_nsec = 0;
+		} else {
+			TIMEVAL_TO_TIMESPEC(&tv, &entry->rcvtimeo);
+			_thread_sys_getsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, &tlen);
+			TIMEVAL_TO_TIMESPEC(&tv, &entry->sndtimeo);
+		}
 
 		/* Get the flags for the file: */
 		if (((fd >= 3) || (_pthread_stdio_flags[fd] == -1)) &&
diff -ru uthread.org/uthread_getsockopt.c uthread/uthread_getsockopt.c
--- uthread.org/uthread_getsockopt.c	Sat Jan 29 14:53:48 2000
+++ uthread/uthread_getsockopt.c	Fri Jan 19 17:24:47 2001
@@ -45,6 +45,16 @@
 
 	if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
 		ret = _thread_sys_getsockopt(fd, level, optname, optval, optlen);
+		if (ret == 0 && level == SOL_SOCKET) {
+			switch (optname) {
+			case SO_SNDTIMEO:
+				TIMEVAL_TO_TIMESPEC((struct timeval *)optval, &_thread_fd_table[fd]->sndtimeo);
+				break;
+			case SO_RCVTIMEO:
+				TIMEVAL_TO_TIMESPEC((struct timeval *)optval, &_thread_fd_table[fd]->rcvtimeo);
+				break;
+			}
+		}
 		_FD_UNLOCK(fd, FD_RDWR);
 	}
 	return ret;
diff -ru uthread.org/uthread_read.c uthread/uthread_read.c
--- uthread.org/uthread_read.c	Thu Jan 27 15:07:13 2000
+++ uthread/uthread_read.c	Fri Jan 19 16:56:15 2001
@@ -70,10 +70,11 @@
 			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
 			    (errno == EWOULDBLOCK || errno == EAGAIN)) {
 				_thread_run->data.fd.fd = fd;
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_RCVTIMEO(fd));
 
 				/* Reset the interrupted operation flag: */
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 
 				_thread_kern_sched_state(PS_FDR_WAIT,
 				    __FILE__, __LINE__);
@@ -87,6 +88,10 @@
 					ret = -1;
 					break;
 				}
+
+				/* Socket timer timed out: */
+				if (_thread_run->timeout)
+					break;
 			} else {
 				break;
 			}
diff -ru uthread.org/uthread_readv.c uthread/uthread_readv.c
--- uthread.org/uthread_readv.c	Sat Jan 29 14:53:49 2000
+++ uthread/uthread_readv.c	Fri Jan 19 16:56:05 2001
@@ -65,10 +65,11 @@
 			if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 &&
 			    (errno == EWOULDBLOCK || errno == EAGAIN)) {
 				_thread_run->data.fd.fd = fd;
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_RCVTIMEO(fd));
 
 				/* Reset the interrupted operation flag: */
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 
 				_thread_kern_sched_state(PS_FDR_WAIT,
 				    __FILE__, __LINE__);
@@ -82,6 +83,10 @@
 					ret = -1;
 					break;
 				}
+
+				/* Socket timer timed out: */
+				if (_thread_run->timeout)
+					break;
 			} else {
 				break;
 			}
diff -ru uthread.org/uthread_recvfrom.c uthread/uthread_recvfrom.c
--- uthread.org/uthread_recvfrom.c	Sat Jan 29 14:53:50 2000
+++ uthread/uthread_recvfrom.c	Fri Jan 19 16:57:03 2001
@@ -51,8 +51,9 @@
 				_thread_run->data.fd.fd = fd;
 
 				/* Set the timeout: */
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_RCVTIMEO(fd));
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 				_thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);
 
 				/* Check if the wait was interrupted: */
@@ -62,6 +63,8 @@
 					ret = -1;
 					break;
 				}
+				if (_thread_run->timeout)
+					break;
 			} else {
 				ret = -1;
 				break;
diff -ru uthread.org/uthread_recvmsg.c uthread/uthread_recvmsg.c
--- uthread.org/uthread_recvmsg.c	Sat Jan 29 14:53:50 2000
+++ uthread/uthread_recvmsg.c	Fri Jan 19 16:57:55 2001
@@ -50,8 +50,9 @@
 				_thread_run->data.fd.fd = fd;
 
 				/* Set the timeout: */
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_RCVTIMEO(fd));
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 				_thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__);
 
 				/* Check if the wait was interrupted: */
@@ -61,6 +62,8 @@
 					ret = -1;
 					break;
 				}
+				if (_thread_run->timeout)
+					break;
 			} else {
 				ret = -1;
 				break;
diff -ru uthread.org/uthread_sendfile.c uthread/uthread_sendfile.c
--- uthread.org/uthread_sendfile.c	Sat Nov 25 10:10:28 2000
+++ uthread/uthread_sendfile.c	Fri Jan 19 17:17:59 2001
@@ -109,10 +109,11 @@
 			num += n;
 
 			_thread_run->data.fd.fd = fd;
-			_thread_kern_set_timeout(NULL);
+			_thread_kern_set_timeout(_FD_SNDTIMEO(fd));
 
 			/* Reset the interrupted operation flag. */
 			_thread_run->interrupted = 0;
+			_thread_run->timeout = 0;
 
 			_thread_kern_sched_state(PS_FDW_WAIT, __FILE__,
 			    __LINE__);
@@ -121,6 +122,8 @@
 				/* Interrupted by a signal.  Return an error. */
 				break;
 			}
+			if (_thread_run->timeout)
+				break;
 		} else {
 			/* Incomplete non-blocking syscall, or error. */
 			break;
diff -ru uthread.org/uthread_sendmsg.c uthread/uthread_sendmsg.c
--- uthread.org/uthread_sendmsg.c	Sat Jan 29 14:53:51 2000
+++ uthread/uthread_sendmsg.c	Fri Jan 19 17:08:02 2001
@@ -50,8 +50,9 @@
 				_thread_run->data.fd.fd = fd;
 
 				/* Set the timeout: */
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_SNDTIMEO(fd));
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 				_thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__);
 
 				/* Check if the operation was interrupted: */
@@ -60,6 +61,8 @@
 					ret = -1;
 					break;
 				}
+				if (_thread_run->timeout)
+					break;
 			} else {
 				ret = -1;
 				break;
diff -ru uthread.org/uthread_sendto.c uthread/uthread_sendto.c
--- uthread.org/uthread_sendto.c	Sat Jan 29 14:53:51 2000
+++ uthread/uthread_sendto.c	Fri Jan 19 17:09:12 2001
@@ -51,8 +51,9 @@
 				_thread_run->data.fd.fd = fd;
 
 				/* Set the timeout: */
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_SNDTIMEO(fd));
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 				_thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__);
 
 				/* Check if the operation was interrupted: */
@@ -61,6 +62,8 @@
 					ret = -1;
 					break;
 				}
+				if (_thread_run->timeout)
+					break;
 			} else {
 				ret = -1;
 				break;
diff -ru uthread.org/uthread_setsockopt.c uthread/uthread_setsockopt.c
--- uthread.org/uthread_setsockopt.c	Sat Jan 29 14:53:52 2000
+++ uthread/uthread_setsockopt.c	Fri Jan 19 17:25:41 2001
@@ -45,6 +45,16 @@
 
 	if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
 		ret = _thread_sys_setsockopt(fd, level, optname, optval, optlen);
+		if (ret == 0 && level == SOL_SOCKET) {
+			switch (optname) {
+			case SO_SNDTIMEO:
+				TIMEVAL_TO_TIMESPEC((struct timeval *)optval, &_thread_fd_table[fd]->sndtimeo);
+				break;
+			case SO_RCVTIMEO:
+				TIMEVAL_TO_TIMESPEC((struct timeval *)optval, &_thread_fd_table[fd]->rcvtimeo);
+				break;
+			}
+		}
 		_FD_UNLOCK(fd, FD_RDWR);
 	}
 	return ret;
diff -ru uthread.org/uthread_write.c uthread/uthread_write.c
--- uthread.org/uthread_write.c	Sat Nov 25 10:10:31 2000
+++ uthread/uthread_write.c	Fri Jan 19 17:15:57 2001
@@ -95,10 +95,11 @@
 			if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
 			    errno == EAGAIN)) || (n >= 0 && num < nbytes))) {
 				_thread_run->data.fd.fd = fd;
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_SNDTIMEO(fd));
 
 				/* Reset the interrupted operation flag: */
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 
 				_thread_kern_sched_state(PS_FDW_WAIT,
 				    __FILE__, __LINE__);
@@ -110,6 +111,15 @@
 				if (_thread_run->interrupted) {
 					/* Return an error: */
 					ret = -1;
+				}
+				if (_thread_run->timeout) {
+					/* Return a short count or an error */
+					if (num > 0) {
+						ret = num;
+					} else {
+						ret = -1;
+						errno = EWOULDBLOCK;
+					}
 				}
 
 			/*
diff -ru uthread.org/uthread_writev.c uthread/uthread_writev.c
--- uthread.org/uthread_writev.c	Sat Jan 29 14:53:55 2000
+++ uthread/uthread_writev.c	Fri Jan 19 17:20:59 2001
@@ -159,10 +159,11 @@
 			if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
 			    errno == EAGAIN)) || (n >= 0 && idx < iovcnt))) {
 				_thread_run->data.fd.fd = fd;
-				_thread_kern_set_timeout(NULL);
+				_thread_kern_set_timeout(_FD_SNDTIMEO(fd));
 
 				/* Reset the interrupted operation flag: */
 				_thread_run->interrupted = 0;
+				_thread_run->timeout = 0;
 
 				_thread_kern_sched_state(PS_FDW_WAIT,
 				    __FILE__, __LINE__);
@@ -174,6 +175,15 @@
 				if (_thread_run->interrupted) {
 					/* Return an error: */
 					ret = -1;
+				}
+				if (_thread_run->timeout) {
+					/* Return a short count or an error */
+					if (num > 0) {
+						ret = num;
+					} else {
+						ret = -1;
+						errno = EWOULDBLOCK;
+					}
 				}
 
 			/*


 Mikko Työläjärvi_______________________________________mikko@rsasecurity.com
 RSA Security


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.21.0101191815561.520-100000>