static void clear_connection( connecttab* c, struct timeval* tvP ) { ClientData client_data; /* If we haven't actually sent the buffered response yet, do so now. */ httpd_write_response( c->hc ); if ( c->idle_read_timer != (Timer*) 0 ) { tmr_cancel( c->idle_read_timer ); c->idle_read_timer = 0; } if ( c->idle_send_timer != (Timer*) 0 ) { tmr_cancel( c->idle_send_timer ); c->idle_send_timer = 0; } if ( c->wakeup_timer != (Timer*) 0 ) { tmr_cancel( c->wakeup_timer ); c->wakeup_timer = 0; } /* This is our version of Apache's lingering_close() routine, which is ** their version of the often-broken SO_LINGER socket option. For why ** this is necessary, see http://www.apache.org/docs/misc/fin_wait_2.html ** What we do is delay the actual closing for a few seconds, while reading ** any bytes that come over the connection. However, we don't want to do ** this unless it's necessary, because it ties up a connection slot and ** file descriptor which means our maximum connection-handling rate ** is lower. So, elsewhere we set a flag when we detect the few ** circumstances that make a lingering close necessary. If the flag ** isn't set we do the real close now. */ if ( c->hc->should_linger ) { c->conn_state = CNST_LINGERING; fdwatch_del_fd( c->hc->conn_fd ); fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); /* Make sure we are still in no-delay mode. */ httpd_set_ndelay( c->hc->conn_fd ); client_data.p = c; c->linger_timer = tmr_create( tvP, linger_clear_connection, client_data, LINGER_TIME * 1000L, 0 ); if ( c->linger_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(linger_clear_connection) failed" ); exit( 1 ); } } else really_clear_connection( c, tvP ); }
static int handle_newconnect(struct timeval *tv, int listen_fd) { struct connect_s *conn; ClientData client_data; /* This loops until the accept() fails, trying to start new connections as * fast as possible so we don't overrun the listen queue. */ nvdbg("New connection(s) on listen_fd %d\n", listen_fd); for (;;) { /* Get the next free connection from the free list */ conn = free_connections; /* Are there any free connections? */ if (!conn) { /* Out of connection slots. Run the timers, then the existing * connections, and maybe we'll free up a slot by the time we get * back here. */ ndbg("No free connections\n"); tmr_run(tv); return -1; } /* Make the httpd_conn if necessary */ if (!conn->hc) { conn->hc = NEW(httpd_conn, 1); if (conn->hc == NULL) { ndbg("out of memory allocating an httpd_conn\n"); exit(1); } conn->hc->initialized = 0; } /* Get the connection */ switch (httpd_get_conn(hs, listen_fd, conn->hc)) { /* Some error happened. Run the timers, then the existing * connections. Maybe the error will clear. */ case GC_FAIL: tmr_run(tv); return -1; /* No more connections to accept for now */ case GC_NO_MORE: return 0; default: break; } nvdbg("New connection fd %d\n", conn->hc->conn_fd); /* Remove the connection entry from the free list */ conn->conn_state = CNST_READING; free_connections = conn->next; conn->next = NULL; client_data.p = conn; conn->active_at = tv->tv_sec; conn->wakeup_timer = NULL; conn->linger_timer = NULL; conn->offset = 0; /* Set the connection file descriptor to no-delay mode */ httpd_set_ndelay(conn->hc->conn_fd); fdwatch_add_fd(fw, conn->hc->conn_fd, conn); } }
static int handle_newconnect( struct timeval* tvP, int listen_fd ) { connecttab* c; ClientData client_data; /* This loops until the accept() fails, trying to start new ** connections as fast as possible so we don't overrun the ** listen queue. */ for (;;) { /* Is there room in the connection table? */ if ( num_connects >= max_connects ) { /* Out of connection slots. Run the timers, then the ** existing connections, and maybe we'll free up a slot ** by the time we get back here. */ tmr_run( tvP ); return 0; } /* Get the first free connection entry off the free list. */ if ( first_free_connect == -1 || connects[first_free_connect].conn_state != CNST_FREE ) { return; } c = &connects[first_free_connect]; /* Make the httpd_conn if necessary. */ if ( c->hc == (httpd_conn*) 0 ) { c->hc = NEW( httpd_conn, 1 ); if ( c->hc == (httpd_conn*) 0 ) { return; } c->hc->initialized = 0; c->hc->conn = c; ++httpd_conn_count; } /* Get the connection. */ switch ( httpd_get_conn( hs, listen_fd, c->hc ) ) { /* Some error happened. Run the timers, then the ** existing connections. Maybe the error will clear. */ case GC_FAIL: tmr_run( tvP ); return 0; /* No more connections to accept for now. */ case GC_NO_MORE: return 1; } c->conn_state = CNST_READING; /* Pop it off the free list. */ first_free_connect = c->next_free_connect; c->next_free_connect = -1; ++num_connects; client_data.p = c; c->active_at = tvP->tv_sec; c->wakeup_timer = (Timer*) 0; c->linger_timer = (Timer*) 0; c->next_byte_index = 0; /* Set the connection file descriptor to no-delay mode. */ httpd_set_ndelay( c->hc->conn_fd ); fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); ++stats_connections; if ( num_connects > stats_simultaneous ) stats_simultaneous = num_connects; } }
static int handle_newconnect( struct timeval* tvP, int listen_fd ) { int cnum; connecttab* c; ClientData client_data; /* This loops until the accept() fails, trying to start new ** connections as fast as possible so we don't overrun the ** listen queue. */ for (;;) { /* Is there room in the connection table? */ if ( numconnects >= maxconnects ) { /* Out of connection slots. Run the timers, then the ** existing connections, and maybe we'll free up a slot ** by the time we get back here. **/ syslog( LOG_WARNING, "too many connections!" ); tmr_run( tvP ); return 0; } /* Find a free connection entry. */ for ( cnum = 0; cnum < maxconnects; ++cnum ) if ( connects[cnum].conn_state == CNST_FREE ) break; c = &connects[cnum]; /* Make the httpd_conn if necessary. */ if ( c->hc == (httpd_conn*) 0 ) { c->hc = NEW( httpd_conn, 1 ); if ( c->hc == (httpd_conn*) 0 ) { syslog( LOG_CRIT, "out of memory allocating an httpd_conn" ); exit( 1 ); } c->hc->initialized = 0; ++httpd_conn_count; } /* Get the connection. */ switch ( httpd_get_conn( hs, listen_fd, c->hc ) ) { case GC_FAIL: case GC_NO_MORE: return 1; } c->conn_state = CNST_READING; ++numconnects; client_data.p = c; c->idle_read_timer = tmr_create( tvP, idle_read_connection, client_data, IDLE_READ_TIMELIMIT * 1000L, 0 ); if ( c->idle_read_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(idle_read_connection) failed" ); exit( 1 ); } c->idle_send_timer = (Timer*) 0; c->wakeup_timer = (Timer*) 0; c->linger_timer = (Timer*) 0; c->bytes_sent = 0; c->numtnums = 0; /* Set the connection file descriptor to no-delay mode. */ httpd_set_ndelay( c->hc->conn_fd ); fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); ++stats_connections; if ( numconnects > stats_simultaneous ) stats_simultaneous = numconnects; } }