void reload_cmd(sock_t fd, char *options, unsigned int nb_options) { char *msg; if (get_active_threads_size() > 0) { msg = "Threads still active, cannot reload"; proxenet_write(fd, (void*)msg, strlen(msg)); return; } proxy_state = SLEEPING; proxenet_destroy_plugins_vm(); proxenet_delete_list_plugins(); if( proxenet_initialize_plugins_list() < 0) { msg = "Failed to reinitilize plugins"; proxenet_write(fd, (void*)msg, strlen(msg)); proxy_state = INACTIVE; return; } proxenet_initialize_plugins(); proxy_state = ACTIVE; msg = "Plugins list successfully reloaded\n"; proxenet_write(fd, (void*)msg, strlen(msg)); return; }
void xloop(sock_t sock, sock_t ctl_sock) { fd_set sock_set; int retcode; pthread_attr_t pattr; int tid; sock_t conn; sigset_t curmask, oldmask; sock_t ctl_cli_sock = -1; /* prepare threads */ proxenet_xzero(threads, sizeof(pthread_t) * MAX_THREADS); if (pthread_attr_init(&pattr)) { xlog(LOG_ERROR, "%s\n", "Failed to pthread_attr_init"); return; } pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE); /* block useful signal */ sigemptyset(&curmask); sigaddset(&curmask, SIGTERM); sigaddset(&curmask, SIGINT); sigaddset(&curmask, SIGCHLD); if (pthread_sigmask(SIG_BLOCK, &curmask, &oldmask) < 0) { xlog(LOG_ERROR, "sigprocmask failed : %s\n", strerror(errno)); return; } /* proxenet is now running :) */ proxy_state = ACTIVE; /* big loop */ while (proxy_state != INACTIVE) { conn = -1; retcode = -1; FD_ZERO(&sock_set); FD_SET(sock, &sock_set); FD_SET(ctl_sock, &sock_set); if (ctl_cli_sock > 0) FD_SET(ctl_cli_sock, &sock_set); purge_zombies(); /* set asynchronous listener */ struct timespec timeout = { .tv_sec = 5, .tv_nsec = 0 }; retcode = pselect(FD_SETSIZE, &sock_set, NULL, NULL, &timeout, &oldmask); if (retcode < 0) { if (errno != EINTR) { xlog(LOG_ERROR, "[main] pselect() returned %d: %s\n", retcode, strerror(errno)); proxy_state = INACTIVE; break; } else { continue; } } if (retcode == 0) continue; if (proxy_state == INACTIVE) break; /* event on the listening socket -> new request */ if( FD_ISSET(sock, &sock_set) && proxy_state != SLEEPING) { #ifdef DEBUG xlog(LOG_DEBUG, "%s\n", "Incoming listening event"); #endif tid = get_new_thread_id(); if(tid < 0) { continue; } struct sockaddr addr; socklen_t addrlen = 0; proxenet_xzero(&addr, sizeof(struct sockaddr)); conn = accept(sock, &addr, &addrlen); if (conn < 0) { if(errno != EINTR) xlog(LOG_ERROR, "[main] accept() failed: %s\n", strerror(errno)); continue; } retcode = proxenet_start_new_thread(conn, tid, &threads[tid], &pattr); if (retcode < 0) { xlog(LOG_ERROR, "[main] %s\n", "Error while spawn new thread"); continue; } } /* end if _socket_event */ /* event on control listening socket */ if( FD_ISSET(ctl_sock, &sock_set) ) { #ifdef DEBUG xlog(LOG_DEBUG, "%s\n", "Incoming control event"); #endif struct sockaddr_un sun_cli; socklen_t sun_cli_len = 0; int new_conn = -1; proxenet_xzero(&sun_cli, sizeof(struct sockaddr_un)); new_conn = accept(ctl_sock, (struct sockaddr *)&sun_cli, &sun_cli_len); if (new_conn < 0) { xlog(LOG_ERROR, "[main] control accept() failed: %s\n", strerror(errno)); continue; } if (ctl_cli_sock < 0) { ctl_cli_sock = new_conn; xlog(LOG_INFO, "%s\n", "New connection on Control socket"); proxenet_write(ctl_cli_sock, CONTROL_MOTD, strlen(CONTROL_MOTD)); proxenet_write(ctl_cli_sock, CONTROL_PROMPT, strlen(CONTROL_PROMPT)); } else { if(new_conn > 0) { xlog(LOG_ERROR, "%s\n", "Denied control connection: already established"); if(close_socket(new_conn) < 0) { xlog(LOG_ERROR, "Failed to close socket: %s\n", strerror(errno)); } } } }/* end if _control_listening_event */ /* event on control socket */ if( ctl_cli_sock > 0 && FD_ISSET(ctl_cli_sock, &sock_set) ) { if (proxenet_handle_control_event(&ctl_cli_sock) < 0) { close_socket(ctl_cli_sock); ctl_cli_sock = -1; } } /* end if _control_event */ } /* endof while(!INACTIVE) */ kill_zombies(); proxenet_destroy_plugins_vm(); pthread_attr_destroy(&pattr); return; } /** * * @param signum */ void sighandler(int signum) { #ifdef DEBUG xlog(LOG_DEBUG, "Received signal %s [%d]\n", strsignal(signum), signum); #endif switch(signum) { case SIGTERM: case SIGINT: if (proxy_state != INACTIVE) proxy_state = INACTIVE; cfg->try_exit++; xlog(LOG_INFO, "%s, %d/%d\n", "Trying to leave", cfg->try_exit, cfg->try_exit_max); if (cfg->try_exit == cfg->try_exit_max) { xlog(LOG_CRITICAL, "%s\n", "Failed to exit properly"); abort(); } break; case SIGCHLD: purge_zombies(); break; } }
/** * This function is called right after the configuration was parsed. * It simply: * - creates the main listening sockets (control and proxy) * - initialize the signal mask * - initialize all the VMs * - fill the plugin list with the valid plugins located in the autoload path * - then call the main thread loop * - once finished, it also cleans the structures * * @return 0 if everything went well, -1 otherwise with an error message */ int proxenet_start() { sock_t control_socket, listening_socket; struct sigaction saction; /* create control socket */ control_socket = proxenet_bind_control_socket(); if (control_socket < 0) { xlog(LOG_CRITICAL, "Cannot create control socket: %s\n", strerror(errno)); return -1; } if(cfg->verbose) xlog(LOG_INFO, "Control socket: %d\n", control_socket); /* create listening socket */ listening_socket = proxenet_bind_socket(cfg->iface, cfg->port); if (listening_socket < 0) { xlog(LOG_CRITICAL, "Cannot create bind socket: %s\n", strerror(errno)); return -1; } if(cfg->verbose) xlog(LOG_INFO, "Bind socket: %d\n", listening_socket); /* init everything */ initialize_sigmask(&saction); plugins_list = NULL; proxy_state = INACTIVE; active_threads_bitmask = 0; /* set up plugins */ if( proxenet_initialize_plugins_list() < 0 ) return -1; /* this call *MUST* succeed or die */ proxenet_initialize_plugins(); /* setting request counter */ request_id = 0; /* we "artificially" allocate an ID 0 so that all new requests will be > 0 */ /* for the child threads, a request id of 0 means not allocated */ get_new_request_id(); init_global_stats(); /* prepare threads and start looping */ xloop(listening_socket, control_socket); end_global_stats(); if (cfg->verbose) print_global_stats(); /* clean context */ proxenet_destroy_plugins_vm(); proxenet_free_all_plugins(); proxenet_close_socket(listening_socket, NULL); proxenet_close_socket(control_socket, NULL); unlink(CFG_CONTROL_SOCK_PATH); return 0; }