コード例 #1
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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 );
    }
コード例 #2
0
ファイル: desc.cpp プロジェクト: adi97ida/Server
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();
}
コード例 #3
0
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);
}
コード例 #4
0
ファイル: desc_client.cpp プロジェクト: cCorax2/Source_code
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();
}
コード例 #5
0
ファイル: PeerBase.cpp プロジェクト: adi97ida/Server
void CPeerBase::Disconnect()
{
	if (m_fd != INVALID_SOCKET)
	{
		fdwatch_del_fd(m_fdWatcher, m_fd);

		socket_close(m_fd);
		m_fd = INVALID_SOCKET;
	}
}
コード例 #6
0
ファイル: thttpd.c プロジェクト: tisrael/thttpd-2.21b
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 );
    }
コード例 #7
0
ファイル: thttpd.c プロジェクト: hll4fork/nuttx-apps
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);
}
コード例 #8
0
ファイル: thttpd.c プロジェクト: tisrael/thttpd-2.21b
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;
    }
コード例 #9
0
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;
}
コード例 #10
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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 );
    }
コード例 #11
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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;
    }
コード例 #12
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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 );
    }
コード例 #13
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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 );
    }
コード例 #14
0
ファイル: thttpd.c プロジェクト: wangxuemin/coding
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.) */
    }
コード例 #15
0
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;
}
コード例 #16
0
ファイル: thttpd.c プロジェクト: tisrael/thttpd-2.21b
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 );
    }
コード例 #17
0
ファイル: thttpd.c プロジェクト: tisrael/thttpd-2.21b
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 );
		}
	    }
	}
    }