Ejemplo n.º 1
0
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;
    }
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
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)));
	}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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 );
    }
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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 );
	}
    }
Ejemplo n.º 11
0
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);
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
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 );
    }
Ejemplo n.º 14
0
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);
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
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 );
    }
Ejemplo n.º 17
0
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);
}
Ejemplo n.º 18
0
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;
	}
    }
Ejemplo n.º 19
0
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);
}
Ejemplo n.º 20
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 );
    }
Ejemplo n.º 21
0
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);
    }
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 23
0
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 );
    }
Ejemplo n.º 24
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;
    }
Ejemplo n.º 25
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;
	}
    }