httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Roy Fielding <field...@hyperreal.com>
Subject cvs commit: apache/src CHANGES http_main.c
Date Sun, 16 Feb 1997 23:32:35 GMT
fielding    97/02/16 15:32:34

  Modified:    src       CHANGES http_main.c
  Log:
  Rearranged main child loop to remove duplication of code in
  select/accept and keep-alive requests, fixed several bugs regarding
  checking scoreboard_image for exit indication and failure to
  account for all success conditions and trap all error conditions,
  prevented multiple flushes before closing the socket; close the entire
  socket buffer instead of just one descriptor, prevent logging of
  EPROTO and ECONNABORTED on platforms where supported, and generally
  improved readability.
  
  Reviewed by: Randy Terbush, Marc Slemko, Jim Jagielski, Chuck Murcko
  
  Revision  Changes    Path
  1.163     +9 -0      apache/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache/src/CHANGES,v
  retrieving revision 1.162
  retrieving revision 1.163
  diff -C3 -r1.162 -r1.163
  *** CHANGES	1997/02/16 22:48:25	1.162
  --- CHANGES	1997/02/16 23:32:32	1.163
  ***************
  *** 16,21 ****
  --- 16,30 ----
         read causing the child to hang, and stopped logging of errors if
         the socket is not connected (reset by client).  [Roy Fielding]
    
  +   *) Rearranged main child loop to remove duplication of code in
  +      select/accept and keep-alive requests, fixed several bugs regarding
  +      checking scoreboard_image for exit indication and failure to
  +      account for all success conditions and trap all error conditions,
  +      prevented multiple flushes before closing the socket; close the entire
  +      socket buffer instead of just one descriptor, prevent logging of
  +      EPROTO and ECONNABORTED on platforms where supported, and generally
  +      improved readability.  [Roy Fielding]
  + 
      *) Extensive performance improvements. Cleaned up inefficient use of
         auto initializers, multiple is_matchexp calls on a static string,
         and excessive merging of response_code_strings. [Dean Gaudet]
  
  
  
  1.121     +139 -122  apache/src/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_main.c,v
  retrieving revision 1.120
  retrieving revision 1.121
  diff -C3 -r1.120 -r1.121
  *** http_main.c	1997/02/15 12:26:20	1.120
  --- http_main.c	1997/02/16 23:32:32	1.121
  ***************
  *** 313,355 ****
    {
        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 and
         * set the socket to non-blocking for later reads.
         */
    
  !     if (((shutdown(sd, 1)) != 0) || (fcntl(sd, F_SETFL, FNDELAY) == -1)) {
    	/* if it fails, no need to go through the rest of the routine */
    	if (errno != ENOTCONN)
    	    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 {
            /* We use a 1 second timeout because current (Feb 97) browsers
             * fail to close a connection after the server closes it.  Thus,
  --- 313,357 ----
    {
        int dummybuf[512];
        struct timeval tv;
  !     fd_set lfds, fds_read, fds_err;
        int select_rv = 0, read_rv = 0;
  !     int lsd;
    
  !     /* Prevent a slow-drip client from holding us here indefinitely */
  ! 
  !     kill_timeout(r);                 /* Remove any leftover timeouts */
  !     hard_timeout("lingering_close", r);
  ! 
  !     /* Send any leftover data to the client, but never try to again */
    
  !     bflush(r->connection->client);
  !     bsetflag(r->connection->client, B_EOUT, 1);
    
  !     /* Close our half of the connection --- send the client a FIN and
         * set the socket to non-blocking for later reads.
         */
  +     lsd = r->connection->client->fd;
    
  !     if (((shutdown(lsd, 1)) != 0) || (fcntl(lsd, F_SETFL, FNDELAY) == -1)) {
    	/* if it fails, no need to go through the rest of the routine */
    	if (errno != ENOTCONN)
    	    log_unixerr("shutdown", NULL, "lingering_close", r->server);
  ! 	bclose(r->connection->client);
    	return;
        }
    
        /* Set up to wait for readable data on socket... */
    
  !     FD_ZERO(&lfds);
  !     FD_SET(lsd, &lfds);
    
        /* 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 lsd, get an error or EOF
         * on a read, or the timer expires.
         */
    
        do {
            /* We use a 1 second timeout because current (Feb 97) browsers
             * fail to close a connection after the server closes it.  Thus,
  ***************
  *** 363,380 ****
            tv.tv_sec  = 1;
            tv.tv_usec = 0;
            read_rv    = 0;
  !         fds_read   = fds;
  !         fds_err    = fds;
        
    #ifdef SELECT_NEEDS_CAST
  !         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) */
        
  --- 365,382 ----
            tv.tv_sec  = 1;
            tv.tv_usec = 0;
            read_rv    = 0;
  !         fds_read   = lfds;
  !         fds_err    = lfds;
        
    #ifdef SELECT_NEEDS_CAST
  !         select_rv = select(lsd+1, (int*)&fds_read, NULL, (int*)&fds_err, &tv);
    #else
  !         select_rv = select(lsd+1, &fds_read, NULL, &fds_err, &tv);
    #endif
        } while ((select_rv > 0) &&           /* Something to see on socket   
*/
  !              !FD_ISSET(lsd, &fds_err) &&   /* that isn't an error condition
*/
  !              FD_ISSET(lsd, &fds_read) &&   /* and is worth trying to read
  */
  !              ((read_rv = read(lsd, dummybuf, sizeof dummybuf)) > 0));
    
        /* Log any errors that occurred (client close or reset is not an error) */
        
  ***************
  *** 385,392 ****
    
        /* 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);
    }
  --- 387,393 ----
    
        /* Should now have seen final ack.  Safe to finally kill socket */
    
  !     bclose(r->connection->client);
    
        kill_timeout(r);
    }
  ***************
  *** 1521,1530 ****
  --- 1522,1533 ----
     * they are really private to child_main.
     */
    
  + static int srv;
    static int csd;
    static int dupped_csd;
    static int requests_this_child;
    static int child_num;
  + static fd_set main_fds;
    
    void child_main(int child_num_arg)
    {
  ***************
  *** 1540,1547 ****
        dupped_csd = -1;
        child_num = child_num_arg;
        requests_this_child = 0;
  !     reopen_scoreboard (pconf);
  !     (void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
    
    #ifdef MPE
        /* Only try to switch if we're running as MANAGER.SYS */
  --- 1543,1551 ----
        dupped_csd = -1;
        child_num = child_num_arg;
        requests_this_child = 0;
  ! 
  !     reopen_scoreboard(pconf);
  !     (void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL);
    
    #ifdef MPE
        /* Only try to switch if we're running as MANAGER.SYS */
  ***************
  *** 1551,1557 ****
                GETUSERMODE();
    #else
        /* Only try to switch if we're running as root */
  !     if(!geteuid() && setuid(user_id) == -1) {
    #endif
            log_unixerr("setuid", NULL, "unable to change uid", server_conf);
    	exit (1);
  --- 1555,1561 ----
                GETUSERMODE();
    #else
        /* Only try to switch if we're running as root */
  !     if (!geteuid() && setuid(user_id) == -1) {
    #endif
            log_unixerr("setuid", NULL, "unable to change uid", server_conf);
    	exit (1);
  ***************
  *** 1561,1566 ****
  --- 1565,1574 ----
        }
    #endif
    
  +     /*
  +      * Setup the jump buffers so that we can return here after
  +      * a signal or a timeout (yeah, I know, same thing).
  +      */
    #ifdef NEXT
        setjmp(jmpbuffer);
    #else
  ***************
  *** 1574,1579 ****
  --- 1582,1591 ----
    	BUFF *conn_io;
    	request_rec *r;
          
  +         /*
  +          * (Re)initialize this child to a pre-connection state.
  +          */
  + 
            alarm(0);		/* Cancel any outstanding alarms. */
            timeout_req = NULL;	/* No request in progress */
    	current_conn = NULL;
  ***************
  *** 1582,1590 ****
    	clear_pool (ptrans);
    	
    	sync_scoreboard_image();
  ! 
  ! 	/*fprintf(stderr,"%d check %d %d\n",getpid(),scoreboard_image->global.exit_generation,generation);*/
  ! 	if(scoreboard_image->global.exit_generation >= generation)
    	    exit(0);
    	
    	if ((count_idle_servers() >= daemons_max_free)
  --- 1594,1600 ----
    	clear_pool (ptrans);
    	
    	sync_scoreboard_image();
  ! 	if (scoreboard_image->global.exit_generation >= generation)
    	    exit(0);
    	
    	if ((count_idle_servers() >= daemons_max_free)
  ***************
  *** 1594,1676 ****
    	    exit(0);
    	}
    
  ! 	(void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
  ! 	
  ! 	accept_mutex_on();  /* Lock around "accept", if necessary */
  ! 
  ! 	if (listeners != NULL)
  ! 	{
  ! 	    fd_set fds;
    
  ! 	    for (;;) {
  ! 		memcpy(&fds, &listenfds, sizeof(fd_set));
  ! #ifdef SELECT_NEEDS_CAST
  ! 		csd = select(listenmaxfd+1, (int*)&fds, NULL, NULL, NULL);
  ! #else
  !                 csd = select(listenmaxfd+1, &fds, NULL, NULL, NULL);
  ! #endif
  ! 		if (csd < 0 && errno != EINTR)
  ! 		    log_unixerr("select",NULL,"select error", server_conf);
    
  ! 		/*fprintf(stderr,"%d check(2a) %d %d\n",getpid(),scoreboard_image->global.exit_generation,generation);*/
  ! 		if(scoreboard_image->global.exit_generation >= generation)
  ! 		    exit(0);
    
  ! 		if (csd <= 0) continue;
  ! 		for (sd=listenmaxfd; sd >= 0; sd--)
  ! 		    if (FD_ISSET(sd, &fds)) break;
  ! 		if (sd < 0) continue;
  ! 
  !                 do {
  !                     clen = sizeof(sa_client);
  !                     csd  = accept(sd, &sa_client, &clen);
  !                 } while (csd < 0 && errno == EINTR);
  !                 if (csd > 0) break;
  ! 		log_unixerr("accept", "(client socket)", NULL, server_conf);
  ! 	    }
  ! 	}
  ! 	else {
  ! 	    fd_set fds;
    
  ! 	    do {
  !                 FD_ZERO(&fds);
  !                 FD_SET(sd,&fds);
    #ifdef SELECT_NEEDS_CAST
  ! 		csd = select(sd+1, (int*)&fds, NULL, NULL, NULL);
    #else
  ! 		csd = select(sd+1, &fds, NULL, NULL, NULL);
    #endif
  !             } while (csd < 0 && errno == EINTR);
    
  !             if (csd < 0) {
  ! 		log_unixerr("select","(listen)",NULL,server_conf);
  ! 		exit(0);
                }
  - 	    /*fprintf(stderr,"%d check(2a) %d %d\n",getpid(),scoreboard_image->global.exit_generation,generation);*/
  - 	    sync_scoreboard_image();
  - 	    if(scoreboard_image->global.exit_generation >= generation)
  - 		exit(0);
    
                do {
                    clen = sizeof(sa_client);
                    csd  = accept(sd, &sa_client, &clen);
                } while (csd < 0 && errno == EINTR);
  -             if (csd < 0)
  -                 log_unixerr("accept", NULL, "socket error: accept failed",
  -                             server_conf);
  - 	}
    
  ! 	accept_mutex_off(); /* unlock after "accept" */
    
    	clen = sizeof(sa_server);
  ! 	if(getsockname(csd, &sa_server, &clen) < 0) {
    	    log_unixerr("getsockname", NULL, NULL, server_conf);
    	    continue;
    	}
    
    	sock_disable_nagle(csd);
    
  ! 	(void)update_child_status (child_num, SERVER_BUSY_READ, (request_rec*)NULL);
    	conn_io = bcreate(ptrans, B_RDWR);
    	dupped_csd = csd;
    #if defined(NEED_DUPPED_CSD)
  --- 1604,1685 ----
    	    exit(0);
    	}
    
  ! 	(void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL);
    
  !         if (listeners == NULL) {
  !             FD_ZERO(&listenfds);
  !             FD_SET(sd, &listenfds);
  !             listenmaxfd = sd;
  !         }
    
  !         /*
  !          * Wait for an acceptable connection to arrive.
  !          */
    
  !         accept_mutex_on();  /* Lock around "accept", if necessary */
    
  !         for (;;) {
  !             memcpy(&main_fds, &listenfds, sizeof(fd_set));
    #ifdef SELECT_NEEDS_CAST
  !             srv = select(listenmaxfd+1, (int*)&main_fds, NULL, NULL, NULL);
    #else
  !             srv = select(listenmaxfd+1, &main_fds, NULL, NULL, NULL);
    #endif
  !             sync_scoreboard_image();
  !             if (scoreboard_image->global.exit_generation >= generation)
  !                 exit(0);
  ! 
  !             if (srv < 0 && errno != EINTR)
  !                 log_unixerr("select", "(listen)", NULL, server_conf);
    
  !             if (srv <= 0)
  !                 continue;
  ! 
  !             if (listeners != NULL) {
  !                 for (sd = listenmaxfd; sd >= 0; sd--)
  !                     if (FD_ISSET(sd, &main_fds)) break;
  !                 if (sd < 0)
  !                     continue;
                }
    
                do {
                    clen = sizeof(sa_client);
                    csd  = accept(sd, &sa_client, &clen);
                } while (csd < 0 && errno == EINTR);
    
  !             if (csd >= 0)
  !                 break;      /* We have a socket ready for reading */
  !             else {
  ! 
  ! #if defined(EPROTO) && defined(ECONNABORTED)
  !               if ((errno != EPROTO) && (errno != ECONNABORTED))
  ! #elif defined(EPROTO)
  !               if (errno != EPROTO)
  ! #elif defined(ECONNABORTED)
  !               if (errno != ECONNABORTED)
  ! #endif
  !                 log_unixerr("accept", "(client socket)", NULL, server_conf);
  !             }
  !         }
  ! 
  !         accept_mutex_off(); /* unlock after "accept" */
  ! 
  !         /*
  !          * We now have a connection, so set it up with the appropriate
  !          * socket options, file descriptors, and read/write buffers.
  !          */
    
    	clen = sizeof(sa_server);
  ! 	if (getsockname(csd, &sa_server, &clen) < 0) {
    	    log_unixerr("getsockname", NULL, NULL, server_conf);
    	    continue;
    	}
    
    	sock_disable_nagle(csd);
    
  ! 	(void)update_child_status(child_num, SERVER_BUSY_READ,
  ! 	                          (request_rec*)NULL);
  ! 
    	conn_io = bcreate(ptrans, B_RDWR);
    	dupped_csd = csd;
    #if defined(NEED_DUPPED_CSD)
  ***************
  *** 1686,1734 ****
    				       (struct sockaddr_in *)&sa_server,
    				       child_num);
    
  ! 	r = read_request (current_conn);
  ! 	(void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
  ! 	if (r) process_request (r); /* else premature EOF --- ignore */
  ! #if defined(STATUS)
  !         if (r) increment_counts(child_num,r,1);
  ! #endif
  ! 	while (r && current_conn->keepalive) {
  ! 	    destroy_pool(r->pool);
  ! 	    (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE,
  ! 	     (request_rec*)NULL);
  ! 	    r = read_request (current_conn);
  ! 	    (void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
  ! 	    if (r) process_request (r);
    #if defined(STATUS)
  ! 	    if (r) increment_counts(child_num,r,0);
    #endif
  ! 	  sync_scoreboard_image();
  ! 	  if(scoreboard_image->global.exit_generation >= generation)
  ! 	      exit(0);
  ! 	  /*fprintf(stderr,"%d check(3) %d %d\n",getpid(),scoreboard_image->global.exit_generation,generation);*/
    
  ! 	}
  ! #if 0	
  ! 	if (bytes_in_pool (ptrans) > 80000)
  ! 	    log_printf(r->server,
  ! 		       "Memory hog alert: allocated %ld bytes for %s",
  ! 		       bytes_in_pool (ptrans), r->the_request);
  ! #endif		
  ! 	bflush(conn_io);
    
    #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	
        }    
    }
    
  --- 1695,1752 ----
    				       (struct sockaddr_in *)&sa_server,
    				       child_num);
    
  !         /*
  !          * Read and process each request found on our connection
  !          * until no requests are left or we decide to close.
  !          */
  ! 
  !         for (;;) {
  !             r = read_request(current_conn);
  !             (void)update_child_status(child_num, SERVER_BUSY_WRITE, r);
  ! 
  !             if (r) process_request(r); /* else premature EOF --- ignore */
    #if defined(STATUS)
  !             if (r) increment_counts(child_num,r,1);
    #endif
  !             if (!r || !current_conn->keepalive)
  !                 break;
    
  !             destroy_pool(r->pool);
  !             (void)update_child_status(child_num, SERVER_BUSY_KEEPALIVE,
  !                                       (request_rec*)NULL);
  ! 
  !             sync_scoreboard_image();
  !             if (scoreboard_image->global.exit_generation >= generation) {
  !                 bclose(conn_io);
  !                 exit(0);
  !             }
  !         }
  ! 
  !         /*
  !          * Close the connection, being careful to send out whatever is still
  !          * in our buffers.  If possible, try to avoid a hard close until the
  !          * client has ACKed our FIN and/or has stopped sending us data.
  !          */
    
    #ifdef NO_LINGCLOSE
  !         bclose(conn_io);        /* just close it */
    #else
  !         if (r &&  r->connection
  !               && !r->connection->aborted
  !               &&  r->connection->client
  !               && (r->connection->client->fd >= 0)) {
  ! 
  !             lingering_close(r);
  !         }
  !         else {
  !             /* if the connection was aborted by a soft_timeout, it has
  !              * already been shutdown() so we don't need to go through
  !              * lingering_close
  !              */
  !             bsetflag(conn_io, B_EOUT, 1);
  !             bclose(conn_io);
  !         }
  ! #endif
        }    
    }
    
  ***************
  *** 2207,2213 ****
                if (r) process_request (r);
            }
    
  - 	bflush(cio);
    	bclose(cio);
        }
        exit (0);
  --- 2225,2230 ----
  
  
  

Mime
View raw message