You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Roy T. Fielding" <fi...@kiwi.ICS.UCI.EDU> on 1997/01/23 20:36:42 UTC

Re: [PATCH] lingering_close cleanups

I made a few changes (mostly cosmetic) to Marc's patch.  This might
hopefully fix problems with people getting linger errors, but it will
not fix the problem with Netscape (and IE) holding on to keep-alive
sockets forever.  But neither does NO_LINGER, so this is the best
solution on our side.

+1 from me (I tested it pretty thoroughly).

.....Roy

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
*** http_main.c	1997/01/20 04:28:08	1.108
--- http_main.c	1997/01/23 19:31:48
***************
*** 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,368 ****
   */
  
  #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
!     while ((select_rv = select (sd + 1, (int*)&fds_read, NULL, (int*)&fds_err,
! 				&tv)) > 0) {
  #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)
  {
--- 316,396 ----
   */
  
  #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;
+     int sd = r->connection->client->fd;
+ 
+     if (sd < 0)          /* Don't do anything if the socket is invalid */
+         return;
+ 
+     kill_timeout(r);     /* Remove any leftover timeouts */
  
      /* 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);
  
      /* 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.
       */
  
+     /* Prevent a slow-drip client from holding us here indefinitely */
+ 
+     hard_timeout("lingering_close", r);
+ 
+     do {
+ 	/* 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.  These parameters are
+          * reset on each pass, since they may be changed by select.
+ 	 */
+         tv.tv_sec  = max(r->server->keep_alive_timeout, 10);
+         tv.tv_usec = 0;
+         read_rv    = 0;
+         fds_read   = fds;
+         fds_err    = fds;
+     
  #ifdef HPUX
!         select_rv = select(sd + 1, (int*)&fds_read, NULL, (int*)&fds_err, &tv);
  #else
!         select_rv = select(sd + 1, &fds_read, NULL, &fds_err, &tv);
  #endif
!     } while ((select_rv > 0) &&           /* Something to see on socket    */
!              !FD_ISSET(sd, &fds_err) &&   /* that isn't an error condition */
!              FD_ISSET(sd, &fds_read) &&   /* and is worth trying to read   */
!              ((read_rv = read(sd, dummybuf, sizeof dummybuf)) > 0));
  
!     /* Log any errors that occurred (client close or reset is not 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);
  }
! #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	
      }    
  }
--- 1700,1714 ----
  #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	
      }    
  }

Re: [PATCH] lingering_close cleanups

Posted by Brian Behlendorf <br...@organic.com>.
On Fri, 24 Jan 1997, Marc Slemko wrote:
> On Thu, 23 Jan 1997, Dean Gaudet wrote:
> 
> > With Marc's jan 22nd patch I started seeing these: 
> > 
> > [Thu Jan 23 09:10:49 1997] shutdown: Transport endpoint is not connected
> > [Thu Jan 23 09:10:49 1997] - lingering_close
> > 
> > This is on linux.  I'll swap out for Roy's patch and see what happens.
> 
> You still getting them?  Anyone else seeing them running with the changes
> (Roy's patch, which _should_ do nearly the exact same thing as mine) 
> committed earlier today? 

Clean as a whistle on www.apache.org since I upgraded to the most recent
1.2b5-dev snapshot.  BSDI 2.0.

	Brian

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
brian@organic.com  www.apache.org  hyperreal.com  http://www.organic.com/JOBS


Re: [PATCH] lingering_close cleanups

Posted by Dean Gaudet <dg...@arctic.org>.
Yup I got two yesterday after I switched to Roy's patch:

[Thu Jan 23 19:08:37 1997] shutdown: Transport endpoint is not connected
[Thu Jan 23 19:08:37 1997] - lingering_close
[Thu Jan 23 19:08:39 1997] shutdown: Transport endpoint is not connected
[Thu Jan 23 19:08:39 1997] - lingering_close

This is a low volume server, 6k hits per day.  I actually have two on the
18th, and very few others... so they're not totally new, just more of them
appearing now.  Unfortunately I didn't keep track of what lingering close
patch I was running on the 18th -- prior to that I was running 1.2b4. 

Dean

On Fri, 24 Jan 1997, Marc Slemko wrote:

> On Thu, 23 Jan 1997, Dean Gaudet wrote:
> 
> > With Marc's jan 22nd patch I started seeing these: 
> > 
> > [Thu Jan 23 09:10:49 1997] shutdown: Transport endpoint is not connected
> > [Thu Jan 23 09:10:49 1997] - lingering_close
> > 
> > This is on linux.  I'll swap out for Roy's patch and see what happens.
> 
> You still getting them?  Anyone else seeing them running with the changes
> (Roy's patch, which _should_ do nearly the exact same thing as mine) 
> committed earlier today? 
> 
> I do not understand why this could have started appearing.
> 
> 


Re: [PATCH] lingering_close cleanups

Posted by Marc Slemko <ma...@znep.com>.
On Thu, 23 Jan 1997, Dean Gaudet wrote:

> With Marc's jan 22nd patch I started seeing these: 
> 
> [Thu Jan 23 09:10:49 1997] shutdown: Transport endpoint is not connected
> [Thu Jan 23 09:10:49 1997] - lingering_close
> 
> This is on linux.  I'll swap out for Roy's patch and see what happens.

You still getting them?  Anyone else seeing them running with the changes
(Roy's patch, which _should_ do nearly the exact same thing as mine) 
committed earlier today? 

I do not understand why this could have started appearing.


Re: [PATCH] lingering_close cleanups

Posted by Dean Gaudet <dg...@arctic.org>.
With Marc's jan 22nd patch I started seeing these: 

[Thu Jan 23 09:10:49 1997] shutdown: Transport endpoint is not connected
[Thu Jan 23 09:10:49 1997] - lingering_close

This is on linux.  I'll swap out for Roy's patch and see what happens.

Dean

On Thu, 23 Jan 1997, Roy T. Fielding wrote:

> I made a few changes (mostly cosmetic) to Marc's patch.  This might
> hopefully fix problems with people getting linger errors, but it will
> not fix the problem with Netscape (and IE) holding on to keep-alive
> sockets forever.  But neither does NO_LINGER, so this is the best
> solution on our side.
> 
> +1 from me (I tested it pretty thoroughly).
> 
> .....Roy
> 
> 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
> *** http_main.c	1997/01/20 04:28:08	1.108
> --- http_main.c	1997/01/23 19:31:48
> ***************
> *** 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,368 ****
>    */
>   
>   #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
> !     while ((select_rv = select (sd + 1, (int*)&fds_read, NULL, (int*)&fds_err,
> ! 				&tv)) > 0) {
>   #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)
>   {
> --- 316,396 ----
>    */
>   
>   #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;
> +     int sd = r->connection->client->fd;
> + 
> +     if (sd < 0)          /* Don't do anything if the socket is invalid */
> +         return;
> + 
> +     kill_timeout(r);     /* Remove any leftover timeouts */
>   
>       /* 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);
>   
>       /* 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.
>        */
>   
> +     /* Prevent a slow-drip client from holding us here indefinitely */
> + 
> +     hard_timeout("lingering_close", r);
> + 
> +     do {
> + 	/* 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.  These parameters are
> +          * reset on each pass, since they may be changed by select.
> + 	 */
> +         tv.tv_sec  = max(r->server->keep_alive_timeout, 10);
> +         tv.tv_usec = 0;
> +         read_rv    = 0;
> +         fds_read   = fds;
> +         fds_err    = fds;
> +     
>   #ifdef HPUX
> !         select_rv = select(sd + 1, (int*)&fds_read, NULL, (int*)&fds_err, &tv);
>   #else
> !         select_rv = select(sd + 1, &fds_read, NULL, &fds_err, &tv);
>   #endif
> !     } while ((select_rv > 0) &&           /* Something to see on socket    */
> !              !FD_ISSET(sd, &fds_err) &&   /* that isn't an error condition */
> !              FD_ISSET(sd, &fds_read) &&   /* and is worth trying to read   */
> !              ((read_rv = read(sd, dummybuf, sizeof dummybuf)) > 0));
>   
> !     /* Log any errors that occurred (client close or reset is not 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);
>   }
> ! #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	
>       }    
>   }
> --- 1700,1714 ----
>   #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	
>       }    
>   }
> 



Re: [PATCH] lingering_close cleanups

Posted by Marc Slemko <ma...@znep.com>.
On Thu, 23 Jan 1997, Roy T. Fielding wrote:

> I made a few changes (mostly cosmetic) to Marc's patch.  This might
> hopefully fix problems with people getting linger errors, but it will
> not fix the problem with Netscape (and IE) holding on to keep-alive
> sockets forever.  But neither does NO_LINGER, so this is the best
> solution on our side.

Looks good to me.  Does what I did but makes the code almost readable.
Hey, this sort of code isn't supposed to be readable.  <g>

One thing that needs to be added before the final close() in
lingering_close() is something like:

	#ifdef NEED_SHUTDOWN
	/* some broken SVR4 systems flush data queued for sending when
	 * the socket is destroyed.  Doing a shutdown() first should
	 * prevent that.
	 */
	shutdown(sd, 2);
	#endif /* NEED_SHUTDOWN */

With the appropriate support for the define.  Me thinks that without
it the broken systems could still break, and the stated point of
lingering_close (we all know the more important real reason now)
was to fix those systems so we may as well not break that now.

> 
> +1 from me (I tested it pretty thoroughly).
> 
> .....Roy
> 
> 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
> *** http_main.c	1997/01/20 04:28:08	1.108
> --- http_main.c	1997/01/23 19:31:48
> ***************
> *** 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,368 ****
>    */
>   
>   #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
> !     while ((select_rv = select (sd + 1, (int*)&fds_read, NULL, (int*)&fds_err,
> ! 				&tv)) > 0) {
>   #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)
>   {
> --- 316,396 ----
>    */
>   
>   #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;
> +     int sd = r->connection->client->fd;
> + 
> +     if (sd < 0)          /* Don't do anything if the socket is invalid */
> +         return;
> + 
> +     kill_timeout(r);     /* Remove any leftover timeouts */
>   
>       /* 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);
>   
>       /* 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.
>        */
>   
> +     /* Prevent a slow-drip client from holding us here indefinitely */
> + 
> +     hard_timeout("lingering_close", r);
> + 
> +     do {
> + 	/* 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.  These parameters are
> +          * reset on each pass, since they may be changed by select.
> + 	 */
> +         tv.tv_sec  = max(r->server->keep_alive_timeout, 10);
> +         tv.tv_usec = 0;
> +         read_rv    = 0;
> +         fds_read   = fds;
> +         fds_err    = fds;
> +     
>   #ifdef HPUX
> !         select_rv = select(sd + 1, (int*)&fds_read, NULL, (int*)&fds_err, &tv);
>   #else
> !         select_rv = select(sd + 1, &fds_read, NULL, &fds_err, &tv);
>   #endif
> !     } while ((select_rv > 0) &&           /* Something to see on socket    */
> !              !FD_ISSET(sd, &fds_err) &&   /* that isn't an error condition */
> !              FD_ISSET(sd, &fds_read) &&   /* and is worth trying to read   */
> !              ((read_rv = read(sd, dummybuf, sizeof dummybuf)) > 0));
>   
> !     /* Log any errors that occurred (client close or reset is not 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);
>   }
> ! #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	
>       }    
>   }
> --- 1700,1714 ----
>   #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	
>       }    
>   }
>