static void idle(ClientData client_data, struct timeval *nowP)
{
  int cnum;
  struct connect_s *conn;

  for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum)
    {
      conn = &connects[cnum];
      switch (conn->conn_state)
        {
        case CNST_READING:
          if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_READ_LIMIT_SEC)
            {
              ndbg("%s connection timed out reading\n", httpd_ntoa(&conn->hc->client_addr));
              httpd_send_err(conn->hc, 408, httpd_err408title, "",
                             httpd_err408form, "");
              finish_connection(conn, nowP);
            }
          break;

        case CNST_SENDING:
          if (nowP->tv_sec - conn->active_at >= CONFIG_THTTPD_IDLE_SEND_LIMIT_SEC)
            {
              ndbg("%s connection timed out sending\n", httpd_ntoa(&conn->hc->client_addr));
              clear_connection(conn, nowP);
            }
          break;
        }
    }
}
Beispiel #2
0
static void
idle( ClientData client_data, struct timeval* nowP )
    {
    int cnum;
    connecttab* c;

    for ( cnum = 0; cnum < max_connects; ++cnum )
	{
	c = &connects[cnum];
	switch ( c->conn_state )
	    {
	    case CNST_READING:
	    if ( nowP->tv_sec - c->active_at >= IDLE_READ_TIMELIMIT )
		{
		httpd_send_err(
		    c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
		finish_connection( c, nowP );
		}
	    break;
	    case CNST_SENDING:
	    case CNST_PAUSING:
	    if ( nowP->tv_sec - c->active_at >= IDLE_SEND_TIMELIMIT )
		{
		clear_connection( c, nowP );
		}
	    break;
	    case CNST_SLEEPING:;
	    }
	}
    }
Beispiel #3
0
int32 PoorManServer::_Listener(void* data)
{
	PRINT(("The listener thread is working.\n"));
	int retval;
	thread_id tid;
	httpd_conn* hc;
	PoorManServer* s = static_cast<PoorManServer*>(data);
	
	while (s->fIsRunning) {
		hc = new httpd_conn;
		hc->initialized = 0;
		PRINT(("calling httpd_get_conn()\n"));
		retval = //accept(), blocked here
			httpd_get_conn(s->fHttpdServer, s->fHttpdServer->listen4_fd, hc);
		switch (retval) {
			case GC_OK:
				break;
			case GC_FAIL:
				httpd_destroy_conn(hc);
				delete hc;
				s->fIsRunning = false;
				return -1;
			case GC_NO_MORE:
				//should not happen, since we have a blocking socket
				httpd_destroy_conn(hc);
				continue;
				break;
			default: 
				//shouldn't happen
				continue;
				break;
		}
		
		if (s->fCurConns > s->fMaxConns) {
			httpd_send_err(hc, 503,
				httpd_err503title, (char *)"", httpd_err503form, (char *)"");
			httpd_write_response(hc);
			continue;
		}
		
		tid = spawn_thread(
			PoorManServer::_Worker,
			"www connection",
			B_NORMAL_PRIORITY,
			static_cast<void*>(s)
		);
		if (tid < B_OK) {
			continue;
		}
		/*We don't check the return code here.
		 *As we can't kill a thread that doesn't receive the
		 *httpd_conn, we simply let it die itself.
		 */
		send_data(tid, 512, &hc, sizeof(httpd_conn*));
		atomic_add(&s->fCurConns, 1);
		resume_thread(tid);
	}//while
	return 0;
}
Beispiel #4
0
static void
idle_read_connection( ClientData client_data, struct timeval* nowP )
    {
    connecttab* c;

    c = (connecttab*) client_data.p;
    c->idle_read_timer = (Timer*) 0;
    if ( c->conn_state != CNST_FREE )
	{
	syslog( LOG_INFO,
	    "%.80s connection timed out reading",
	    httpd_ntoa( &c->hc->client_addr ) );
	httpd_send_err( c->hc, 408, httpd_err408title, "", httpd_err408form, "" );
	clear_connection( c, nowP );
	}
    }
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;
}
Beispiel #6
0
static void
handle_read( connecttab* c, struct timeval* tvP )
    {
    int sz;
    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, "" );
	    finish_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 );
    if ( sz == 0 )
	{
	httpd_send_err( hc, 400, httpd_err400title, "", httpd_err400form, "" );
	finish_connection( c, tvP );
	return;
	}
    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;
	httpd_send_err(
	    hc, 400, httpd_err400title, "", httpd_err400form, "" );
	finish_connection( c, tvP );
	return;
	}
    hc->read_idx += sz;
    c->active_at = tvP->tv_sec;

    /* 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, "" );
	finish_connection( c, tvP );
	return;
	}

    /* Yes.  Try parsing and resolving it. */
    if ( httpd_parse_request( hc ) < 0 )
	{
	finish_connection( c, tvP );
	return;
	}

    /* Start the connection going. */
    if ( httpd_start_request( hc, tvP ) < 0 )
	{
	/* Something went wrong.  Close down the connection. */
	finish_connection( c, tvP );
	return;
	}

    if ( c->conn_state == CNST_SLEEPING )
        {
        return;
        }
    handle_read_2( c, tvP );
    }
Beispiel #7
0
int32 PoorManServer::_Worker(void* data)
{
	static const struct timeval kTimeVal = {60, 0};
	PoorManServer* s = static_cast<PoorManServer*>(data);
	httpd_conn* hc;
	int retval;
	
	if (has_data(find_thread(NULL))) {
		thread_id sender;
		if (receive_data(&sender, &hc, sizeof(httpd_conn*)) != 512)
			goto cleanup;
	} else {
		// No need to go throught the whole cleanup, as we haven't open
		// nor allocated ht yet.
		atomic_add(&s->fCurConns, -1);
		return 0;
	}
	
	PRINT(("A worker thread starts to work.\n"));

	setsockopt(hc->conn_fd, SOL_SOCKET, SO_RCVTIMEO, &kTimeVal,
		sizeof(struct timeval));
	retval = recv(
		hc->conn_fd,
		&(hc->read_buf[hc->read_idx]),
		hc->read_size - hc->read_idx,
		0
	);
	if (retval < 0)
		goto cleanup;

	hc->read_idx += retval;
	switch(httpd_got_request(hc)) {
		case GR_GOT_REQUEST:
			break;
		case GR_BAD_REQUEST:
			httpd_send_err(hc, 400,
				httpd_err400title, (char *)"", httpd_err400form, (char *)"");
			httpd_write_response(hc);//fall through
		case GR_NO_REQUEST: //fall through
		default: //won't happen
			goto cleanup;
			break;
	}
	
	if (httpd_parse_request(hc) < 0) {
		httpd_write_response(hc);
		goto cleanup;
	}
	
	retval = httpd_start_request(hc, (struct timeval*)0);
	if (retval < 0) {
		httpd_write_response(hc);
		goto cleanup;
	}
	
	/*true means the connection is already handled
	 *by the directory index generator in httpd_start_request().
	 */
	if (hc->file_address == (char*) 0) {
		static_cast<PoorManApplication*>(be_app)->GetPoorManWindow()->SetHits(
			static_cast<PoorManApplication*>(be_app)->GetPoorManWindow()->GetHits() + 1
		);
		hc->conn_fd = -1;
		goto cleanup;
	}
	
	switch (hc->method) {
		case METHOD_GET:
			s->_HandleGet(hc);
			break;
		case METHOD_HEAD:
			s->_HandleHead(hc);
			break;
		case METHOD_POST:
			s->_HandlePost(hc);
			break;
	}
	
cleanup: ;
	httpd_close_conn(hc, (struct timeval*)0);
	httpd_destroy_conn(hc);
	
	delete hc;
	atomic_add(&s->fCurConns, -1);
	return 0;
}
Beispiel #8
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 );
    }