static void shut_down(void) { int cnum; for (cnum = 0; cnum < AVAILABLE_FDS; ++cnum) { if (connects[cnum].conn_state != CNST_FREE) { httpd_close_conn(connects[cnum].hc); } if (connects[cnum].hc != NULL) { httpd_destroy_conn(connects[cnum].hc); httpd_free((void *)connects[cnum].hc); connects[cnum].hc = NULL; } } if (hs) { httpd_server *ths = hs; hs = NULL; if (ths->listen_fd != -1) { fdwatch_del_fd(fw, ths->listen_fd); } httpd_terminate(ths); } tmr_destroy(); httpd_free((void *)connects); }
static void * httpd_session_main(void *data) #endif { struct hrequest_t *req; conndata_t *conn; httpd_conn_t *rconn; hservice_t *service; herror_t status; struct timeval start, end, duration; int done; if (gettimeofday(&start, NULL) == -1) log_error("gettimeofday failed (%s)", strerror(errno)); conn = (conndata_t *) data; log_verbose("starting new httpd session on socket %d", conn->sock); rconn = httpd_new(&(conn->sock)); done = 0; while (!done) { log_verbose("starting HTTP request on socket %d (%p)", conn->sock, conn->sock.sock); if ((status = hrequest_new_from_socket(&(conn->sock), &req)) != H_OK) { int code; switch ((code = herror_code(status))) { case HSSL_ERROR_SSLCLOSE: case HSOCKET_ERROR_RECEIVE: log_error("hrequest_new_from_socket failed (%s)", herror_message(status)); break; default: httpd_send_bad_request(rconn, herror_message(status)); break; } herror_release(status); done = 1; } else { char *conn_str; _httpd_request_print(req); conn_str = hpairnode_get_ignore_case(req->header, HEADER_CONNECTION); if (conn_str && strncasecmp(conn_str, "close", 6) == 0) done = 1; if (!done) done = req->version == HTTP_1_0 ? 1 : 0; if ((service = httpd_find_service(req->path))) { log_verbose("service '%s' for '%s' found", service->context, req->path); if (service->status == NHTTPD_SERVICE_UP) { pthread_rwlock_wrlock(&(service->statistics->lock)); service->statistics->requests++; pthread_rwlock_unlock(&(service->statistics->lock)); if (_httpd_authenticate_request(req, service->auth)) { if (service->func != NULL) { service->func(rconn, req); if (gettimeofday(&end, NULL) == -1) log_error("gettimeofday failed (%s)", strerror(errno)); timersub(&end, &start, &duration); pthread_rwlock_wrlock(&(service->statistics->lock)); service->statistics->bytes_received += rconn->sock->bytes_received; service->statistics->bytes_transmitted += rconn->sock->bytes_transmitted; timeradd(&(service->statistics->time), &duration, &(service->statistics->time)); pthread_rwlock_unlock(&(service->statistics->lock)); if (rconn->out && rconn->out->type == HTTP_TRANSFER_CONNECTION_CLOSE) { log_verbose("Connection close requested"); done = 1; } } else { char buffer[256]; snprintf(buffer, 256, "service '%s' is not registered properly (service function is NULL)", req->path); log_verbose("%s", buffer); httpd_send_not_implemented(rconn, buffer); } } else { httpd_send_unauthorized(rconn, req->path); done = 1; } } else { char buffer[256]; sprintf(buffer, "service for '%s' is disabled", req->path); log_verbose("%s", buffer); httpd_send_internal_error(rconn, buffer); } } else { char buffer[256]; sprintf(buffer, "no service for '%s' found", req->path); log_verbose("%s", buffer); httpd_send_not_implemented(rconn, buffer); done = 1; } hrequest_free(req); } } httpd_free(rconn); hsocket_close(&(conn->sock)); #ifdef WIN32 CloseHandle((HANDLE) conn->tid); #else pthread_attr_destroy(&(conn->attr)); #endif conn->flag = CONNECTION_FREE; #ifdef WIN32 _endthread(); return 0; #else /* pthread_exits automagically */ return NULL; #endif }
int http_get(struct httpd * httpd, struct httpctl * ctl) { int (* cgi)(struct tcp_pcb * tp); char buf[128]; // int content_type; // int content_len; // char * opt; char * ext; struct stat sb; int type; int hash; int size; int ret; int fd; int n; strcpy(buf, httpd->root); strcat(buf, ctl->uri); // for (opt = buf; (*opt); opt++) { // if (*opt == '?') { // *opt++ = '\0'; // break; // } // } DBG(DBG_INFO, "path=%s", buf); if ((ret = stat(buf, &sb)) < 0) { DBG(DBG_ERROR, "404 File Not Found"); httpd_404(ctl->tp); return ret; } if (S_ISDIR(sb.st_mode)) { DBG(DBG_INFO, "is a directory"); strcat(buf, "/"); strcat(buf, httpd_page_default); if ((ret = stat(buf, &sb)) < 0) { strcpy(buf, httpd->root); strcat(buf, ctl->uri); return httpd_dirlist(httpd, ctl); } } if (!S_ISREG(sb.st_mode)) { DBG(DBG_ERROR, "403 Forbidden"); httpd_403(ctl->tp); return -1; } if ((fd = open(buf, O_RDONLY)) < 0) { DBG(DBG_ERROR, "404 File Not Found"); httpd_404(ctl->tp); return -1; } ret = 0; if ((ext = strrchr(buf, '.')) != NULL) { DBG(DBG_INFO, "extension=%s", ext); /* skip the '.' */ ext++; hash = mk_ext_hash(ext); switch (hash) { case EXT_CGI: DBG(DBG_INFO, "cgi"); goto dynamic_cgi; case EXT_TXT: DBG(DBG_INFO, "text"); type = text_plain; break; case EXT_JPEG: case EXT_JPG: DBG(DBG_INFO, "jpeg"); type = image_jpeg; break; case EXT_ICO: DBG(DBG_INFO, "ico"); case EXT_GIF: DBG(DBG_INFO, "gif"); type = image_gif; break; case EXT_PNG: DBG(DBG_INFO, "png"); type = image_png; break; case EXT_JS: DBG(DBG_INFO, "js"); type = application_x_javascript; break; case EXT_HTML: case EXT_HTM: DBG(DBG_INFO, "html"); default: type = text_html; break; } httpd_200(ctl->tp, type); while ((n = read(fd, buf, 128)) > 0) { if (tcp_send(ctl->tp, buf, n, 0) <= 0) { DBG(DBG_ERROR, "tcp_send()"); ret = -1; break; } } } else { dynamic_cgi: size = lseek(fd, 0, SEEK_END); DBG(DBG_TRACE, "size=%d", size); cgi = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); DBG(DBG_TRACE, "cgi=%p", cgi); ret = cgi(ctl->tp); } close(fd); #if 0 DBG(DBG_INFO, "file uid=%d", info.fi_uid); if (info.fi_uid < __httpd->uid) { unsigned int uid; DBG(DBG_INFO, "info.fi_uid=%d < httpd->uid=%d, auth required", info.fi_uid, __httpd->uid); uid = httpd_auth(__http->httpd, __http->usr, __http->pwd); if (info.fi_uid < uid) { DBG(DBG_ERROR, "401 Unauthorized, uid=%d", uid); httpd_401_auth(__tp); return -1; } } content_type = __http->ctype; content_len = __http->ctlen; if (info.fi_mime != _code_) { /* detach the PCB */ tcp_attach(__tp, NULL, __httpd); /* release the control structure */ httpd_free(__httpd, __http); httpd_send(__tp, info.fi_mime, (char *)info.fi_data, info.fi_size); tcp_close(__tp); return 0; } /* dynamic cgi */ DBG(DBG_INFO, "dynamic page"); cgi_call = (httpd_cgi_t)info.fi_data; /* reuse the allocated buffer */ cgi = (struct cgistate *)__http; /* XXX: */ cgi->httpd = __httpd; cgi->callback = NULL; /* attach the PCB to the CGI handler */ tcp_attach(__tp, (tcp_callback_t)httpd_cgi_handler, cgi); if (cgi_call(__tp, opt, content_type, content_len) < 0) { /* close the tcp pcb */ tcp_close(__tp); } else { /* if the CGI is still detached, close-it */ if (cgi->callback == NULL) tcp_close(__tp); } #endif return ret; }
int main( int argc, char **argv ) { // Read any command line arguments from our friend the user. arguments(argc, argv); // Catch some signals so can exit cleanly signal(SIGINT, exit_interrupt); #ifndef WIN32 signal(SIGHUP, exit_interrupt); signal(SIGTERM, exit_interrupt); signal(SIGPIPE, SIG_IGN); if (debug_on) setvbuf(stdout, NULL, _IONBF, 0); #endif printf("%s - Jorgen Lundman v%s %s %s\n\n", argv ? argv[0] : "llink", VERSION, VERSION_STRING, #if WITH_DVDREAD "(libdvdread)" #else #if HAVE_CLINKC "(libdvdnav, ClinkC)" #else "(libdvdnav)" #endif #endif ); lion_buffersize(conf_buffersize); //lion_buffersize(2352); if (lion_init()) { printf("Failed to initialize lion/networking\n"); exit(-1); } debugf("\n"); // Read configuration file, if any // Warning, calls lion_poll until done. conf_init(); debugf("[main] initialising...\n"); // Warning, calls lion_poll until done. mime_init(); // Warning, calls lion_poll until done. skin_init(); ssdp_init(); httpd_init(); request_init(); root_init(); llrar_init(); visited_init(); cgicmd_init(); #ifdef EXTERNAL external_init(); #endif printf("[main] ready!\n"); // Background? #ifndef WIN32 if (!foreground) { if (fork()) exit(0); setsid(); if (conf_pidfile) { FILE *fd; if ((fd = fopen(conf_pidfile, "w"))) { fprintf(fd, "%u\r\n", getpid()); fclose(fd); } } } #endif cupnp_init(); // Scan for media if (conf_xmlscan) { signal(SIGINT, SIG_DFL); xmlscan_run(); do_exit = 1; } query_init(); #ifdef WIN32 SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); #endif // The main loop while ( !do_exit ) { // Was 250,0 - we should probably let users control this in // conf settings. if (lion_poll(0, 1)<0) do_exit=1; request_events(); #ifdef EXTERNAL external_resume(); #endif } printf("\n[main] releasing resources...\n"); query_free(); cupnp_free(); #ifdef EXTERNAL external_free(); #endif root_free(); cgicmd_free(); visited_free(); llrar_free(); request_free(); httpd_free(); ssdp_free(); skin_free(); mime_free(); conf_free(); #ifndef WIN32 // Crashed when releasing spawned processes, until i can fix: lion_free(); #endif debugf("[main] done.\n"); return 0; }