You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Robert S. Thau" <rs...@ai.mit.edu> on 1996/06/28 03:32:06 UTC

Possible SO_LINGER alternative...

Damn, my timing on these things is becoming execrable.  Here's a
patch which shows a technique which is at least alleged in some
quarters to work as well as SO_LINGER, without causing quite so
many problems as are encountered in SO_LINGER alternatives.  I'm
running with a SunOS server compiled with -DNEED_LINGER and with
this patch in overnight, and so far, at least, it doesn't seem
to be causing any untoward behavior.

The *interesting* questions, of course, are:

1) Does it also solve the "truncated data" problems which
   seem to be solved by setting the real SO_LINGER option on
   certain SVR4 derivatives?

2) Does it avoid the problem with processes seemingly idling
   indefinitely which may or may not be caused by SO_LINGER?

... and I'm not in *any* position to test either of those things
here.

Again, sorry about the timing foax...

rst

*** http_main.c~	Thu Jun 13 16:33:02 1996
--- http_main.c	Thu Jun 27 21:19:11 1996
***************
*** 271,276 ****
--- 271,330 ----
  #define accept_mutex_off()
  #endif
  
+ /*
+  * More machine-dependant networking gooo... on some systems,
+  * you've got to be *really* sure that all the packets are acknowledged
+  * before closing the connection.  Actually, it shouldn't hurt anyplace,
+  * but this is a late bugfix, so be conservative...
+  */
+ 
+ #ifdef NEED_LINGER
+ 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 */
+ 
+     shutdown (sd, 1);
+ 
+     /* 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...
+      */
+ 
+     while ((select_rv = select (sd + 1, &fds_read, NULL, &fds_err, &tv)) > 0) {
+ 	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)
  {
      fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin);
***************
*** 1258,1264 ****
--- 1312,1325 ----
  		       bytes_in_pool (ptrans), r->the_request);
  #endif		
  	bflush(conn_io);
+ #ifdef NEED_LINGER 
+ 	if (r)
+ 	    lingering_close (conn_io->fd, r->server);
+ 	else
+ 	    close (conn_io->fd);
+ #else	
  	bclose(conn_io);
+ #endif	
      }    
  }
  
***************
*** 1312,1319 ****
          exit(1); 
      }
  
! #ifdef NEED_LINGER   /* If puts don't complete, you could try this. */
      {
  	struct linger li;
  	li.l_onoff = 1;
  	li.l_linger = 900;
--- 1373,1385 ----
          exit(1); 
      }
  
! #ifdef NOTDEF   /* If puts don't complete, you could try this. */
      {
+ 	/* Unfortunately, SO_LINGER causes problems as severe as it
+ 	 * cures on many of the affected systems; now trying the
+ 	 * lingering_close trick (see routine by that name above)
+ 	 * instead...
+ 	 */
  	struct linger li;
  	li.l_onoff = 1;
  	li.l_linger = 900;