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	
      }    
  }