static void shut_down( void ) { int cnum; struct timeval tv; (void) gettimeofday( &tv, (struct timezone*) 0 ); for ( cnum = 0; cnum < max_connects; ++cnum ) { if ( connects[cnum].conn_state != CNST_FREE ) httpd_close_conn( connects[cnum].hc, &tv ); if ( connects[cnum].hc != (httpd_conn*) 0 ) { httpd_destroy_conn( connects[cnum].hc ); free( (void*) connects[cnum].hc ); --httpd_conn_count; connects[cnum].hc = (httpd_conn*) 0; } } if ( hs != (httpd_server*) 0 ) { httpd_server* ths = hs; hs = (httpd_server*) 0; if ( ths->listen4_fd != -1 ) fdwatch_del_fd( ths->listen4_fd ); if ( ths->listen6_fd != -1 ) fdwatch_del_fd( ths->listen6_fd ); httpd_terminate( ths ); } tmr_destroy(); free( (void*) connects ); }
void DESC::Destroy() { if (m_bDestroyed) { return; } m_bDestroyed = true; if (m_pkLoginKey) m_pkLoginKey->Expire(); if (GetAccountTable().id) DESC_MANAGER::instance().DisconnectAccount(GetAccountTable().login); if (m_pLogFile) { fclose(m_pLogFile); m_pLogFile = NULL; } if (m_lpCharacter) { m_lpCharacter->Disconnect("DESC::~DESC"); m_lpCharacter = NULL; } SAFE_BUFFER_DELETE(m_lpOutputBuffer); SAFE_BUFFER_DELETE(m_lpInputBuffer); event_cancel(&m_pkPingEvent); event_cancel(&m_pkDisconnectEvent); if (!g_bAuthServer) { if (m_accountTable.login[0] && m_accountTable.passwd[0]) { TLogoutPacket pack; strlcpymt(pack.login, m_accountTable.login, sizeof(pack.login)); strlcpymt(pack.passwd, m_accountTable.passwd, sizeof(pack.passwd)); db_clientdesc->DBPacket(HEADER_GD_LOGOUT, m_dwHandle, &pack, sizeof(TLogoutPacket)); } } if (m_sock != INVALID_SOCKET) { sys_log(0, "SYSTEM: closing socket. DESC #%d", m_sock); Log("SYSTEM: closing socket. DESC #%d", m_sock); fdwatch_del_fd(m_lpFdw, m_sock); #ifdef _IMPROVED_PACKET_ENCRYPTION_ cipher_.CleanUp(); #endif socket_close(m_sock); m_sock = INVALID_SOCKET; } m_seq_vector.clear(); }
static void shut_down(void) { int cnum; for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) { if (connects[cnum].conn_state != CNST_FREE) { httpd_close_conn(connects[cnum].hc); } if (connects[cnum].hc != NULL) { httpd_destroy_conn(connects[cnum].hc); httpd_free((void *)connects[cnum].hc); connects[cnum].hc = NULL; } } if (hs) { httpd_server *ths = hs; hs = NULL; if (ths->listen_fd != -1) { fdwatch_del_fd(fw, ths->listen_fd); } httpd_terminate(ths); } tmr_destroy(); httpd_free((void *)connects); }
void CLIENT_DESC::Destroy() { if (m_sock == INVALID_SOCKET) { return; } P2P_MANAGER::instance().UnregisterConnector(this); if (this == db_clientdesc) { CPartyManager::instance().DeleteAllParty(); CPartyManager::instance().DisablePCParty(); CGuildManager::instance().StopAllGuildWar(); DBManager::instance().StopAllBilling(); } fdwatch_del_fd(m_lpFdw, m_sock); sys_log(0, "SYSTEM: closing client socket. DESC #%d", m_sock); socket_close(m_sock); m_sock = INVALID_SOCKET; // Chain up to base class Destroy() DESC::Destroy(); }
void CPeerBase::Disconnect() { if (m_fd != INVALID_SOCKET) { fdwatch_del_fd(m_fdWatcher, m_fd); socket_close(m_fd); m_fd = INVALID_SOCKET; } }
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 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 void really_clear_connection( connecttab* c, struct timeval* tvP ) { stats_bytes += c->bytes_to_send; fdwatch_del_fd( c->hc->conn_fd ); httpd_close_conn( c->hc, tvP ); clear_throttles( c, tvP ); if ( c->linger_timer != (Timer*) 0 ) { tmr_cancel( c->linger_timer ); c->linger_timer = 0; } c->conn_state = CNST_FREE; --numconnects; }
static void really_clear_connection(struct connect_s *conn) { fdwatch_del_fd(fw, conn->hc->conn_fd); httpd_close_conn(conn->hc); if (conn->linger_timer != NULL) { tmr_cancel(conn->linger_timer); conn->linger_timer = 0; } /* Put the connection structure back on the free list */ conn->conn_state = CNST_FREE; conn->next = free_connections; free_connections = conn; }
void httpd_conn_sleep( httpd_conn *hc, int seconds ) { connecttab* c = hc->conn; ClientData client_data; if ( c->wakeup_timer != (Timer*) 0 ) { tmr_cancel( c->wakeup_timer ); c->wakeup_timer = 0; } fdwatch_del_fd( hc->conn_fd ); c->conn_state = CNST_SLEEPING; client_data.p = c; c->wakeup_timer = tmr_create( 0, httpd_conn_wakeup, client_data, seconds * 1000, 0 ); }
static void really_clear_connection( connecttab* c, struct timeval* tvP ) { stats_bytes += c->hc->bytes_sent; if ( c->conn_state != CNST_PAUSING && c->conn_state != CNST_SLEEPING ) fdwatch_del_fd( c->hc->conn_fd ); httpd_close_conn( c->hc, tvP ); if ( c->linger_timer != (Timer*) 0 ) { tmr_cancel( c->linger_timer ); c->linger_timer = 0; } c->conn_state = CNST_FREE; c->next_free_connect = first_free_connect; first_free_connect = c - connects; /* division by sizeof is implied */ --num_connects; }
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 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 ); }
static void handle_send( connecttab* c, struct timeval* tvP ) { size_t max_bytes; int sz, coast; ClientData client_data; time_t elapsed; httpd_conn* hc = c->hc; int tind; max_bytes = 1000000000L; /* Do we need to write the headers first? */ if ( hc->responselen == 0 ) { /* No, just write the file. */ sz = write( hc->conn_fd, &(hc->body_data[c->next_byte_index]), MIN( c->end_byte_index - c->next_byte_index, max_bytes ) ); } else { /* Yes. We'll combine headers and file into a single writev(), ** hoping that this generates a single packet. */ struct iovec iv[2]; iv[0].iov_base = hc->response; iv[0].iov_len = hc->responselen; iv[1].iov_base = &(hc->body_data[c->next_byte_index]); iv[1].iov_len = MIN( c->end_byte_index - c->next_byte_index, max_bytes ); sz = writev( hc->conn_fd, iv, 2 ); } if ( sz < 0 && errno == EINTR ) return; if ( sz == 0 || ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) ) { /* This shouldn't happen, but some kernels, e.g. ** SunOS 4.1.x, are broken and select() says that ** O_NDELAY sockets are always writable even when ** they're actually not. ** ** Current workaround is to block sending on this ** socket for a brief adaptively-tuned period. ** Fortunately we already have all the necessary ** blocking code, for use with throttling. */ c->wouldblock_delay += MIN_WOULDBLOCK_DELAY; c->conn_state = CNST_PAUSING; fdwatch_del_fd( hc->conn_fd ); client_data.p = c; c->wakeup_timer = tmr_create( tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 ); if ( c->wakeup_timer == (Timer*) 0 ) { return; } return; } if ( sz < 0 ) { /* Something went wrong, close this connection. */ clear_connection( c, tvP ); return; } /* Ok, we wrote something. */ c->active_at = tvP->tv_sec; /* Was this a headers + file writev()? */ if ( hc->responselen > 0 ) { /* Yes; did we write only part of the headers? */ if ( sz < hc->responselen ) { /* Yes; move the unwritten part to the front of the buffer. */ int newlen = hc->responselen - sz; (void) memmove( hc->response, &(hc->response[sz]), newlen ); hc->responselen = newlen; sz = 0; } else { /* Nope, we wrote the full headers, so adjust accordingly. */ sz -= hc->responselen; hc->responselen = 0; } } /* And update how much of the file we wrote. */ c->next_byte_index += sz; c->hc->bytes_sent += sz; /* Are we done? */ if ( c->next_byte_index >= c->end_byte_index ) { /* This connection is finished! */ finish_connection( c, tvP ); return; } /* Tune the (blockheaded) wouldblock delay. */ if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY ) c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY; /* (No check on min_limit here, that only controls connection startups.) */ }
static void handle_read(struct connect_s *conn, struct timeval *tv) { ClientData client_data; httpd_conn *hc = conn->hc; off_t actual; int sz; /* Is there room in our buffer to read more bytes? */ if (hc->read_idx >= hc->read_size) { if (hc->read_size > CONFIG_THTTPD_MAXREALLOC) { BADREQUEST("MAXREALLOC"); goto errout_with_400; } httpd_realloc_str(&hc->read_buf, &hc->read_size, hc->read_size + CONFIG_THTTPD_REALLOCINCR); } /* Read some more bytes */ sz = read(hc->conn_fd, &(hc->read_buf[hc->read_idx]), hc->read_size - hc->read_idx); if (sz == 0) { BADREQUEST("EOF"); goto errout_with_400; } if (sz < 0) { /* Ignore EINTR and EAGAIN. Also ignore EWOULDBLOCK. 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 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { return; } ndbg("read(fd=%d) failed: %d\n", hc->conn_fd, errno); BADREQUEST("read"); goto errout_with_400; } hc->read_idx += sz; conn->active_at = tv->tv_sec; /* Do we have a complete request yet? */ switch (httpd_got_request(hc)) { case GR_NO_REQUEST: return; case GR_BAD_REQUEST: BADREQUEST("httpd_got_request"); goto errout_with_400; } /* Yes. Try parsing and resolving it */ if (httpd_parse_request(hc) < 0) { goto errout_with_connection; } /* Start the connection going */ if (httpd_start_request(hc, tv) < 0) { /* Something went wrong. Close down the connection */ goto errout_with_connection; } /* Set up the file offsets to read */ conn->eof = false; if (hc->got_range) { conn->offset = hc->range_start; conn->end_offset = hc->range_end + 1; } else { conn->offset = 0; if (hc->bytes_to_send < 0) { conn->end_offset = 0; } else { conn->end_offset = hc->bytes_to_send; } } /* Check if it's already handled */ if (hc->file_fd < 0) { /* No file descriptor means someone else is handling it */ conn->offset = hc->bytes_sent; goto errout_with_connection; } if (conn->offset >= conn->end_offset) { /* There's nothing to send */ goto errout_with_connection; } /* Seek to the offset of the next byte to send */ actual = lseek(hc->file_fd, conn->offset, SEEK_SET); if (actual != conn->offset) { ndbg("fseek to %d failed: offset=%d errno=%d\n", conn->offset, actual, errno); BADREQUEST("lseek"); goto errout_with_400; } /* We have a valid connection and a file to send to it */ conn->conn_state = CNST_SENDING; client_data.p = conn; fdwatch_del_fd(fw, hc->conn_fd); return; errout_with_400: BADREQUEST("errout"); httpd_send_err(hc, 400, httpd_err400title, "", httpd_err400form, ""); errout_with_connection: finish_connection(conn, tv); return; }
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 void handle_send( connecttab* c, struct timeval* tvP ) { int sz, coast; ClientData client_data; time_t elapsed; httpd_conn* hc = c->hc; /* Do we need to write the headers first? */ if ( hc->responselen == 0 ) { /* No, just write the file. */ sz = write( hc->conn_fd, &(hc->file_address[c->bytes_sent]), MIN( c->bytes_to_send - c->bytes_sent, c->limit ) ); } else { /* Yes. We'll combine headers and file into a single writev(), ** hoping that this generates a single packet. */ struct iovec iv[2]; iv[0].iov_base = hc->response; iv[0].iov_len = hc->responselen; iv[1].iov_base = &(hc->file_address[c->bytes_sent]); iv[1].iov_len = MIN( c->bytes_to_send - c->bytes_sent, c->limit ); sz = writev( hc->conn_fd, iv, 2 ); } if ( sz == 0 || ( sz < 0 && ( errno == EWOULDBLOCK || errno == EAGAIN ) ) ) { /* This shouldn't happen, but some kernels, e.g. ** SunOS 4.1.x, are broken and select() says that ** O_NDELAY sockets are always writable even when ** they're actually not. ** ** Current workaround is to block sending on this ** socket for a brief adaptively-tuned period. ** Fortunately we already have all the necessary ** blocking code, for use with throttling. */ c->wouldblock_delay += MIN_WOULDBLOCK_DELAY; c->conn_state = CNST_PAUSING; fdwatch_del_fd( hc->conn_fd ); client_data.p = c; c->wakeup_timer = tmr_create( tvP, wakeup_connection, client_data, c->wouldblock_delay, 0 ); if ( c->wakeup_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" ); exit( 1 ); } return; } if ( sz < 0 ) { /* Something went wrong, close this connection. ** ** If it's just an EPIPE, don't bother logging, that ** just means the client hung up on us. ** ** On some systems, write() occasionally gives an EINVAL. ** Dunno why, something to do with the socket going ** bad. Anyway, we don't log those either. ** ** And ECONNRESET isn't interesting either. */ if ( errno != EPIPE && errno != EINVAL && errno != ECONNRESET ) syslog( LOG_ERR, "write - %m sending %.80s", hc->encodedurl ); clear_connection( c, tvP ); return; } /* Ok, we wrote something. */ tmr_reset( tvP, c->idle_send_timer ); /* Was this a headers + file writev()? */ if ( hc->responselen > 0 ) { /* Yes; did we write only part of the headers? */ if ( sz < hc->responselen ) { /* Yes; move the unwritten part to the front of the buffer. */ int newlen = hc->responselen - sz; (void) memcpy( hc->response, &(hc->response[sz]), newlen ); hc->responselen = newlen; sz = 0; } else { /* Nope, we wrote the full headers, so adjust accordingly. */ sz -= hc->responselen; hc->responselen = 0; } } /* And update how much of the file we wrote. */ c->bytes_sent += sz; c->hc->bytes_sent += sz; /* Are we done? */ if ( c->bytes_sent >= c->bytes_to_send ) { /* This conection is finished! */ clear_connection( c, tvP ); return; } /* Tune the (blockheaded) wouldblock delay. */ if ( c->wouldblock_delay > MIN_WOULDBLOCK_DELAY ) c->wouldblock_delay -= MIN_WOULDBLOCK_DELAY; /* If we're throttling, check if we're sending too fast. */ if ( c->limit != THROTTLE_NOLIMIT ) { elapsed = tvP->tv_sec - c->started_at; if ( elapsed == 0 || c->hc->bytes_sent / elapsed > c->limit ) { c->conn_state = CNST_PAUSING; fdwatch_del_fd( hc->conn_fd ); /* When should we send the next c->limit bytes ** to get back on schedule? If less than a second ** (integer math rounding), use 1/8 second. */ coast = ( c->hc->bytes_sent + c->limit ) / c->limit - elapsed; client_data.p = c; c->wakeup_timer = tmr_create( tvP, wakeup_connection, client_data, coast ? ( coast * 1000L ) : 125L, 0 ); if ( c->wakeup_timer == (Timer*) 0 ) { syslog( LOG_CRIT, "tmr_create(wakeup_connection) failed" ); exit( 1 ); } } } }