示例#1
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;
}
示例#2
0
static void
finish_connection( connecttab* c, struct timeval* tvP )
    {
    /* If we haven't actually sent the buffered response yet, do so now. */
    httpd_write_response( c->hc );

    /* And clear. */
    clear_connection( c, tvP );
    }
static void finish_connection(struct connect_s *conn, struct timeval *tv)
{
  /* If we haven't actually sent the buffered response yet, do so now */

  httpd_write_response(conn->hc);

  /* And clear */

  clear_connection(conn, tv);
}
示例#4
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 );
    }
示例#5
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;
}