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; }
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); }
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 ); }
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; }