Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Jul 2014 23:24:20 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Dmitry Sivachenko <trtrmitya@gmail.com>
Cc:        freebsd-net@freebsd.org
Subject:   Re: does setsockopt(SO_RCVTIMEO) work?
Message-ID:  <20140716223814.O2597@besplex.bde.org>
In-Reply-To: <F6D31298-F070-4CB8-ADFF-243302A6CE1E@gmail.com>
References:  <F6D31298-F070-4CB8-ADFF-243302A6CE1E@gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 16 Jul 2014, Dmitry Sivachenko wrote:

> I am having trouble using {g,s}etsockopt(SO_RCVTIMEO).  Consider the following small test program.
> I expect to retrieve the value of 1 second via getsockopt call, I expect the following output:
> tv_sec=1, tv_usec=0
> But I actually get
> tv_sec=0, tv_usec=0
>
> What am I missing?
>
> Thanks!
>
> PS: on Linux it works as I expect.

On old versions of FreeBSD it works as expected.

This was broken last year.  I pointed out the bug and many others in my
review, but it is still there.  From the review:

@ On Sun, 1 Sep 2013, Davide Italiano wrote:
@ 
@ > Log:
@ >  Fix socket buffer timeouts precision using the new sbintime_t KPI instead
@ >  of relying on the tvtohz() workaround. The latter has been introduced
@ >  lately by jhb@ (r254699) in order to have a fix that can be backported
@ >  to STABLE.
@ >
@ >  Reported by:	Vitja Makarov <vitja.makarov at gmail dot com>
@ >  Reviewed by:	jhb (earlier version)
@ 
@ This reintroduces overflow bugs that were fixed by using tvtohz().  tvtohz()
@ clamps the value to INT_MAX instead of overflowing, but tvtosbt() just
@ overflows.

These bugs are small (they are are only for timevals larger than INT_MAX
seconds, which can only occur on systems with bloated 64-bit time_t's),
but they were fixed long ago.

@ 
@ This gives much larger overflow bugs in getsockopt().

This bug is still there.  So in your test program, the timeout is set
correctly, but it is returned as 0 after overflow of a large value
gives 0.  All values larger than 1 second are truncated to less than
1 second.

I expected more garbage in the values for timevals between 0.5 seconds
(inclusive) and 1.0 seconds (not inclusive).  I think they would happen
for the corresonding bug in setsockopt(), but in getsockopt() there is
only a small (but annoying) rounding error.  I tried a timeval of
0 seconds, 500000 microseconds.  This was returned as 0 seconds,
499999 microseconds.  This rounding error happens because almost no values
in the power-of-10 time scale for timevals can be represented in the
power-of-2 time scale for sbintimes.  The rounding is always down, so
conversion back and forth drops 1 ULP in almost all cases.  bintime
gives similar errors.  sys/time.h has a large comment defending this
bug.

@ 
@ > ...
@ > Modified: head/sys/kern/uipc_socket.c
@ > ==============================================================================
@ > --- head/sys/kern/uipc_socket.c	Sun Sep  1 23:06:28 2013	(r255137)
@ > +++ head/sys/kern/uipc_socket.c	Sun Sep  1 23:34:53 2013	(r255138)
@ > @@ -2541,7 +2541,7 @@ sosetopt(struct socket *so, struct socko
@ > 	int	error, optval;
@ > 	struct	linger l;
@ > 	struct	timeval tv;
@ > -	u_long  val;
@ > +	sbintime_t val;
@ > 	uint32_t val32;
@ > #ifdef MAC
@ > 	struct mac extmac;
@ 
@ This fixes a style bug (type error) that should have been fixed in the
@ previous commit.  'int optval' is used for most options, but the old
@ code needed `u_long val' for its home made conversion.  u_long became
@ unnecessary and the extra variable became bogus when tvtohz() was used,
@ since optval can hold tvtohz().
@ 
@ > @@ -2703,7 +2703,7 @@ sosetopt(struct socket *so, struct socko
@ > 				error = EDOM;
@ > 				goto bad;
@ > 			}
@ 
@ There used to be more range checking above here.  Some was moved into
@ tvtohz().  Changing to tvtosbt() moves it to /dev/null.
@ 
@ > -			val = tvtohz(&tv);
@ > +			val = tvtosbt(tv);
@ >
@ > 			switch (sopt->sopt_name) {
@ > 			case SO_SNDTIMEO:
@ 
@ optval can't hold tvtosbt(), so an extra variable is not a large style
@ bug now.  But it can be avoided here by doing 2 assignments of tvtosbt()
@ to so_snd/rcv.sb_timeout.

'val' _can_ hold tvtosbt() (it was enlarged to do this), so there is only
a far-off overflow bug here (when tvtosbt() overflows internally)).

@ 
@ > @@ -2857,8 +2857,7 @@ integer:
@ > 			optval = (sopt->sopt_name == SO_SNDTIMEO ?
@ > 				  so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
@ 
@ This is now very broken.  optval is only int, so it can't hold the 64-bit
@ sbintime_t.  I think it can hold times less than 0.5 seconds.  Overflow
@ starts at 0.5 seconds by giving sign extension bugs on 2's complement machines.
@ 
@ Style bug: non-KNF indentation.

This still has all its bugs and style bugs.

@ 
@ >
@ 
@ Style bug: extra blank line separates related code.
@ 
@ > -			tv.tv_sec = optval / hz;
@ > -			tv.tv_usec = (optval % hz) * tick;
@ > +			tv = sbttotv(optval);
@ 
@ This together with the style can be fixed by 2 assignments also (1
@ assignment in the conditional operater also fixes verbosenes):
@ 
@  			tv = sbttotv(sopt->sopt_name == SO_SNDTIMEO ?
@  			    so->so_snd.sb_timeo : so->so_rcv.sb_timeo);

Fix for the main bug some style bugs.

[... 200 more lines with further duscussion of style and overflow bugs]

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20140716223814.O2597>