httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dean gaudet <dgaudet-list-new-ht...@arctic.org>
Subject Re: [PATCH] dean's code and/or ideas for 2.0 lingering_close()
Date Tue, 11 Apr 2000 23:50:33 GMT
looks good to me :)  +1

-dean

On Tue, 11 Apr 2000, Jeff Trawick wrote:

> I was bad and punted on dean's suggestion for what constant to use
> for sizing the read buffer in lingering_close().
> 
> This doesn't implement ap_bshutdown() for non-UNIX yet and has a hack
> in lingering_close() to work around that temporarily.
> 
> Some folks may be disturbed about the use of ap_bshutdown()'s "how"
> parameter w.r.t. the pretty enum that APR uses.  I suppose I should let 
> ap_bshutdown() et al use that enum as well.
> 
> I haven't properly tested the timeout logic yet, but that should be
> easy to do.  (At the worst, I can put the client on OS/390 and suspend
> the virtual machine it runs in just before the server calls shutdown.) 
> 
> Index: src/include/ap_iol.h
> ===================================================================
> RCS file: /cvs/apache/apache-2.0/src/include/ap_iol.h,v
> retrieving revision 1.15
> diff -u -r1.15 ap_iol.h
> --- ap_iol.h	2000/04/11 16:28:37	1.15
> +++ ap_iol.h	2000/04/11 20:41:53
> @@ -114,6 +114,7 @@
>      ap_status_t (* sendfile)(ap_iol *fd, ap_file_t * file, ap_hdtr_t * hdtr, 
>                               ap_off_t * offset, ap_size_t * len, 
>                               ap_int32_t flags);
> +    ap_status_t (*shutdown)(ap_iol *fd, int how);
>      /* TODO: accept, connect, ... */
>  };
>  
> @@ -131,6 +132,7 @@
>  #define iol_setopt(iol, a, b) ((iol)->methods->setopt((iol), (a), (b)))
>  #define iol_getopt(iol, a, b) ((iol)->methods->getopt((iol), (a), (b)))
>  #define iol_sendfile(iol, a, b, c, d, e) ((iol)->methods->sendfile((iol), (a),
(b), (c), (d), (e)))
> +#define iol_shutdown(iol, a) ((iol)->methods->shutdown((iol), (a)))
>  
>  /* the file iol */
>  ap_iol *ap_create_file_iol(ap_file_t *file);
> Index: src/include/buff.h
> ===================================================================
> RCS file: /cvs/apache/apache-2.0/src/include/buff.h,v
> retrieving revision 1.16
> diff -u -r1.16 buff.h
> --- buff.h	2000/04/11 16:28:38	1.16
> +++ buff.h	2000/04/11 20:41:54
> @@ -199,6 +199,7 @@
>  API_EXPORT(ap_status_t) ap_bwrite(BUFF *fb, const void *buf, ap_size_t nbyte,
>                                    ap_ssize_t *bytes_written);
>  API_EXPORT(ap_status_t) ap_bflush(BUFF *fb);
> +API_EXPORT(ap_status_t) ap_bshutdown(BUFF *fb, int how);
>  API_EXPORT(int) ap_bputs(const char *x, BUFF *fb);
>  API_EXPORT(int) ap_bvputs(BUFF *fb,...);
>  API_EXPORT_NONSTD(int) ap_bprintf(BUFF *fb, const char *fmt,...)
> Index: src/main/buff.c
> ===================================================================
> RCS file: /cvs/apache/apache-2.0/src/main/buff.c,v
> retrieving revision 1.34
> diff -u -r1.34 buff.c
> --- buff.c	2000/03/31 08:44:19	1.34
> +++ buff.c	2000/04/11 20:41:59
> @@ -869,6 +869,19 @@
>      return bflush_core(fb, &n);
>  }
>  
> +API_EXPORT(ap_status_t) ap_bshutdown(BUFF *fb, int how)
> +{
> +    ap_status_t status;
> +    
> +    if (how >= 1) {
> +        ap_bsetflag(fb, B_EOUT, 1);
> +    }
> +    
> +    status = iol_shutdown(fb->iol, how);
> +    
> +    return status;
> +}
> +
>  /*
>   * Flushes and closes the file, even if an error occurred.
>   * Discards an data that was not read, or not written by bflush()
> Index: src/main/http_connection.c
> ===================================================================
> RCS file: /cvs/apache/apache-2.0/src/main/http_connection.c,v
> retrieving revision 1.28
> diff -u -r1.28 http_connection.c
> --- http_connection.c	2000/03/31 08:44:20	1.28
> +++ http_connection.c	2000/04/11 20:42:01
> @@ -75,9 +75,6 @@
>  IMPLEMENT_HOOK_VOID(pre_connection,(conn_rec *c),(c))
>  IMPLEMENT_HOOK_RUN_FIRST(int,process_connection,(conn_rec *c),(c),DECLINED)
>  
> -/* TODO: reimplement the lingering close stuff */
> -#define NO_LINGCLOSE
> -
>  /*
>   * More machine-dependent networking gooo... on some systems,
>   * you've got to be *really* sure that all the packets are acknowledged
> @@ -126,70 +123,75 @@
>  
>  #ifndef NO_LINGCLOSE
>  
> -/* Since many clients will abort a connection instead of closing it,
> - * attempting to log an error message from this routine will only
> - * confuse the webmaster.  There doesn't seem to be any portable way to
> - * distinguish between a dropped connection and something that might be
> - * worth logging.
> +/* we now proceed to read from the client until we get EOF, or until
> + * MAX_SECS_TO_LINGER has passed.  the reasons for doing this are
> + * documented in a draft:
> + *
> + * http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt
> + *
> + * in a nutshell -- if we don't make this effort we risk causing
> + * TCP RST packets to be sent which can tear down a connection before
> + * all the response data has been sent to the client.
>   */
> -static void lingering_close(request_rec *r)     
> -{
> -  /*TODO remove the hardwired 512. This is an IO Buffer Size */
> -    char dummybuf[512];    
> -    struct pollfd pd;
> -    int lsd;
> -    int max_wait;
>  
> -    /* Prevent a slow-drip client from holding us here indefinitely */
> -
> -    max_wait = 30;
> -    ap_bsetopt(r->connection->client, BO_TIMEOUT, &max_wait);
> +static void lingering_close(conn_rec *c)
> +{
> +    char dummybuf[512];
> +    ap_time_t start;
> +    ap_ssize_t nbytes;
> +    ap_status_t rc;
> +    int timeout;
>  
>      /* Send any leftover data to the client, but never try to again */
>  
> -    if (ap_bflush(r->connection->client) != APR_SUCCESS) {
> -	ap_bclose(r->connection->client);
> -	return;
> +    if (ap_bflush(c->client) != APR_SUCCESS) {
> +        ap_bclose(c->client);
> +        return;
>      }
> -    ap_bsetflag(r->connection->client, B_EOUT, 1);
> -
> -    /* Close our half of the connection --- send the client a FIN */
>  
> -    lsd = r->connection->client->fd;
> +    /* TODO...  Get ap_bshutdown() implemented on Win32, BeOS,
> +     * and OS/2 and axe this code.
> +     */
>  
> -    if ((shutdown(lsd, 1) != 0)  
> -        || ap_is_aborted(r->connection)) {
> -	ap_bclose(r->connection->client);
> -	return;
> +    if (!c->client->methods->shutdown) {
> +        ap_bclose(c->client);
> +        return;
>      }
> -
> -    /* Set up to wait for readable data on socket... */
> -    pd.fd = lsd;
> -    pd.events = POLLIN;
> -
> -    /* 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 poll(), get an error or EOF on a read, or the timer expires.
> +    /* end of code to axe */
> +    
> +    /* Shut down the socket for write, which will send a FIN
> +     * to the peer.
>       */
> -    /* We use a 2 second timeout because current (Feb 97) browsers
> -     * fail to close a connection after the server closes it.  Thus,
> -     * to avoid keeping the child busy, we are only lingering long enough
> -     * for a client that is actively sending data on a connection.
> -     * This should be sufficient unless the connection is massively
> -     * losing packets, in which case we might have missed the RST anyway.
> -     * These parameters are reset on each pass, since they might be
> -     * changed by poll.
> +    
> +    if (ap_bshutdown(c->client, 1) != APR_SUCCESS
> +        || ap_is_aborted(c)) {
> +        ap_bclose(c->client);
> +        return;
> +    }
> +
> +    /* Read all data from the peer until we reach "end-of-file" (FIN
> +     * from peer) or we've exceeded our overall timeout.
>       */
> -    do {
> -        pd.revents = 0;
> -    } while ((poll(&pd, 1, 2) == 1)   
> -             && read(lsd, dummybuf, sizeof(dummybuf)));
> -      /* && (time() = epoch) < max_wait); */    
> +    
> +    start = ap_now();
> +    timeout = MAX_SECS_TO_LINGER;
> +    for (;;) {
> +        ap_bsetopt(c->client, BO_TIMEOUT, &timeout);
> +        rc = ap_bread(c->client, dummybuf, sizeof(dummybuf),
> +                      &nbytes);
> +        if (rc != APR_SUCCESS || nbytes == 0) break;
> +
> +        /* how much time has elapsed? */
> +        timeout = (ap_now() - start) / AP_USEC_PER_SEC;
> +        if (timeout >= MAX_SECS_TO_LINGER) break;
>  
> -    /* Should now have seen final ack.  Safe to finally kill socket */
> -    ap_bclose(r->connection->client);
> +        /* figure out the new timeout */
> +        timeout = MAX_SECS_TO_LINGER - timeout;
> +    }
> +
> +    ap_bclose(c->client);
>  }
> +
>  #endif /* ndef NO_LINGCLOSE */
>  
>  CORE_EXPORT(void) ap_process_connection(conn_rec *c)
> @@ -209,12 +211,11 @@
>  #ifdef NO_LINGCLOSE
>      ap_bclose(c->client);	/* just close it */
>  #else
> -    if (r && r->connection
> -	&& !r->connection->aborted
> -	&& r->connection->client
> -	&& (r->connection->client->fd >= 0)) {
> +    if (!c->aborted
> +	&& c->client
> +	/* && (c->client->fd >= 0) */ ) {
>  
> -	lingering_close(r);
> +	lingering_close(c);
>      }
>      else {
>  	ap_bsetflag(c->client, B_EOUT, 1);
> Index: src/os/unix/iol_socket.c
> ===================================================================
> RCS file: /cvs/apache/apache-2.0/src/os/unix/iol_socket.c,v
> retrieving revision 1.19
> diff -u -r1.19 iol_socket.c
> --- iol_socket.c	2000/03/31 09:17:16	1.19
> +++ iol_socket.c	2000/04/11 20:42:01
> @@ -134,13 +134,22 @@
>      return saved_errno;
>  }
>  
> +static ap_status_t unix_shutdown(ap_iol *viol, int how)
> +{
> +    iol_socket *iol = (iol_socket *)viol;
> +
> +    return ap_shutdown(iol->sock, how);
> +}
> +    
>  static const ap_iol_methods socket_methods = {
>      unix_close,
>      unix_write,
>      unix_writev,
>      unix_read,
>      unix_setopt,
> -    unix_getopt
> +    unix_getopt,
> +    NULL,
> +    unix_shutdown
>  };
>  
>  ap_iol *unix_attach_socket(ap_socket_t *sock)
> 
> 
> -- 
> Jeff Trawick | trawick@ibm.net | PGP public key at web site:
>      http://www.geocities.com/SiliconValley/Park/9289/
>           Born in Roswell... married an alien...
> 


Mime
View raw message