From 26248772325231d2a1d0b8bf81083228836378ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yves=20R=C5=B1tschl=C3=A9?= Date: Tue, 12 Aug 2025 23:05:24 +0200 Subject: [PATCH] sslh-ev: keep track of forked processes --- hash.c | 3 ++- processes.c | 39 +++++++++++++++++++++------------------ processes.h | 3 ++- sslh-ev.c | 20 ++++++++++++++++++++ sslh-select.c | 23 +++++++++++++++++++++++ tcp-listener.c | 13 ++++--------- tcp-listener.h | 8 -------- 7 files changed, 72 insertions(+), 37 deletions(-) diff --git a/hash.c b/hash.c index cd79f2d..5105254 100644 --- a/hash.c +++ b/hash.c @@ -46,6 +46,7 @@ #if 0 #define DEBUG 1 +#include #endif typedef void* hash_item; @@ -169,7 +170,7 @@ int hash_insert(hash* h, hash_item new) if (distance(index, h, curr_item) < distance(index, h, new)) { gap_set(h->data, index, new); #if DEBUG - fprintf(stderr, "intermediate insert [%d] at %d\n", new->pid, index); + fprintf(stderr, "intermediate insert at %d\n", index); #endif new = curr_item; } diff --git a/processes.c b/processes.c index 294b114..0f20688 100644 --- a/processes.c +++ b/processes.c @@ -26,6 +26,14 @@ #include "probe.h" #include "log.h" +/* Struct to keep track of an association of a forked PID to its + * listening socket and its protocol */ +struct pid2proto { + pid_t pid; + struct listen_endpoint* endpoint; + struct sslhcfg_protocols_item* proto; +}; + int tidy_connection(struct connection *cnx, struct loop_info* fd_info) { @@ -130,10 +138,7 @@ static int pid_cmp(hash_item item1, hash_item item2) /* When a child has died, update the counts appropriately */ void decrease_forked_connection(struct loop_info* loop, pid_t pid) { - struct pid2proto p2p = { - .pid = pid, - .proto = NULL - }; + struct pid2proto p2p = { .pid = pid }; struct pid2proto* found = hash_find(loop->pid2proto, &p2p); dec_proto_connections(found->proto); dec_listen_connections(found->endpoint); @@ -142,20 +147,18 @@ void decrease_forked_connection(struct loop_info* loop, pid_t pid) { free(found); } -/* Check if SIGCHLD was received, find which PID and reap appropriately */ -extern volatile sig_atomic_t received_sigchld; -void sigchld_process(struct loop_info* loop) + +typedef struct pid2proto* hash_item; +#include "hash.h" +void remember_child_data(struct loop_info* fd_info, + struct connection* cnx, pid_t pid) { - int chld; - if (received_sigchld) { - received_sigchld = 0; - do { - chld = waitpid(-1, NULL, WNOHANG); - CHECK_RES_RETURN(chld, "waitpid", ); - if (chld) { - decrease_forked_connection(loop, chld); - } - } while (chld); + struct pid2proto* pid2proto = malloc(sizeof(*pid2proto)); + pid2proto->pid = pid; + pid2proto->proto = cnx->proto; + pid2proto->endpoint = cnx->endpoint; + if (hash_insert(fd_info->pid2proto, pid2proto)) { + /* TODO something if it fails */ } } @@ -170,7 +173,7 @@ void loop_init(struct loop_info* loop) loop->pid2proto = hash_init(32, pid_make_key, pid_cmp); if (!loop->pid2proto) { - /* do something! (we're also not doing anything for UDP) */ + /* TODO do something! (we're also not doing anything for UDP) */ } } diff --git a/processes.h b/processes.h index 6c3afae..acc0eaf 100644 --- a/processes.h +++ b/processes.h @@ -33,7 +33,8 @@ struct connection* cnx_accept_process(struct loop_info* fd_info, struct listen_e int tidy_connection(struct connection *cnx, struct loop_info* fd_info); void loop_init(struct loop_info* loop); -void sigchld_process(struct loop_info* loop); +void remember_child_data(struct loop_info* fd_info, + struct connection* cnx, pid_t pid); /* These must be declared in the loop handler, sslh-ev or sslh-select */ void watchers_add_read(watchers* w, int fd); diff --git a/sslh-ev.c b/sslh-ev.c index 3e2a4b9..321d5d0 100644 --- a/sslh-ev.c +++ b/sslh-ev.c @@ -129,6 +129,26 @@ static void cnx_accept_cb(EV_P_ ev_io *w, int revents) cnx_accept_process(info, gap_get(info->watchers->fd2ls, w->fd)); } + +void sigchld_cb(EV_P_ ev_child *w, int revents) +{ + printf("sigchld_cb %d\n", w->pid); + struct loop_info* info = ev_userdata(EV_A); + ev_child_stop(EV_A_ w); + + decrease_forked_connection(info, w->pid); + free(w); +} + +void watcher_sigchld(struct loop_info* fd_info, struct connection* cnx, pid_t pid) +{ + ev_child* cw = malloc(sizeof(*cw)); + + ev_child_init(cw, sigchld_cb, pid, 0); + ev_child_start(EV_DEFAULT_ cw); +} + + void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen) { struct loop_info ev_info; diff --git a/sslh-select.c b/sslh-select.c index 8516779..e5e82fc 100644 --- a/sslh-select.c +++ b/sslh-select.c @@ -88,8 +88,31 @@ void watchers_del_write(watchers* w, int fd) FD_CLR(fd, &w->fds_w); } +void watcher_sigchld(struct loop_info* fd_info, struct connection* cnx, pid_t pid) +{ + /* Nothing to do, watcher is processed in the event loop when select() is + * interrupted by the signal */ +} + /* /end watchers */ +/* Check if SIGCHLD was received, find which PID and reap appropriately */ +extern volatile sig_atomic_t received_sigchld; +static void sigchld_process(struct loop_info* loop) +{ + int chld; + printf("sigchld_process\n"); + if (received_sigchld) { + received_sigchld = 0; + do { + chld = waitpid(-1, NULL, WNOHANG); + CHECK_RES_RETURN(chld, "waitpid", ); + if (chld) { + decrease_forked_connection(loop, chld); + } + } while (chld); + } +} diff --git a/tcp-listener.c b/tcp-listener.c index 227e79d..728d426 100644 --- a/tcp-listener.c +++ b/tcp-listener.c @@ -26,8 +26,6 @@ #include "log.h" -typedef struct pid2proto* hash_item; -#include "hash.h" /* Removes cnx from probing list */ static void remove_probing_cnx(struct loop_info* fd_info, struct connection* cnx) @@ -309,15 +307,12 @@ void fork_shoveling_process(struct loop_info* fd_info, struct connection* cnx) { case -1: print_message(msg_system_error, "fork failed: err %d: %s\n", errno, strerror(errno)); break; default: /* parent */ - struct pid2proto* pid2proto = malloc(sizeof(*pid2proto)); - pid2proto->pid = pid; - pid2proto->proto = cnx->proto; - if (hash_insert(fd_info->pid2proto, pid2proto)) { - /* TODO something if it fails */ - } + remember_child_data(fd_info, cnx, pid); + watcher_sigchld(fd_info, cnx, pid); break; } - /* Free file descriptor, but do not reduce protocol count */ + /* Free file descriptor (used only in child), but do not reduce connection + * counts */ cnx->proto = NULL; cnx->endpoint = NULL; tidy_connection(cnx, fd_info); diff --git a/tcp-listener.h b/tcp-listener.h index e6f8e53..e67606d 100644 --- a/tcp-listener.h +++ b/tcp-listener.h @@ -5,14 +5,6 @@ #include "collection.h" #include "tcp-probe.h" -/* Struct to keep track of an association of a forked PID to its - * listening socket and its protocol */ -struct pid2proto { - pid_t pid; - struct listen_endpoint* endpoint; - struct sslhcfg_protocols_item* proto; -}; - void tcp_read_process(struct loop_info* fd_info, int fd); struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info); void probing_read_process(struct connection* cnx, struct loop_info* fd_info);