From: Fabian Keil Date: Fri, 12 Oct 2012 11:17:48 +0000 (+0000) Subject: Add drain_and_close_socket() X-Git-Tag: v_3_0_20~256 X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=commitdiff_plain;h=c076ee3df798ec00e61c1708d0b1e352971ee41c Add drain_and_close_socket() Apparently on some platforms immediately closing a client socket with both unread and written-but-not-yet-transmitted data may result in the connection being teared down prematurely, in which case the client ends up with an incomplete response. To prevent this, drain_and_close_socket() shuts down our side of the connection (on platforms with shutdown()), drains the unread data on the socket and finally calls close_socket(). I suspect that this was the main cause of the page truncation issues reported with Opera in #3464439. --- diff --git a/configure.in b/configure.in index 5d164b78..16bbcc42 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. dnl -dnl $Id: configure.in,v 1.172 2012/10/12 11:12:22 fabiankeil Exp $ +dnl $Id: configure.in,v 1.173 2012/10/12 11:15:17 fabiankeil Exp $ dnl dnl Written by and Copyright (C) 2001-2010 the dnl Privoxy team. http://www.privoxy.org/ @@ -32,7 +32,7 @@ dnl ================================================================= dnl AutoConf Initialization dnl ================================================================= -AC_REVISION($Revision: 1.172 $) +AC_REVISION($Revision: 1.173 $) AC_INIT(jcc.c) if test ! -f config.h.in; then @@ -761,6 +761,7 @@ AC_CHECK_FUNCS([ \ regcomp \ select \ setlocale \ + shutdown \ snprintf \ socket \ strchr \ diff --git a/jbsockets.c b/jbsockets.c index 56226510..2e20a83f 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -1,4 +1,4 @@ -const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.113 2012/03/09 16:23:50 fabiankeil Exp $"; +const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.114 2012/03/09 17:56:41 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $ @@ -703,6 +703,68 @@ void close_socket(jb_socket fd) #else close(fd); #endif +} + + +/********************************************************************* + * + * Function : drain_and_close_socket + * + * Description : Closes a TCP/IP socket after draining unread data + * + * Parameters : + * 1 : fd = file descriptor of the socket to be closed + * + * Returns : void + * + *********************************************************************/ +void drain_and_close_socket(jb_socket fd) +{ +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if (socket_is_still_alive(fd)) +#endif + { + int bytes_drained_total = 0; + int bytes_drained; + +#ifdef HAVE_SHUTDOWN +/* Apparently Windows has shutdown() but now SHUT_WR */ +#ifndef SHUT_WR +#define SHUT_WR 1 +#endif + if (0 != shutdown(fd, SHUT_WR)) + { + log_error(LOG_LEVEL_ERROR, "Failed to shutdown socket %d %E", fd); + } +#endif +#define ARBITRARY_DRAIN_LIMIT 10000 + do + { + char drainage[500]; + + bytes_drained = read_socket(fd, drainage, sizeof(drainage)); + if (bytes_drained < 0) + { + log_error(LOG_LEVEL_ERROR, "Failed to drain socket %d %E", fd); + } + else if (bytes_drained > 0) + { + bytes_drained_total += bytes_drained; + if (bytes_drained_total > ARBITRARY_DRAIN_LIMIT) + { + log_error(LOG_LEVEL_CONNECT, "Giving up draining socket %d", fd); + break; + } + } + } while (bytes_drained > 0); + if (bytes_drained_total != 0) + { + log_error(LOG_LEVEL_CONNECT, + "Drained %d bytes before closing socket %d", bytes_drained_total, fd); + } + } + + close_socket(fd); } diff --git a/jbsockets.h b/jbsockets.h index 7221bac7..e41aab2f 100644 --- a/jbsockets.h +++ b/jbsockets.h @@ -1,6 +1,6 @@ #ifndef JBSOCKETS_H_INCLUDED #define JBSOCKETS_H_INCLUDED -#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.19 2011/07/30 15:17:35 fabiankeil Exp $" +#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.20 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jbsockets.h,v $ @@ -55,6 +55,7 @@ extern int write_socket(jb_socket fd, const char *buf, size_t n); extern int read_socket(jb_socket fd, char *buf, int n); extern int data_is_available(jb_socket fd, int seconds_to_wait); extern void close_socket(jb_socket fd); +extern void drain_and_close_socket(jb_socket fd); extern int bind_port(const char *hostnam, int portnum, jb_socket *pfd); extern int accept_connection(struct client_state * csp, jb_socket fds[]);