| Summary: | small SO_RCVTIMEO values are taken to be zero | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | brandt <brandt> | ||||
| Component: | kern | Assignee: | Maxim Konovalov <maxim> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 5.0-CURRENT | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
On Fri, 14 Dec 2001 12:08:41 +0100, Hartmut Brandt wrote:
> >Category: kern
> >Synopsis: small SO_RCVTIMEO values are taken to be zero
I've asked for review on the freebsd-audit mailing list. Hopefully,
someone will take a look soon.
Ciao,
Sheldon.
State Changed From-To: open->patched Fixed in rev. 1.138 src/sys/kern/uipc_socket.c in -CURRENT. Thanks for the patch! Responsible Changed From-To: freebsd-bugs->maxim Will MFC the diff in two weeks. State Changed From-To: patched->closed Fixed in rev. 1.138 and rev. 1.68.2.22 src/sys/kern/uipc_socket.c in -CURRENT and -STABLE. Thanks! |
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. Fix: Apply the following patch to /usr/src/sys/kern/uipc_socket.c (this fixes the same problem for the send case): 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); }