Received: by taz.hyperreal.com (8.8.4/V2.0) id VAA27433; Wed, 22 Jan 1997 21:53:19 -0800 (PST) Received: from scanner.worldgate.com by taz.hyperreal.com (8.8.4/V2.0) with ESMTP id VAA27426; Wed, 22 Jan 1997 21:53:14 -0800 (PST) Received: from znep.com (uucp@localhost) by scanner.worldgate.com (8.7.5/8.7.3) with UUCP id WAA12029 for new-httpd@hyperreal.com; Wed, 22 Jan 1997 22:53:18 -0700 (MST) Received: from localhost (marcs@localhost) by alive.ampr.ab.ca (8.7.5/8.7.3) with SMTP id WAA25533 for ; Wed, 22 Jan 1997 22:52:46 -0700 (MST) Date: Wed, 22 Jan 1997 22:52:46 -0700 (MST) From: Marc Slemko X-Sender: marcs@alive.ampr.ab.ca To: new-httpd@hyperreal.com Subject: [PATCH] lingering_close cleanups Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: new-httpd-owner@apache.org Precedence: bulk Reply-To: new-httpd@hyperreal.com Below is a patch which fixes up what I think are the known problems with lingering_close. I don't like it using hard_timeout() because the timer value isn't necessarily appropriate, but until all the messed up timeout handling is rewritten I don't think it is worth worrying about. As long as people agree with this patch, I think it should go in and then the next beta should be put out a short bit later. Index: http_main.c =================================================================== RCS file: /export/home/cvs/apache/src/http_main.c,v retrieving revision 1.108 diff -c -r1.108 http_main.c *** 1.108 1997/01/20 04:28:08 --- http_main.c 1997/01/23 05:48:32 *************** *** 109,114 **** --- 109,118 ---- #include "explain.h" + #if !defined(max) + #define max(a,b) (a > b ? a : b) + #endif + #ifdef __EMX__ /* Add MMAP style functionality to OS/2 */ #ifdef HAVE_MMAP *************** *** 312,340 **** */ #ifndef NO_LINGCLOSE ! static void lingering_close (int sd, server_rec *server_conf) { int dummybuf[512]; struct timeval tv; fd_set fds, fds_read, fds_err; ! int select_rv = 0, read_rv = 0; /* Close our half of the connection --- send client a FIN */ ! if ((shutdown (sd, 1)) != 0) ! log_unixerr("shutdown", NULL, "lingering_close", server_conf); /* Set up to wait for readable data on socket... */ FD_ZERO (&fds); FD_SET (sd, &fds); ! tv.tv_sec = server_conf->keep_alive_timeout; tv.tv_usec = 0; fds_read = fds; fds_err = fds; /* Wait for readable data or error condition on socket; ! * slurp up any data that arrives... */ #ifdef HPUX --- 316,359 ---- */ #ifndef NO_LINGCLOSE ! static void lingering_close (request_rec *r) { int dummybuf[512]; struct timeval tv; fd_set fds, fds_read, fds_err; ! int select_rv = 0, read_rv = 0, close_rv; ! int sd = r->connection->client->fd; ! ! kill_timeout(r); ! hard_timeout("lingering_close", r); /* Close our half of the connection --- send client a FIN */ ! if ((shutdown (sd, 1)) != 0) { ! /* if it fails, no need to go through the rest of the routine */ ! log_unixerr("shutdown", NULL, "lingering_close", r->server); ! close(sd); ! return; ! } /* Set up to wait for readable data on socket... */ FD_ZERO (&fds); FD_SET (sd, &fds); ! tv.tv_sec = max(r->server->keep_alive_timeout, 10); ! /* If keep_alive_timeout is too low, using it as a timeout ! * can cause undesirable behavior so pick some pseudo-arbitrary ! * minimum value, currently 10 seconds. ! */ tv.tv_usec = 0; fds_read = fds; fds_err = fds; /* Wait for readable data or error condition on socket; ! * slurp up any data that arrives... We exit when we go for ! * an interval of tv length without getting any more data, get an ! * error from select(), get an exception on sd, get an error or EOF ! * on a read, or the timer expires. */ #ifdef HPUX *************** *** 343,368 **** #else while ((select_rv = select (sd + 1, &fds_read, NULL, &fds_err, &tv)) > 0) { #endif ! if ((read_rv = read (sd, dummybuf, sizeof(dummybuf))) <= 0) break; ! else { fds_read = fds; fds_err = fds; } } /* Log any errors that occured (client closing their end isn't an error) */ if (select_rv < 0) ! log_unixerr("select", NULL, "lingering_close", server_conf); else if (read_rv < 0 && errno != ECONNRESET) ! log_unixerr("read", NULL, "lingering_close", server_conf); /* Should now have seen final ack. Safe to finally kill socket */ ! ! shutdown (sd, 2); ! close (sd); } ! #endif void usage(char *bin) { --- 362,401 ---- #else while ((select_rv = select (sd + 1, &fds_read, NULL, &fds_err, &tv)) > 0) { #endif ! if (FD_ISSET(sd, &fds_err)) { ! /* exception on fd; out of band data (connection close?) */ ! read_rv = 0; ! break; ! } else if (FD_ISSET(sd, &fds_read) && ! ( (read_rv = read(sd, dummybuf, sizeof(dummybuf))) <= 0 ) ) { ! /* read returned EOF or an error (connection close?) */ break; ! } else { ! /* go through the whole thing again */ fds_read = fds; fds_err = fds; + /* BSD man page threatens to adjust timeout after select(), and + * Linux does so we need to reset it. + */ + tv.tv_sec = max(r->server->keep_alive_timeout, 10); + tv.tv_usec = 0; } } /* Log any errors that occured (client closing their end isn't an error) */ if (select_rv < 0) ! log_unixerr("select", NULL, "lingering_close", r->server); else if (read_rv < 0 && errno != ECONNRESET) ! log_unixerr("read", NULL, "lingering_close", r->server); /* Should now have seen final ack. Safe to finally kill socket */ ! if (close(sd) < 0) { ! log_unixerr("close", NULL, "lingering_close", r->server); ! } ! kill_timeout(r); ! /* not currently needed, but nice to cleanup what you start */ } ! #endif /* ndef NO_LINGCLOSE */ void usage(char *bin) { *************** *** 1672,1681 **** #ifdef NO_LINGCLOSE bclose(conn_io); /* just close it */ #else ! if (r) ! lingering_close (conn_io->fd, r->server); ! else ! close (conn_io->fd); #endif } } --- 1705,1719 ---- #ifdef NO_LINGCLOSE bclose(conn_io); /* just close it */ #else ! if (r && !r->connection->aborted) { ! /* if the connection was aborted by a soft_timeout, it has ! * already been shutdown() so we don't need to go through ! * lingering_close ! */ ! lingering_close(r); ! } else { ! close(conn_io->fd); ! } #endif } }