static inline void cleanup_web_clients(void) { struct web_client *w; for (w = web_clients; w;) { if (w->obsolete) { debug(D_WEB_CLIENT, "%llu: Removing client.", w->id); // pthread_cancel(w->thread); // pthread_join(w->thread, NULL); w = web_client_free(w); #ifdef NETDATA_INTERNAL_CHECKS log_allocations(); #endif } else w = w->next; } }
void *socket_listen_main_single_threaded(void *ptr) { (void)ptr; web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED; info("Single threaded WEB SERVER thread created with task id %d", gettid()); struct web_client *w; int retval, failures = 0; if(ptr) { ; } if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) error("Cannot set pthread cancel type to DEFERRED."); if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) error("Cannot set pthread cancel state to ENABLE."); if(listen_fd < 0 || listen_fd >= FD_SETSIZE) fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd); int i; for(i = 0; i < FD_SETSIZE ; i++) single_threaded_clients[i] = NULL; fd_set ifds, ofds, efds, rifds, rofds, refds; FD_ZERO (&ifds); FD_ZERO (&ofds); FD_ZERO (&efds); FD_SET(listen_fd, &ifds); FD_SET(listen_fd, &efds); int fdmax = listen_fd; for(;;) { debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (listen fd = %d, fdmax = %d)...", listen_fd, fdmax); struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; rifds = ifds; rofds = ofds; refds = efds; retval = select(fdmax+1, &rifds, &rofds, &refds, &tv); if(unlikely(retval == -1)) { debug(D_WEB_CLIENT, "LISTENER: select() failed."); failures++; if(failures > 10) { if(global_statistics.connected_clients) { error("REMOVING ALL %lu WEB CLIENTS !", global_statistics.connected_clients); while (web_clients) { single_threaded_unlink_client(web_clients, &ifds, &ofds, &efds); web_client_free(web_clients); } } error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd); close(listen_fd); listen_fd = -1; sleep(5); create_listen_socket(); if(listen_fd < 0 || listen_fd >= FD_SETSIZE) fatal("Cannot listen for web clients (connected clients %llu).", global_statistics.connected_clients); FD_ZERO (&ifds); FD_ZERO (&ofds); FD_ZERO (&efds); FD_SET(listen_fd, &ifds); FD_SET(listen_fd, &efds); failures = 0; } } else if(likely(retval)) { failures = 0; debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something."); if(FD_ISSET(listen_fd, &rifds)) { debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection."); w = web_client_create(listen_fd); if(single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) { web_client_free(w); } } for(i = 0 ; i <= fdmax ; i++) { if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds))) continue; w = single_threaded_clients[i]; if(unlikely(!w)) continue; if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) { web_client_free(w); continue; } if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) { web_client_free(w); continue; } if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) { if (unlikely(web_client_receive(w) < 0)) { web_client_free(w); continue; } if (w->mode != WEB_CLIENT_MODE_FILECOPY) { debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id); web_client_process(w); } } if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) { if (unlikely(web_client_send(w) < 0)) { debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id); web_client_free(w); continue; } } if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) { web_client_free(w); } } } else { debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout."); #ifdef NETDATA_INTERNAL_CHECKS log_allocations(); #endif } } debug(D_WEB_CLIENT, "LISTENER: exit!"); close(listen_fd); listen_fd = -1; return NULL; }
void *socket_listen_main_multi_threaded(void *ptr) { (void)ptr; web_server_mode = WEB_SERVER_MODE_MULTI_THREADED; info("Multi-threaded WEB SERVER thread created with task id %d", gettid()); struct web_client *w; int retval, failures = 0, counter = 0; if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) error("Cannot set pthread cancel type to DEFERRED."); if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) error("Cannot set pthread cancel state to ENABLE."); if(listen_fd < 0) fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fd); for(;;) { struct pollfd fd = { .fd = listen_fd, .events = POLLIN, .revents = 0 }; int timeout = 10 * 1000; // debug(D_WEB_CLIENT, "LISTENER: Waiting..."); retval = poll(&fd, 1, timeout); if(unlikely(retval == -1)) { debug(D_WEB_CLIENT, "LISTENER: poll() failed."); failures++; if(failures > 10) { error("LISTENER: our listen port %d seems dead. Re-opening it.", listen_fd); close(listen_fd); listen_fd = -1; sleep(5); create_listen_socket(); if(listen_fd < 0) fatal("Cannot listen for web clients (connected clients %llu).", global_statistics.connected_clients); failures = 0; } continue; } else if(likely(retval)) { // check for new incoming connections if(fd.revents & POLLIN || fd.revents & POLLPRI) { w = web_client_create(listen_fd); if(unlikely(!w)) { // no need for error log - web_client_create already logged the error continue; } if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) { error("%llu: failed to create new thread for web client."); w->obsolete = 1; } else if(pthread_detach(w->thread) != 0) { error("%llu: Cannot request detach of newly created web client thread.", w->id); w->obsolete = 1; } } else { failures++; debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything."); continue; } } else { debug(D_WEB_CLIENT, "LISTENER: select() timeout."); counter = CLEANUP_EVERY_EVENTS; } // cleanup unused clients counter++; if(counter > CLEANUP_EVERY_EVENTS) { counter = 0; for (w = web_clients; w;) { if (w->obsolete) { debug(D_WEB_CLIENT, "%llu: Removing client.", w->id); // pthread_cancel(w->thread); // pthread_join(w->thread, NULL); w = web_client_free(w); #ifdef NETDATA_INTERNAL_CHECKS log_allocations(); #endif } else w = w->next; } } failures = 0; } debug(D_WEB_CLIENT, "LISTENER: exit!"); close(listen_fd); listen_fd = -1; return NULL; } struct web_client *single_threaded_clients[FD_SETSIZE]; static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) { if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send))) return 1; if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) { error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE); return 1; } FD_SET(w->ifd, efds); if(unlikely(*max < w->ifd)) *max = w->ifd; if(unlikely(w->ifd != w->ofd)) { if(*max < w->ofd) *max = w->ofd; FD_SET(w->ofd, efds); } if(w->wait_receive) FD_SET(w->ifd, ifds); if(w->wait_send) FD_SET(w->ofd, ofds); single_threaded_clients[w->ifd] = w; single_threaded_clients[w->ofd] = w; return 0; } static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) { FD_CLR(w->ifd, efds); if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds); if(w->wait_receive) FD_CLR(w->ifd, ifds); if(w->wait_send) FD_CLR(w->ofd, ofds); single_threaded_clients[w->ifd] = NULL; single_threaded_clients[w->ofd] = NULL; if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send))) return 1; return 0; }
void *socket_listen_main_single_threaded(void *ptr) { (void)ptr; web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED; info("Single-threaded WEB SERVER thread created with task id %d", gettid()); struct web_client *w; int retval; if(ptr) { ; } if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) error("Cannot set pthread cancel type to DEFERRED."); if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) error("Cannot set pthread cancel state to ENABLE."); int i; if(!listen_fds_count) fatal("LISTENER: no listen sockets available."); for(i = 0; i < FD_SETSIZE ; i++) single_threaded_clients[i] = NULL; fd_set ifds, ofds, efds, rifds, rofds, refds; FD_ZERO (&ifds); FD_ZERO (&ofds); FD_ZERO (&efds); int fdmax = 0; for(i = 0; i < listen_fds_count ; i++) { if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE) fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]); info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN"); FD_SET(listen_fds[i], &ifds); FD_SET(listen_fds[i], &efds); if(fdmax < listen_fds[i]) fdmax = listen_fds[i]; } for(;;) { debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax); struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; rifds = ifds; rofds = ofds; refds = efds; retval = select(fdmax+1, &rifds, &rofds, &refds, &tv); if(unlikely(retval == -1)) { error("LISTENER: select() failed."); continue; } else if(likely(retval)) { debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something."); for(i = 0; i < listen_fds_count ; i++) { if (FD_ISSET(listen_fds[i], &rifds)) { debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection."); w = web_client_create(listen_fds[i]); if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) { web_client_free(w); } } } for(i = 0 ; i <= fdmax ; i++) { if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds))) continue; w = single_threaded_clients[i]; if(unlikely(!w)) continue; if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) { web_client_free(w); continue; } if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) { web_client_free(w); continue; } if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) { if (unlikely(web_client_receive(w) < 0)) { web_client_free(w); continue; } if (w->mode != WEB_CLIENT_MODE_FILECOPY) { debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id); web_client_process(w); } } if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) { if (unlikely(web_client_send(w) < 0)) { debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id); web_client_free(w); continue; } } if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) { web_client_free(w); } } } else { debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout."); #ifdef NETDATA_INTERNAL_CHECKS log_allocations(); #endif } } debug(D_WEB_CLIENT, "LISTENER: exit!"); close_listen_sockets(); return NULL; }
void *socket_listen_main(void *ptr) { if(ptr) { ; } info("WEB SERVER thread created with task id %d", gettid()); struct web_client *w; struct timeval tv; int retval; if(ptr) { ; } if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) error("Cannot set pthread cancel type to DEFERRED."); if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) error("Cannot set pthread cancel state to ENABLE."); web_client_timeout = (int) config_get_number("global", "disconnect idle web clients after seconds", DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS); web_enable_gzip = config_get_boolean("global", "enable web responses gzip compression", web_enable_gzip); if(listen_fd < 0) fatal("LISTENER: Listen socket is not ready."); fd_set ifds, ofds, efds; int fdmax = listen_fd; FD_ZERO (&ifds); FD_ZERO (&ofds); FD_ZERO (&efds); for(;;) { tv.tv_sec = 0; tv.tv_usec = 200000; if(listen_fd >= 0) { FD_SET(listen_fd, &ifds); FD_SET(listen_fd, &efds); } // debug(D_WEB_CLIENT, "LISTENER: Waiting..."); retval = select(fdmax+1, &ifds, &ofds, &efds, &tv); if(retval == -1) { error("LISTENER: select() failed."); continue; } else if(retval) { // check for new incoming connections if(FD_ISSET(listen_fd, &ifds)) { w = web_client_create(listen_fd); if(unlikely(!w)) { // no need for error log - web_client_create already logged the error continue; } if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) { error("%llu: failed to create new thread for web client."); w->obsolete = 1; } else if(pthread_detach(w->thread) != 0) { error("%llu: Cannot request detach of newly created web client thread.", w->id); w->obsolete = 1; } } else debug(D_WEB_CLIENT, "LISTENER: select() didn't do anything."); } //else { // debug(D_WEB_CLIENT, "LISTENER: select() timeout."); //} // cleanup unused clients for(w = web_clients; w ; w = w?w->next:NULL) { if(w->obsolete) { debug(D_WEB_CLIENT, "%llu: Removing client.", w->id); // pthread_join(w->thread, NULL); w = web_client_free(w); log_allocations(); } } } error("LISTENER: exit!"); if(listen_fd >= 0) close(listen_fd); exit(2); return NULL; }