Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Dec 2001 12:08:41 +0100 (CET)
From:      Hartmut Brandt <brandt@fokus.gmd.de>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/32827: small SO_RCVTIMEO values are taken to be zero
Message-ID:  <200112141108.fBEB8fL69040@fokus.gmd.de>

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

>Number:         32827
>Category:       kern
>Synopsis:       small SO_RCVTIMEO values are taken to be zero
>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 Dec 14 03:10:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Hartmut Brandt
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
FhG Fokus
>Environment:
System: FreeBSD beagle.fokus.gmd.de 5.0-CURRENT FreeBSD 5.0-CURRENT #3: Mon Dec 10 11:29:08 CET 2001 hbb@beagle.fokus.gmd.de:/opt/obj/usr/src/sys/BEAGLE i386


	
>Description:

If the receive timeout of a socket is set to a number of microseconds larger
than 0 but lesser than the value of 'tick', the code in uipc_socket.c 

			/* assert(tick > 0); */
			/* assert(ULONG_MAX - SHRT_MAX >= 1000000); */
1250:			val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;
			if (val > SHRT_MAX) {
				error = EDOM;
				goto bad;

computes a timeout value for the socket of 0, causing subsequence receive
operations to block as if no timeout had been specified. This is unexpected
and not easily controllable by the application (one has to either fetch the
value of tick via sysctl or always make a getsockopt after the setsockopt).
Only timeout values with tv_sec==0 and tv_usec==0 should block indefinitely.

	
>How-To-Repeat:

Compile and run the following program and find it to timeout the first
receive after 1 second and to block forever on thesecond receive (given
no UDP packet is seen on 127.0.0.1:10000).

# include <sys/types.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <stdio.h>
# include <errno.h>
# include <string.h>
# include <err.h>
# include <netinet/in.h>

int
main(int argc, char *argv[])
{
	int s;
	struct timeval tv;
	struct sockaddr_in sin;
	u_char buf[1000];

	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
		err(1, "socket");

	sin.sin_len = sizeof(sin);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(10000);
	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
		err(1, "bind");

	tv.tv_sec = 1;
	tv.tv_usec = 0;
	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
		err(1, "setsockopt");

	printf("recv 1...\n");
	if (recv(s, buf, sizeof(buf), 0) == -1)
		warn("recv");

	tv.tv_sec = 0;
	tv.tv_usec = 100;
	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
		err(1, "setsockopt");

	printf("recv 2...\n");
	if (recv(s, buf, sizeof(buf), 0) == -1)
		warn("recv");

	return (0);
}
	

>Fix:

Apply the following patch to /usr/src/sys/kern/uipc_socket.c (this fixes
the same problem for the send case):

Index: uipc_socket.c
===================================================================
RCS file: /usr/ncvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.106
diff -r1.106 uipc_socket.c
1254a1255,1256
> 			if (val == 0 && (tv.tv_usec != 0 || tv.tv_sec != 0))
> 				val = 1;


	


>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?200112141108.fBEB8fL69040>