bool CLIENT_DESC::Connect(int iPhaseWhenSucceed) { if (iPhaseWhenSucceed != 0) m_iPhaseWhenSucceed = iPhaseWhenSucceed; if (get_global_time() - m_LastTryToConnectTime < 3) // 3초 return false; m_LastTryToConnectTime = get_global_time(); if (m_sock != INVALID_SOCKET) return false; sys_log(0, "SYSTEM: Trying to connect to %s:%d", m_stHost.c_str(), m_wPort); m_sock = socket_connect(m_stHost.c_str(), m_wPort); if (m_sock != INVALID_SOCKET) { sys_log(0, "SYSTEM: connected to server (fd %d, ptr %p)", m_sock, this); fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false); fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_WRITE, false); SetPhase(m_iPhaseWhenSucceed); return true; } else { SetPhase(PHASE_CLIENT_CONNECTING); return false; } }
int irc_run(irc_session_t * session) { if (session->state != LIBIRC_STATE_CONNECTING) { session->lasterror = LIBIRC_ERR_STATE; return 1; } while (irc_is_connected(session)) { const long timeout_ms = 750; fdwatch_zero(); fdwatch_add_fd(session->sock); irc_add_select_descriptors(session); if (fdwatch(timeout_ms) < 0) { if (socket_error() == EINTR) continue; session->lasterror = LIBIRC_ERR_TERMINATED; return 1; } if (session->callbacks.keep_alive_callback) { session->callbacks.keep_alive_callback(session); } if (irc_process_select_descriptors(session)) return 1; } return 0; }
bool CPeerBase::Accept(socket_t fd_accept) { struct sockaddr_in peer; if ((m_fd = socket_accept(fd_accept, &peer)) == INVALID_SOCKET) { Destroy(); return false; } //socket_block(m_fd); socket_sndbuf(m_fd, 233016); socket_rcvbuf(m_fd, 233016); strlcpymt(m_host, inet_ntoa(peer.sin_addr), sizeof(m_host)); m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE); m_inBuffer = buffer_new(MAX_INPUT_LEN); if (!m_outBuffer || !m_inBuffer) { Destroy(); return false; } fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false); OnAccept(); sys_log(0, "ACCEPT FROM %s", inet_ntoa(peer.sin_addr)); return true; }
static int server_listen(void) { t_addr * curr_laddr; t_addr_data laddr_data; int sock; if (!(server_listen_addrs=addrlist_create(prefs_get_servaddrs(),INADDR_ANY,D2CS_SERVER_PORT))) { eventlog(eventlog_level_error,__FUNCTION__,"error create listening address list"); return -1; } BEGIN_LIST_TRAVERSE_DATA(server_listen_addrs,curr_laddr) { sock=net_listen(addr_get_ip(curr_laddr),addr_get_port(curr_laddr),PSOCK_SOCK_STREAM); if (sock<0) { eventlog(eventlog_level_error,__FUNCTION__,"error listen socket"); return -1; } if (psock_ctl(sock,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"error set listen socket in non-blocking mode"); } laddr_data.i = sock; addr_set_data(curr_laddr,laddr_data); if (fdwatch_add_fd(sock, fdwatch_type_read, d2cs_server_handle_accept, curr_laddr)<0) { eventlog(eventlog_level_error,__FUNCTION__,"error adding socket %d to fdwatch pool (max sockets?)",sock); psock_close(sock); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"listen on %s", addr_num_to_addr_str(addr_get_ip(curr_laddr),addr_get_port(curr_laddr))); }
void CPeerBase::Encode(const void* data, DWORD size) { if (!m_outBuffer) { sys_err("Not ready to write"); return; } buffer_write(m_outBuffer, data, size); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); }
void CPeerBase::EncodeDWORD(DWORD dw) { if (!m_outBuffer) { sys_err("Not ready to write"); return; } buffer_write(m_outBuffer, &dw, 4); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); }
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 ); }
void CPeerBase::EncodeBYTE(BYTE b) { if (!m_outBuffer) { sys_err("Not ready to write"); return; } buffer_write(m_outBuffer, &b, 1); fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); }
bool DESC::Setup(LPFDWATCH _fdw, socket_t _fd, const struct sockaddr_in & c_rSockAddr, DWORD _handle, DWORD _handshake) { m_lpFdw = _fdw; m_sock = _fd; m_stHost = inet_ntoa(c_rSockAddr.sin_addr); m_wPort = c_rSockAddr.sin_port; m_dwHandle = _handle; //if (LC_IsEurope() == true || LC_IsNewCIBN()) // m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2); //else //NOTE: 이걸 나라별로 다르게 잡아야할 이유가 있나? m_lpOutputBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE * 2); m_iMinInputBufferLen = MAX_INPUT_LEN >> 1; m_lpInputBuffer = buffer_new(MAX_INPUT_LEN); m_SockAddr = c_rSockAddr; fdwatch_add_fd(m_lpFdw, m_sock, this, FDW_READ, false); // Ping Event desc_event_info* info = AllocEventInfo<desc_event_info>(); info->desc = this; assert(m_pkPingEvent == NULL); m_pkPingEvent = event_create(ping_event, info, ping_event_second_cycle); #ifndef _IMPROVED_PACKET_ENCRYPTION_ if (LC_IsEurope()) { thecore_memcpy(m_adwEncryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4); thecore_memcpy(m_adwDecryptionKey, "1234abcd5678efgh", sizeof(DWORD) * 4); } else { thecore_memcpy(m_adwEncryptionKey, "testtesttesttest", sizeof(DWORD) * 4); thecore_memcpy(m_adwDecryptionKey, "testtesttesttest", sizeof(DWORD) * 4); } #endif // _IMPROVED_PACKET_ENCRYPTION_ // Set Phase to handshake SetPhase(PHASE_HANDSHAKE); StartHandshake(_handshake); sys_log(0, "SYSTEM: new connection from [%s] fd: %d handshake %u output input_len %d, ptr %p", m_stHost.c_str(), m_sock, m_dwHandshake, buffer_size(m_lpInputBuffer), this); Log("SYSTEM: new connection from [%s] fd: %d handshake %u ptr %p", m_stHost.c_str(), m_sock, m_dwHandshake, this); return true; }
static void wakeup_connection( ClientData client_data, struct timeval* nowP ) { connecttab* c; c = (connecttab*) client_data.p; c->wakeup_timer = (Timer*) 0; if ( c->conn_state == CNST_PAUSING || c->conn_state == CNST_SLEEPING ) { c->conn_state = CNST_SENDING; fdwatch_add_fd( c->hc->conn_fd, c, FDW_WRITE ); } }
static void clear_connection(struct connect_s *conn, struct timeval *tv) { ClientData client_data; if (conn->wakeup_timer != NULL) { tmr_cancel(conn->wakeup_timer); conn->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 rateis * 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 (conn->conn_state == CNST_LINGERING) { /* If we were already lingering, shut down for real */ tmr_cancel(conn->linger_timer); conn->linger_timer = NULL; conn->hc->should_linger = false; } else if (conn->hc->should_linger) { fdwatch_del_fd(fw, conn->hc->conn_fd); conn->conn_state = CNST_LINGERING; fdwatch_add_fd(fw, conn->hc->conn_fd, conn); client_data.p = conn; conn->linger_timer = tmr_create(tv, linger_clear_connection, client_data, CONFIG_THTTPD_LINGER_MSEC, 0); if (conn->linger_timer != NULL) { return; } nerr("ERROR: tmr_create(linger_clear_connection) failed\n"); } /* Either we are done lingering, we shouldn't linger, or we failed to setup the linger */ really_clear_connection(conn); }
static bool hasConnection(const irc_session_t *session) { const long timeout_ms = 5000; fdwatch_zero(); fdwatch_add_fd(session->sock); fdwatch_set_fd(session->sock, FDW_WRITE); fdwatch(timeout_ms); if (fdwatch_check_fd(session->sock, FDW_WRITE)) { if (isConnectionEstablished(session)) { return true; } } else { DBG_WARN("got nothing at fdwatch_check_fd at connect!"); } return false; }
static void clear_connection( connecttab* c, struct timeval* tvP ) { ClientData client_data; 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->conn_state == CNST_LINGERING ) { /* If we were already lingering, shut down for real. */ tmr_cancel( c->linger_timer ); c->linger_timer = (Timer*) 0; c->hc->should_linger = 0; } if ( c->hc->should_linger ) { if ( c->conn_state != CNST_PAUSING && c->conn_state != CNST_SLEEPING ) fdwatch_del_fd( c->hc->conn_fd ); c->conn_state = CNST_LINGERING; shutdown( c->hc->conn_fd, SHUT_WR ); fdwatch_add_fd( c->hc->conn_fd, c, FDW_READ ); client_data.p = c; c->linger_timer = tmr_create( tvP, linger_clear_connection, client_data, LINGER_TIME, 0 ); } else really_clear_connection( c, tvP ); }
static void libirc_dcc_add_descriptors(irc_session_t * ircsession) { irc_dcc_session_t * dcc, *dcc_next; libirc_mutex_lock(&ircsession->mutex_dcc); // Preprocessing DCC list: // - ask DCC send callbacks for data; // - remove unused DCC structures for (dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next) { dcc_next = dcc->next; // Clean up unused sessions if (dcc->state == LIBIRC_STATE_REMOVED) libirc_remove_dcc_session(ircsession, dcc, 0); } for (dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next) { fdwatch_add_fd(dcc->sock); switch (dcc->state) { case LIBIRC_STATE_CONNECTING: // While connection, only out_set descriptor should be set fdwatch_set_fd(dcc->sock, FDW_WRITE); break; case LIBIRC_STATE_CONNECTED: fdwatch_set_fd(dcc->sock, FDW_READ); break; case LIBIRC_STATE_CONFIRM_SIZE: fdwatch_set_fd(dcc->sock, FDW_WRITE); break; case LIBIRC_STATE_WAITING_FOR_RESUME_ACK: break; default: DBG_WARN("unknown state at libirc_dcc_add_descriptors"); break; } } libirc_mutex_unlock(&ircsession->mutex_dcc); }
bool CPeerBase::Connect(const char* host, WORD port) { strlcpymt(m_host, host, sizeof(m_host)); if ((m_fd = socket_connect(host, port)) == INVALID_SOCKET) return false; m_outBuffer = buffer_new(DEFAULT_PACKET_BUFFER_SIZE); if (!m_outBuffer) { Destroy(); return false; } fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_READ, false); OnConnect(); return true; }
static void handle_read_2( connecttab *c, struct timeval *tvP ) { httpd_conn* hc = c->hc; ClientData client_data; /* Fill in end_byte_index. */ if ( hc->got_range ) { c->next_byte_index = hc->first_byte_index; c->end_byte_index = hc->last_byte_index + 1; } else if ( hc->bytes_to_send < 0 ) c->end_byte_index = 0; else c->end_byte_index = hc->bytes_to_send; /* Check if it's already handled. */ if ( hc->body_data == (char*) 0 ) { /* No body data means someone else is handling it. */ c->next_byte_index = hc->bytes_sent; finish_connection( c, tvP ); return; } if ( c->next_byte_index >= c->end_byte_index ) { /* There's nothing to send. */ finish_connection( c, tvP ); return; } /* Cool, we have a valid connection and a file to send to it. */ c->conn_state = CNST_SENDING; c->started_at = tvP->tv_sec; c->wouldblock_delay = 0; client_data.p = c; fdwatch_del_fd( hc->conn_fd ); fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE ); }
int CPeerBase::Send() { if (buffer_size(m_outBuffer) <= 0) return 0; int iBufferLeft = fdwatch_get_buffer_size(m_fdWatcher, m_fd); int iBytesToWrite = MIN(iBufferLeft, buffer_size(m_outBuffer)); if (iBytesToWrite == 0) return 0; int result = socket_write(m_fd, (const char *) buffer_read_peek(m_outBuffer), iBytesToWrite); if (result == 0) { buffer_read_proceed(m_outBuffer, iBytesToWrite); if (buffer_size(m_outBuffer) != 0) fdwatch_add_fd(m_fdWatcher, m_fd, this, FDW_WRITE, true); } return (result); }
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; } }
int thttpd_main(int argc, char **argv) #endif { int num_ready; int cnum; FAR struct connect_s *conn; FAR httpd_conn *hc; httpd_sockaddr sa; struct timeval tv; #ifdef CONFIG_THTTPD_DIR int ret; #endif nvdbg("THTTPD started\n"); /* Setup host address */ #ifdef CONFIG_NET_IPv6 # error "IPv6 support not yet implemented" #else sa.sin_family = AF_INET; sa.sin_port = HTONS(CONFIG_THTTPD_PORT); sa.sin_addr.s_addr = HTONL(CONFIG_THTTPD_IPADDR); #endif /* Initialize the fdwatch package to handle all of the configured * socket descriptors */ fw = fdwatch_initialize(CONFIG_NSOCKET_DESCRIPTORS); if (!fw) { ndbg("fdwatch initialization failure\n"); exit(1); } /* Switch directories again if requested */ #ifdef CONFIG_THTTPD_DATADIR if (chdir(CONFIG_THTTPD_DATADIR) < 0) { ndbg("chdir to %s: %d\n", CONFIG_THTTPD_DATADIR, errno); exit(1); } #endif /* Initialize the timer package */ tmr_init(); /* Initialize the HTTP layer */ nvdbg("Calling httpd_initialize()\n"); hs = httpd_initialize(&sa); if (!hs) { ndbg("httpd_initialize() failed\n"); exit(1); } /* Set up the occasional timer */ if (tmr_create(NULL, occasional, JunkClientData, CONFIG_THTTPD_OCCASIONAL_MSEC * 1000L, 1) == NULL) { ndbg("tmr_create(occasional) failed\n"); exit(1); } /* Set up the idle timer */ if (tmr_create(NULL, idle, JunkClientData, 5 * 1000L, 1) == NULL) { ndbg("tmr_create(idle) failed\n"); exit(1); } /* Initialize our connections table */ connects = NEW(struct connect_s, AVAILABLE_FDS); if (connects == NULL) { ndbg("Out of memory allocating a struct connect_s\n"); exit(1); } for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) { connects[cnum].conn_state = CNST_FREE; connects[cnum].next = &connects[cnum + 1]; connects[cnum].hc = NULL; } connects[AVAILABLE_FDS-1].next = NULL; /* End of link list */ free_connections = connects; /* Beginning of the link list */ if (hs != NULL) { if (hs->listen_fd != -1) { fdwatch_add_fd(fw, hs->listen_fd, NULL); } } /* Main loop */ nvdbg("Entering the main loop\n"); (void)gettimeofday(&tv, NULL); for (;;) { /* Do the fd watch */ num_ready = fdwatch(fw, tmr_mstimeout(&tv)); if (num_ready < 0) { if (errno == EINTR || errno == EAGAIN) { /* Not errors... try again */ continue; } ndbg("fdwatch failed: %d\n", errno); exit(1); } (void)gettimeofday(&tv, NULL); if (num_ready == 0) { /* No fd's are ready - run the timers */ tmr_run(&tv); continue; } /* Is it a new connection? */ if (fdwatch_check_fd(fw, hs->listen_fd)) { if (!handle_newconnect(&tv, hs->listen_fd)) { /* Go around the loop and do another fdwatch, rather than * dropping through and processing existing connections. New * connections always get priority. */ continue; } } /* Find the connections that need servicing */ while ((conn = (struct connect_s*)fdwatch_get_next_client_data(fw)) != (struct connect_s*)-1) { if (conn) { hc = conn->hc; if (fdwatch_check_fd(fw, hc->conn_fd)) { nvdbg("Handle conn_state %d\n", conn->conn_state); switch (conn->conn_state) { case CNST_READING: { handle_read(conn, &tv); /* If a GET request was received and a file is ready to * be sent, then fall through to send the file. */ if (conn->conn_state != CNST_SENDING) { break; } } case CNST_SENDING: { /* Send a file -- this really should be performed on a * separate thread to keep the serve from locking up during * the write. */ handle_send(conn, &tv); } break; case CNST_LINGERING: { /* Linger close the connection */ handle_linger(conn, &tv); } break; } } } } tmr_run(&tv); } /* The main loop terminated */ shut_down(); ndbg("Exiting\n"); exit(0); }
static void handle_read( connecttab* c, struct timeval* tvP ) { int sz; ClientData client_data; httpd_conn* hc = c->hc; /* Is there room in our buffer to read more bytes? */ if ( hc->read_idx >= hc->read_size ) { if ( hc->read_size > 5000 ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } httpd_realloc_str( &hc->read_buf, &hc->read_size, hc->read_size + 1000 ); } /* Read some more bytes. */ sz = read( hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx ); /* Ignore EWOULDBLOCK errors. At first glance you would think that ** connections returned by fdwatch as readable should never give an ** EWOULDBLOCK; however, this apparently can happen if a packet gets ** garbled. */ if ( sz == 0 || ( sz < 0 && ( errno != EWOULDBLOCK ) ) ) { httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } hc->read_idx += sz; /* Do we have a complete request yet? */ switch ( httpd_got_request( hc ) ) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" ); clear_connection( c, tvP ); return; } /* Yes. Try parsing and resolving it. */ if ( httpd_parse_request( hc ) < 0 ) { clear_connection( c, tvP ); return; } /* Check the throttle table */ if ( ! check_throttles( c ) ) { httpd_send_err( hc, 503, httpd_err503title, "", httpd_err503form, hc->encodedurl ); clear_connection( c, tvP ); return; } /* Start the connection going. */ if ( httpd_start_request( hc, tvP ) < 0 ) { /* Something went wrong. Close down the connection. */ clear_connection( c, tvP ); return; } /* Fill in bytes_to_send. */ if ( hc->got_range ) { c->bytes_sent = hc->init_byte_loc; c->bytes_to_send = hc->end_byte_loc + 1; } else c->bytes_to_send = hc->bytes_to_send; /* Check if it's already handled. */ if ( hc->file_address == (char*) 0 ) { /* No file address means someone else is handling it. */ c->bytes_sent = hc->bytes_sent; clear_connection( c, tvP ); return; } if ( c->bytes_sent >= c->bytes_to_send ) { /* There's nothing to send. */ clear_connection( c, tvP ); return; } /* Cool, we have a valid connection and a file to send to it. */ c->conn_state = CNST_SENDING; c->started_at = tvP->tv_sec; c->wouldblock_delay = 0; client_data.p = c; tmr_cancel( c->idle_read_timer ); c->idle_read_timer = (Timer*) 0; c->idle_send_timer = tmr_create( tvP, idle_send_connection, client_data, IDLE_SEND_TIMELIMIT * 1000L, 0 ); if ( c->idle_send_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(idle_send_connection) failed" ); exit( 1 ); } fdwatch_del_fd( hc->conn_fd ); fdwatch_add_fd( hc->conn_fd, c, FDW_WRITE ); }
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); } }
int start(int argc, char **argv) { std::string st_localeServiceName; bool bVerbose = false; char ch; //_malloc_options = "A"; #if defined(__FreeBSD__) && defined(DEBUG_ALLOC) _malloc_message = WriteMallocMessage; #endif while ((ch = getopt(argc, argv, "npverltI")) != -1) { char* ep = NULL; switch (ch) { case 'I': // IP enhance_strlcpymt(g_szPublicIP, argv[optind], sizeof(g_szPublicIP)); printf("IP %s\n", g_szPublicIP); optind++; optreset = 1; break; case 'p': // port mother_port = strtol(argv[optind], &ep, 10); if (mother_port <= 1024) { usage(); return 0; } printf("port %d\n", mother_port); optind++; optreset = 1; break; case 'l': { long l = strtol(argv[optind], &ep, 10); log_set_level(l); optind++; optreset = 1; } break; // LOCALE_SERVICE case 'n': { if (optind < argc) { st_localeServiceName = argv[optind++]; optreset = 1; } } break; // END_OF_LOCALE_SERVICE case 'v': // verbose bVerbose = true; break; case 'r': g_bNoRegen = true; break; // TRAFFIC_PROFILER case 't': g_bTrafficProfileOn = true; break; // END_OF_TRAFFIC_PROFILER } } // LOCALE_SERVICE config_init(st_localeServiceName); // END_OF_LOCALE_SERVICE #ifdef _WIN32 // In Windows dev mode, "verbose" option is [on] by default. bVerbose = true; #endif if (!bVerbose) freopen("stdout", "a", stdout); bool is_thecore_initialized = thecore_init(25, heartbeat); if (!is_thecore_initialized) { fprintf(stderr, "Could not initialize thecore, check owner of pid, syslog\n"); exit(0); } if (false == CThreeWayWar::instance().LoadSetting("forkedmapindex.txt")) { if (false == g_bAuthServer) { fprintf(stderr, "Could not Load ThreeWayWar Setting file"); exit(0); } } signal_timer_disable(); main_fdw = fdwatch_new(4096); fprintf(stderr, "PUBLIC_IP: %s\n", g_szPublicIP); fprintf(stderr, "INTERNAL_IP: %s\n", g_szInternalIP); if ((tcp_socket = socket_tcp_bind(g_szPublicIP, mother_port)) == INVALID_SOCKET) { perror("socket_tcp_bind: tcp_socket"); return 0; } #ifndef __UDP_BLOCK__ if ((udp_socket = socket_udp_bind(g_szPublicIP, mother_port)) == INVALID_SOCKET) { perror("socket_udp_bind: udp_socket"); return 0; } #endif // if internal ip exists, p2p socket uses internal ip, if not use public ip //if ((p2p_socket = socket_tcp_bind(*g_szInternalIP ? g_szInternalIP : g_szPublicIP, p2p_port)) == INVALID_SOCKET) if ((p2p_socket = socket_tcp_bind(g_szPublicIP, p2p_port)) == INVALID_SOCKET) { perror("socket_tcp_bind: p2p_socket"); return 0; } fdwatch_add_fd(main_fdw, tcp_socket, NULL, FDW_READ, false); #ifndef __UDP_BLOCK__ fdwatch_add_fd(main_fdw, udp_socket, NULL, FDW_READ, false); #endif fdwatch_add_fd(main_fdw, p2p_socket, NULL, FDW_READ, false); db_clientdesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, db_addr, db_port, PHASE_DBCLIENT, true); if (!g_bAuthServer) { db_clientdesc->UpdateChannelStatus(0, true); } if (g_bAuthServer) { if (g_stAuthMasterIP.length() != 0) { fprintf(stderr, "SlaveAuth"); g_pkAuthMasterDesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, g_stAuthMasterIP.c_str(), g_wAuthMasterPort, PHASE_P2P, true); P2P_MANAGER::instance().RegisterConnector(g_pkAuthMasterDesc); g_pkAuthMasterDesc->SetP2P(g_stAuthMasterIP.c_str(), g_wAuthMasterPort, g_bChannel); } else { fprintf(stderr, "MasterAuth %d", LC_GetLocalType()); } } /* game server to teen server */ else { if (teen_addr[0] && teen_port) g_TeenDesc = DESC_MANAGER::instance().CreateConnectionDesc(main_fdw, teen_addr, teen_port, PHASE_TEEN, true); extern unsigned int g_uiSpamBlockDuration; extern unsigned int g_uiSpamBlockScore; extern unsigned int g_uiSpamReloadCycle; sys_log(0, "SPAM_CONFIG: duration %u score %u reload cycle %u\n", g_uiSpamBlockDuration, g_uiSpamBlockScore, g_uiSpamReloadCycle); extern void LoadSpamDB(); LoadSpamDB(); } signal_timer_enable(30); return 1; }
int main( int argc, char** argv ) { char* cp; struct passwd* pwd; uid_t uid; gid_t gid; char cwd[MAXPATHLEN]; FILE* logfp; int num_ready; int cnum, ridx; connecttab* c; httpd_conn* hc; httpd_sockaddr sa4; httpd_sockaddr sa6; int gotv4, gotv6; struct timeval tv; argv0 = argv[0]; cp = strrchr( argv0, '/' ); if ( cp != (char*) 0 ) ++cp; else cp = argv0; openlog( cp, LOG_NDELAY|LOG_PID, LOG_FACILITY ); /* Handle command-line arguments. */ parse_args( argc, argv ); /* Check port number. */ if ( port <= 0 ) { syslog( LOG_CRIT, "illegal port number" ); (void) fprintf( stderr, "%s: illegal port number\n", argv0 ); exit( 1 ); } /* Read zone info now, in case we chroot(). */ tzset(); /* Look up hostname now, in case we chroot(). */ lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 ); if ( ! ( gotv4 || gotv6 ) ) { syslog( LOG_ERR, "can't find any valid address" ); (void) fprintf( stderr, "%s: can't find any valid address\n", argv0 ); exit( 1 ); } /* Throttle file. */ numthrottles = 0; maxthrottles = 0; throttles = (throttletab*) 0; if ( throttlefile != (char*) 0 ) read_throttlefile( throttlefile ); /* Log file. */ if ( logfile != (char*) 0 ) { if ( strcmp( logfile, "/dev/null" ) == 0 ) { no_log = 1; logfp = (FILE*) 0; } else { logfp = fopen( logfile, "a" ); if ( logfp == (FILE*) 0 ) { syslog( LOG_CRIT, "%.80s - %m", logfile ); perror( logfile ); exit( 1 ); } (void) fcntl( fileno( logfp ), F_SETFD, 1 ); } } else logfp = (FILE*) 0; /* Figure out uid/gid from user. */ pwd = getpwnam( user ); if ( pwd == (struct passwd*) 0 ) { syslog( LOG_CRIT, "unknown user - '%.80s'", user ); (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user ); exit( 1 ); } uid = pwd->pw_uid; gid = pwd->pw_gid; /* Switch directories if requested. */ if ( dir != (char*) 0 ) { if ( chdir( dir ) < 0 ) { syslog( LOG_CRIT, "chdir - %m" ); perror( "chdir" ); exit( 1 ); } } #ifdef USE_USER_DIR else if ( getuid() == 0 ) { /* No explicit directory was specified, we're root, and the ** USE_USER_DIR option is set - switch to the specified user's ** home dir. */ if ( chdir( pwd->pw_dir ) < 0 ) { syslog( LOG_CRIT, "chdir - %m" ); perror( "chdir" ); exit( 1 ); } } #endif /* USE_USER_DIR */ /* Get current directory. */ (void) getcwd( cwd, sizeof(cwd) - 1 ); if ( cwd[strlen( cwd ) - 1] != '/' ) (void) strcat( cwd, "/" ); if ( ! debug ) { /* We're not going to use stdin stdout or stderr from here on, so close ** them to save file descriptors. */ (void) fclose( stdin ); (void) fclose( stdout ); (void) fclose( stderr ); /* Daemonize - make ourselves a subprocess. */ #ifdef HAVE_DAEMON if ( daemon( 1, 1 ) < 0 ) { syslog( LOG_CRIT, "daemon - %m" ); exit( 1 ); } #else /* HAVE_DAEMON */ switch ( fork() ) { case 0: break; case -1: syslog( LOG_CRIT, "fork - %m" ); exit( 1 ); default: exit( 0 ); } #ifdef HAVE_SETSID (void) setsid(); #endif /* HAVE_SETSID */ #endif /* HAVE_DAEMON */ } else { /* Even if we don't daemonize, we still want to disown our parent ** process. */ #ifdef HAVE_SETSID (void) setsid(); #endif /* HAVE_SETSID */ } if ( pidfile != (char*) 0 ) { /* Write the PID file. */ FILE* pidfp = fopen( pidfile, "w" ); if ( pidfp == (FILE*) 0 ) { syslog( LOG_CRIT, "%.80s - %m", pidfile ); exit( 1 ); } (void) fprintf( pidfp, "%d\n", (int) getpid() ); (void) fclose( pidfp ); } /* Chroot if requested. */ if ( do_chroot ) { if ( chroot( cwd ) < 0 ) { syslog( LOG_CRIT, "chroot - %m" ); perror( "chroot" ); exit( 1 ); } (void) strcpy( cwd, "/" ); /* Always chdir to / after a chroot. */ if ( chdir( cwd ) < 0 ) { syslog( LOG_CRIT, "chroot chdir - %m" ); perror( "chroot chdir" ); exit( 1 ); } } /* Set up to catch signals. */ (void) signal( SIGTERM, handle_term ); (void) signal( SIGINT, handle_term ); (void) signal( SIGPIPE, SIG_IGN ); /* get EPIPE instead */ (void) signal( SIGHUP, handle_hup ); got_usr1 = 0; (void) signal( SIGUSR1, handle_usr1 ); (void) signal( SIGUSR2, handle_usr2 ); /* Initialize the timer package. */ tmr_init(); /* Initialize the HTTP layer. Got to do this before giving up root, ** so that we can bind to a privileged port. */ hs = httpd_initialize( hostname, gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0, port, cgi_pattern, charset, cwd, no_log, logfp, no_symlink, do_vhost, do_global_passwd, url_pattern, local_pattern, no_empty_referers ); if ( hs == (httpd_server*) 0 ) exit( 1 ); /* Set up the occasional timer. */ if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(occasional) failed" ); exit( 1 ); } if ( numthrottles > 0 ) { /* Set up the throttles timer. */ if ( tmr_create( (struct timeval*) 0, update_throttles, JunkClientData, THROTTLE_TIME * 1000L, 1 ) == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(update_throttles) failed" ); exit( 1 ); } } #ifdef STATS_TIME /* Set up the stats timer. */ if ( tmr_create( (struct timeval*) 0, show_stats, JunkClientData, STATS_TIME * 1000L, 1 ) == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(show_stats) failed" ); exit( 1 ); } #endif /* STATS_TIME */ start_time = stats_time = time( (time_t*) 0 ); stats_connections = stats_bytes = 0L; stats_simultaneous = 0; /* If we're root, try to become someone else. */ if ( getuid() == 0 ) { /* Set aux groups to null. */ if ( setgroups( 0, (const gid_t*) 0 ) < 0 ) { syslog( LOG_CRIT, "setgroups - %m" ); exit( 1 ); } /* Set primary group. */ if ( setgid( gid ) < 0 ) { syslog( LOG_CRIT, "setgid - %m" ); exit( 1 ); } /* Try setting aux groups correctly - not critical if this fails. */ if ( initgroups( user, gid ) < 0 ) syslog( LOG_WARNING, "initgroups - %m" ); #ifdef HAVE_SETLOGIN /* Set login name. */ (void) setlogin( user ); #endif /* HAVE_SETLOGIN */ /* Set uid. */ if ( setuid( uid ) < 0 ) { syslog( LOG_CRIT, "setuid - %m" ); exit( 1 ); } /* Check for unnecessary security exposure. */ if ( ! do_chroot ) syslog( LOG_CRIT, "started as root without requesting chroot(), warning only" ); } /* Initialize our connections table. */ maxconnects = fdwatch_get_nfiles(); if ( maxconnects < 0 ) { syslog( LOG_CRIT, "fdwatch initialization failure" ); exit( 1 ); } maxconnects -= SPARE_FDS; connects = NEW( connecttab, maxconnects ); if ( connects == (connecttab*) 0 ) { syslog( LOG_CRIT, "out of memory allocating a connecttab" ); exit( 1 ); } for ( cnum = 0; cnum < maxconnects; ++cnum ) { connects[cnum].conn_state = CNST_FREE; connects[cnum].hc = (httpd_conn*) 0; } numconnects = 0; httpd_conn_count = 0; if ( hs != (httpd_server*) 0 ) { if ( hs->listen4_fd != -1 ) fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ ); if ( hs->listen6_fd != -1 ) fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ ); } /* Main loop. */ (void) gettimeofday( &tv, (struct timezone*) 0 ); while ( ( ! terminate ) || numconnects > 0 ) { /* Do the fd watch. */ num_ready = fdwatch( tmr_mstimeout( &tv ) ); if ( num_ready < 0 ) { if ( errno == EINTR ) continue; /* try again */ syslog( LOG_ERR, "fdwatch - %m" ); exit( 1 ); } (void) gettimeofday( &tv, (struct timezone*) 0 ); if ( num_ready == 0 ) { /* No fd's are ready - run the timers. */ tmr_run( &tv ); continue; } /* Is it a new connection? */ if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && fdwatch_check_fd( hs->listen6_fd ) ) { if ( handle_newconnect( &tv, hs->listen6_fd ) ) /* Go around the loop and do another fdwatch, rather than ** dropping through and processing existing connections. ** New connections always get priority. */ continue; } if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && fdwatch_check_fd( hs->listen4_fd ) ) { if ( handle_newconnect( &tv, hs->listen4_fd ) ) /* Go around the loop and do another fdwatch, rather than ** dropping through and processing existing connections. ** New connections always get priority. */ continue; } /* Find the connections that need servicing. */ for ( ridx = 0; ridx < num_ready; ++ridx ) { c = (connecttab*) fdwatch_get_client_data( ridx ); if ( c == (connecttab*) 0 ) continue; hc = c->hc; if ( c->conn_state == CNST_READING && fdwatch_check_fd( hc->conn_fd ) ) handle_read( c, &tv ); else if ( c->conn_state == CNST_SENDING && fdwatch_check_fd( hc->conn_fd ) ) handle_send( c, &tv ); else if ( c->conn_state == CNST_LINGERING && fdwatch_check_fd( hc->conn_fd ) ) handle_linger( c, &tv ); } tmr_run( &tv ); if ( got_usr1 && ! terminate ) { terminate = 1; if ( hs != (httpd_server*) 0 ) { httpd_terminate( hs ); hs = (httpd_server*) 0; } } } /* The main loop terminated. */ shut_down(); syslog( LOG_NOTICE, "exiting" ); closelog(); exit( 0 ); }
int thttpd_run(void) { char* cp; struct passwd* pwd; uid_t uid = 32767; gid_t gid = 32767; int num_ready; int cnum; connecttab* c; httpd_conn* hc; httpd_sockaddr sa4; httpd_sockaddr sa6; int gotv4, gotv6; struct timeval tv; cp = getenv( "GHTTPPORT" ); if ( cp ) port = atoi( cp ); if( port == 0 ) port = 9999; /* Read zone info now, in case we chroot(). */ tzset(); /* Look up hostname now, in case we chroot(). */ lookup_hostname( &sa4, sizeof(sa4), &gotv4, &sa6, sizeof(sa6), &gotv6 ); if ( ! ( gotv4 || gotv6 ) ) { memset(&sa4, 0, sizeof sa4); gotv4 = 1; } /* Initialize the fdwatch package. Have to do this before chroot, ** if /dev/poll is used. */ max_connects = fdwatch_get_nfiles(); if ( max_connects < 0 ) { return; } max_connects -= SPARE_FDS; /* Set up to catch signals. */ #ifdef HAVE_SIGSET (void) sigset( SIGPIPE, SIG_IGN ); /* get EPIPE instead */ #else /* HAVE_SIGSET */ (void) signal( SIGPIPE, SIG_IGN ); /* get EPIPE instead */ #endif /* HAVE_SIGSET */ /* Initialize the timer package. */ tmr_init(); /* Initialize the HTTP layer. Got to do this before giving up root, ** so that we can bind to a privileged port. */ hs = httpd_initialize( hostname, gotv4 ? &sa4 : (httpd_sockaddr*) 0, gotv6 ? &sa6 : (httpd_sockaddr*) 0, port, cgi_pattern, cgi_limit, charset, p3p, max_age, "/", no_log, no_symlink_check, do_vhost, do_global_passwd, url_pattern, local_pattern, no_empty_referers ); if ( hs == (httpd_server*) 0 ) exit( 1 ); /* Set up the occasional timer. */ if ( tmr_create( (struct timeval*) 0, occasional, JunkClientData, OCCASIONAL_TIME * 1000L, 1 ) == (Timer*) 0 ) { return; } /* Set up the idle timer. */ if ( tmr_create( (struct timeval*) 0, idle, JunkClientData, 5 * 1000L, 1 ) == (Timer*) 0 ) { return; } start_time = stats_time = time( (time_t*) 0 ); stats_connections = 0; stats_bytes = 0; stats_simultaneous = 0; /* Initialize our connections table. */ connects = NEW( connecttab, max_connects ); if ( connects == (connecttab*) 0 ) { return; } for ( cnum = 0; cnum < max_connects; ++cnum ) { connects[cnum].conn_state = CNST_FREE; connects[cnum].next_free_connect = cnum + 1; connects[cnum].hc = (httpd_conn*) 0; } connects[max_connects - 1].next_free_connect = -1; /* end of link list */ first_free_connect = 0; num_connects = 0; httpd_conn_count = 0; if ( hs != (httpd_server*) 0 ) { if ( hs->listen4_fd != -1 ) fdwatch_add_fd( hs->listen4_fd, (void*) 0, FDW_READ ); if ( hs->listen6_fd != -1 ) fdwatch_add_fd( hs->listen6_fd, (void*) 0, FDW_READ ); } /* Main loop. */ (void) gettimeofday( &tv, (struct timezone*) 0 ); while ( ( ! terminate ) || num_connects > 0 ) { /* Do the fd watch. */ num_ready = fdwatch( tmr_mstimeout( &tv ) ); if ( num_ready < 0 ) { if ( errno == EINTR || errno == EAGAIN ) continue; /* try again */ return; } (void) gettimeofday( &tv, (struct timezone*) 0 ); if ( num_ready == 0 ) { /* No fd's are ready - run the timers. */ tmr_run( &tv ); continue; } /* Is it a new connection? */ if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && fdwatch_check_fd( hs->listen6_fd ) ) { if ( handle_newconnect( &tv, hs->listen6_fd ) ) /* Go around the loop and do another fdwatch, rather than ** dropping through and processing existing connections. ** New connections always get priority. */ continue; } if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && fdwatch_check_fd( hs->listen4_fd ) ) { if ( handle_newconnect( &tv, hs->listen4_fd ) ) /* Go around the loop and do another fdwatch, rather than ** dropping through and processing existing connections. ** New connections always get priority. */ continue; } /* Find the connections that need servicing. */ while ( ( c = (connecttab*) fdwatch_get_next_client_data() ) != (connecttab*) -1 ) { if ( c == (connecttab*) 0 ) continue; hc = c->hc; if ( ! fdwatch_check_fd( hc->conn_fd ) ) /* Something went wrong. */ clear_connection( c, &tv ); else switch ( c->conn_state ) { case CNST_READING: handle_read( c, &tv ); break; case CNST_SENDING: handle_send( c, &tv ); break; case CNST_LINGERING: handle_linger( c, &tv ); break; } } tmr_run( &tv ); } /* The main loop terminated. */ shut_down(); return 0; }
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; } }