read timeout
Michael Weiser <[email protected]> Thu, 21 Dec 2006 17:51:29 +0100
| Newsgroups | gmane.comp.web.wget.patches |
|---|---|
| Message-ID | <[email protected]> |
--sm4nu43k4a2Rpi4c Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, please find attached a patch to get the --read-timeout option working with connections that hang in a read operation due to the server going offline or changing IP address. When a server goes offline in the middle of an HTTP request, the TCP connection will hang (almost?) indefinitely. Because it isn't closed or rejected but simply doesn't respond to IP packets any more, the select in fd_read will time out normally but then call sock_read which will block forever. There are a couple of scenarios in which this would accour: - the server actually doing down and staying down. After some time a router should start to generate "destination host unreachable" ICMP messages which in turn should reset the HTTP TCP connection but I'm not sure about that. - a firewall is activated on the server which drops all incoming packets. This wouldn't normally happen to a real server but can be used for testing. - a NAT router box inbetween wget and the server loses the connection information. This would be true for most DSL router boxes which get disconnected periodically by the provider, then reconnect and get a different IP. This invalidates all old connections which therefore will hang on the client and server side until they're somehow timed out. I added SO_SNDTIMEO and SO_RCVTIMEO socket options to the socket and put some handling for it into http.c and retr.c. Now I'd like to know if this actually makes any sense or just works around a braindead misunderstanding of mine. ;) I'm not subscribed to this list, so please Cc: to [email protected]. -- Thanks, Michael --sm4nu43k4a2Rpi4c Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="wget-1.10.2-readtimeout.patch" --- wget-1.10.2/src/connect.c.orig 2006-12-21 17:03:39.000000000 +0100 +++ wget-1.10.2/src/connect.c 2006-12-21 17:08:05.000000000 +0100 @@ -294,6 +294,26 @@ } #endif + if (opt.read_timeout) { + struct timeval tmout; + int err; + + tmout.tv_sec = (long) opt.read_timeout; + tmout.tv_usec = 1000000 * (opt.read_timeout - (long) opt.read_timeout); + + err = setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, &tmout, sizeof(tmout)); +#ifdef ENABLE_DEBUG + if (err < 0) + DEBUGP (("Failed setting SO_SNDTIMEO: %s", strerror (errno))); +#endif + + err = setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &tmout, sizeof(tmout)); +#ifdef ENABLE_DEBUG + if (err < 0) + DEBUGP (("Failed setting SO_RCVTIMEO: %s", strerror (errno))); +#endif + } + /* For very small rate limits, set the buffer size (and hence, hopefully, the kernel's TCP window size) to the per-second limit. That way we should never have to sleep for more than 1s between --- wget-1.10.2/src/http.c.orig 2005-08-09 00:54:16.000000000 +0200 +++ wget-1.10.2/src/http.c 2006-12-21 17:27:42.000000000 +0100 @@ -1960,6 +1960,9 @@ hs->restval, &hs->rd_size, &hs->len, &hs->dltime, flags); + if (hs->res < 0 && errno == ETIMEDOUT) + hs->res = -3; + if (hs->res >= 0) CLOSE_FINISH (sock); else @@ -1979,6 +1982,8 @@ } if (hs->res == -2) return FWRITEERR; + if (hs->res == -3) + return READERR; return RETRFINISHED; } --- wget-1.10.2/src/retr.c.orig 2005-06-25 17:07:11.000000000 +0200 +++ wget-1.10.2/src/retr.c 2006-12-21 17:30:45.000000000 +0100 @@ -290,6 +290,11 @@ if (progress_interactive && ret < 0 && errno == ETIMEDOUT) ret = 0; /* interactive timeout, handled above */ + else if (ret < 0 && errno == EWOULDBLOCK) { + ret = -1; /* socket read/write timeout */ + errno = ETIMEDOUT; + break; + } else if (ret <= 0) break; /* EOF or read error */ --sm4nu43k4a2Rpi4c--