You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Marc Slemko <ma...@znep.com> on 1997/01/23 06:52:46 UTC
[PATCH] lingering_close cleanups
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
}
}