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