diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2023-09-08 05:32:40 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2023-09-08 05:32:40 +0000 |
commit | 9efa646c7fb520747804acdc829b3cccea0dce63 (patch) | |
tree | 8b98fc5da073f75d6ceea7bee433bb1f056843f5 /src/conn-tools | |
parent | 9f03a9a73f35b998ea5d923dcdcea087e5712858 (diff) | |
download | s6-networking-9efa646c7fb520747804acdc829b3cccea0dce63.tar.xz |
New versions of s6-tcpserver4d and s6-tcpserver6d
- both now use posix_spawn when available
- s6-tcpserver4d uses avltree for logarithmic lookups
- s6-tcpserver6d still has the linear lookup
- the point was to benchmark linear vs logarithmic, but the
fork() overhead overshadowed everything
- now with fork() out of the way, I'm going back to benchmarks
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/conn-tools')
-rw-r--r-- | src/conn-tools/deps-exe/s6-tcpserver4d | 1 | ||||
-rw-r--r-- | src/conn-tools/deps-exe/s6-tcpserver6d | 1 | ||||
-rw-r--r-- | src/conn-tools/s6-tcpserver4d.c | 245 | ||||
-rw-r--r-- | src/conn-tools/s6-tcpserver6d.c | 69 |
4 files changed, 163 insertions, 153 deletions
diff --git a/src/conn-tools/deps-exe/s6-tcpserver4d b/src/conn-tools/deps-exe/s6-tcpserver4d index 19869b2..062999f 100644 --- a/src/conn-tools/deps-exe/s6-tcpserver4d +++ b/src/conn-tools/deps-exe/s6-tcpserver4d @@ -1,2 +1,3 @@ +-ls6 -lskarnet ${SOCKET_LIB} diff --git a/src/conn-tools/deps-exe/s6-tcpserver6d b/src/conn-tools/deps-exe/s6-tcpserver6d index 19869b2..062999f 100644 --- a/src/conn-tools/deps-exe/s6-tcpserver6d +++ b/src/conn-tools/deps-exe/s6-tcpserver6d @@ -1,2 +1,3 @@ +-ls6 -lskarnet ${SOCKET_LIB} diff --git a/src/conn-tools/s6-tcpserver4d.c b/src/conn-tools/s6-tcpserver4d.c index 4c1edf2..8dd6614 100644 --- a/src/conn-tools/s6-tcpserver4d.c +++ b/src/conn-tools/s6-tcpserver4d.c @@ -9,9 +9,11 @@ #include <fcntl.h> #include <signal.h> -#include <skalibs/gccattributes.h> -#include <skalibs/allreadwrite.h> +#include <skalibs/posixplz.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> #include <skalibs/types.h> +#include <skalibs/allreadwrite.h> #include <skalibs/sgetopt.h> #include <skalibs/strerr.h> #include <skalibs/fmtscan.h> @@ -22,33 +24,38 @@ #include <skalibs/selfpipe.h> #include <skalibs/iopause.h> #include <skalibs/socket.h> -#include <skalibs/exec.h> +#include <skalibs/genset.h> +#include <skalibs/avltreen.h> + +#include <s6/ucspiserver.h> -#define ABSOLUTE_MAXCONN 1000 +#define ABSOLUTE_MAXCONN 16384 #define USAGE "s6-tcpserver4d [ -v verbosity ] [ -1 ] [ -c maxconn ] [ -C localmaxconn ] prog..." -typedef struct pidip_s pidip_t, *pidip_t_ref ; -struct pidip_s +typedef struct pidi_s pidi, *pidi_ref ; +struct pidi_s { - pid_t left ; - uint32_t right ; + pid_t pid ; + uint32_t i ; } ; -static unsigned int maxconn = 40 ; -static unsigned int localmaxconn = 40 ; -static unsigned int verbosity = 1 ; +static uint32_t maxconn = 40 ; +static uint32_t localmaxconn = 40 ; +static uint32_t verbosity = 1 ; static int cont = 1 ; -static pidip_t *pidip = 0 ; -static unsigned int numconn = 0 ; -static diuint32 *ipnum = 0 ; -static unsigned int iplen = 0 ; -static char fmtmaxconn[UINT_FMT+1] = "/" ; -static char fmtlocalmaxconn[UINT_FMT+1] = "/" ; +static genset *pidis ; +#define PIDI(i) genset_p(pidi, pidis, (i)) +#define numconn genset_n(pidis) +static genset *ipnums ; +#define IPNUM(i) genset_p(diuint32, ipnums, (i)) +static avltreen *by_ip ; +static avltreen *by_pid ; +static char fmtmaxconn[UINT32_FMT+1] = "/" ; +static char fmtlocalmaxconn[UINT32_FMT+1] = "/" ; - /* Utility functions */ static inline void dieusage () { @@ -60,25 +67,33 @@ static inline void X (void) strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ; } - - /* Lookup primitives */ - -static inline unsigned int lookup_pid (pid_t pid) +static void *bypid_dtok (uint32_t d, void *aux) { - unsigned int i = 0 ; - for (; i < numconn ; i++) if (pid == pidip[i].left) break ; - return i ; + genset *g = aux ; + return &genset_p(pidi, g, d)->pid ; } -static inline unsigned int lookup_ip (uint32_t ip) +static int bypid_cmp (void const *a, void const *b, void *aux) { - unsigned int i = 0 ; - for (; i < iplen ; i++) if (ip == ipnum[i].left) break ; - return i ; + (void)aux ; + pid_t aa = *(pid_t const *)a ; + pid_t bb = *(pid_t const *)b ; + return aa < bb ? -1 : aa > bb ; } +static void *byip_dtok (uint32_t d, void *aux) +{ + genset *g = aux ; + return &genset_p(diuint32, g, d)->left ; +} - /* Logging */ +static int byip_cmp (void const *a, void const *b, void *aux) +{ + (void)aux ; + uint32_t aa = *(uint32_t const *)a ; + uint32_t bb = *(uint32_t const *)b ; + return aa < bb ? -1 : aa > bb ; +} static inline void log_start (void) { @@ -97,28 +112,28 @@ static void log_status (void) strerr_warni3x("status: ", fmt, fmtmaxconn) ; } -static inline void log_deny (uint32_t ip, uint16_t port, unsigned int num) +static inline void log_deny (uint32_t ip, uint16_t port, uint32_t num) { char fmtip[UINT32_FMT] ; char fmtport[UINT16_FMT] ; - char fmtnum[UINT_FMT] ; + char fmtnum[UINT32_FMT] ; fmtip[ip4_fmtu32(fmtip, ip)] = 0 ; fmtport[uint16_fmt(fmtport, port)] = 0 ; - fmtnum[uint_fmt(fmtnum, num)] = 0 ; + fmtnum[uint32_fmt(fmtnum, num)] = 0 ; strerr_warni7sys("deny ", fmtip, ":", fmtport, " count ", fmtnum, fmtlocalmaxconn) ; } -static inline void log_accept (pid_t pid, uint32_t ip, uint16_t port, unsigned int num) +static inline void log_accept (pid_t pid, uint32_t ip, uint16_t port, uint32_t num) { char fmtipport[IP4_FMT + UINT16_FMT + 1] ; char fmtpid[PID_FMT] ; - char fmtnum[UINT_FMT] ; + char fmtnum[UINT32_FMT] ; size_t n ; n = ip4_fmtu32(fmtipport, ip) ; fmtipport[n++] = ':' ; n += uint16_fmt(fmtipport + n, port) ; fmtipport[n] = 0 ; - fmtnum[uint_fmt(fmtnum, num)] = 0 ; + fmtnum[uint32_fmt(fmtnum, num)] = 0 ; fmtpid[pid_fmt(fmtpid, pid)] = 0 ; strerr_warni7x("allow ", fmtipport, " pid ", fmtpid, " count ", fmtnum, fmtlocalmaxconn) ; } @@ -134,37 +149,42 @@ static inline void log_close (pid_t pid, uint32_t ip, int w) strerr_warni6x("end pid ", fmtpid, " ip ", fmtip, WIFSIGNALED(w) ? " signal " : " exitcode ", fmtw) ; } - - /* Signal handling */ +static int killthem_iter (void *data, void *aux) +{ + kill(((pidi *)data)->pid, *(int *)aux) ; + return 1 ; +} static void killthem (int sig) { - unsigned int i = 0 ; - for (; i < numconn ; i++) kill(pidip[i].left, sig) ; + genset_iter(pidis, &killthem_iter, &sig) ; } static inline void wait_children (void) { for (;;) { - unsigned int i ; - int w ; - pid_t pid = wait_nohang(&w) ; + uint32_t d ; + int wstat ; + pid_t pid = wait_nohang(&wstat) ; if (pid < 0) if (errno != ECHILD) strerr_diefu1sys(111, "wait_nohang") ; else break ; else if (!pid) break ; - i = lookup_pid(pid) ; - if (i < numconn) /* it's one of ours ! */ + if (avltreen_search(by_pid, &pid, &d)) { - uint32_t ip = pidip[i].right ; - unsigned int j = lookup_ip(ip) ; - if (j >= iplen) X() ; - if (!--ipnum[j].right) ipnum[j] = ipnum[--iplen] ; - pidip[i] = pidip[--numconn] ; + uint32_t i = PIDI(d)->i ; + uint32_t ip = IPNUM(i)->left ; + avltreen_delete(by_pid, &pid) ; + genset_delete(pidis, d) ; + if (!--IPNUM(i)->right) + { + avltreen_delete(by_ip, &ip) ; + genset_delete(ipnums, i) ; + } if (verbosity >= 2) { - log_close(pid, ip, w) ; + log_close(pid, ip, wstat) ; log_status() ; } } @@ -214,73 +234,63 @@ static inline void handle_signals (void) } } - - /* New connection handling */ - -static inline void run_child (int, uint32_t, uint16_t, unsigned int, char const *const *) gccattr_noreturn ; -static inline void run_child (int s, uint32_t ip, uint16_t port, unsigned int num, char const *const *argv) -{ - char fmt[74] ; - size_t n = 0 ; - PROG = "s6-tcpserver4d (child)" ; - if ((fd_move(1, s) < 0) || (fd_copy(0, 1) < 0)) - strerr_diefu1sys(111, "move fds") ; - memcpy(fmt+n, "PROTO=TCP\0TCPREMOTEIP=", 22) ; n += 22 ; - n += ip4_fmtu32(fmt+n, ip) ; fmt[n++] = 0 ; - memcpy(fmt+n, "TCPREMOTEPORT=", 14) ; n += 14 ; - n += uint16_fmt(fmt+n, port) ; fmt[n++] = 0 ; - memcpy(fmt+n, "TCPCONNNUM=", 11) ; n += 11 ; - n += uint_fmt(fmt+n, num) ; fmt[n++] = 0 ; - xmexec_n(argv, fmt, n, 4) ; -} - -static inline void new_connection (int s, uint32_t ip, uint16_t port, char const *const *argv) +static inline void new_connection (int s, uint32_t ip, uint16_t port, char const *const *argv, char const *const *envp, size_t envlen) { - unsigned int i = lookup_ip(ip) ; - unsigned int num = (i < iplen) ? ipnum[i].right : 0 ; + size_t m = 0 ; pid_t pid ; + uint32_t d ; + uint32_t num = 0 ; + char fmt[47 + IP4_FMT + UINT16_FMT + UINT_FMT] ; + + if (avltreen_search(by_ip, &ip, &d)) num = IPNUM(d)->right ; if (num >= localmaxconn) { log_deny(ip, port, num) ; return ; } - pid = fork() ; - if (pid < 0) + + memcpy(fmt + m, "PROTO=TCP\0TCPREMOTEIP=", 22) ; m += 22 ; + m += ip4_fmtu32(fmt + m, ip) ; + fmt[m++] = 0 ; + memcpy(fmt + m, "TCPREMOTEPORT=", 14) ; m += 14 ; + m += uint16_fmt(fmt + m, port) ; fmt[m++] = 0 ; + memcpy(fmt + m, "TCPCONNNUM=", 11) ; m += 11 ; + m += uint_fmt(fmt + m, num) ; fmt[m++] = 0 ; + + pid = s6_ucspiserver_spawn(s, argv, envp, envlen, fmt, m, 4) ; + if (!pid) { - if (verbosity) strerr_warnwu1sys("fork") ; + if (verbosity) strerr_warnwu2sys("spawn ", argv[0]) ; return ; } - else if (!pid) - { - selfpipe_finish() ; - run_child(s, ip, port, num+1, argv) ; - } - if (i < iplen) ipnum[i].right = num + 1 ; + if (num) IPNUM(d)->right++ ; else { - ipnum[iplen].left = ip ; - ipnum[iplen++].right = 1 ; + d = genset_new(ipnums) ; + IPNUM(d)->left = ip ; + IPNUM(d)->right = 1 ; + avltreen_insert(by_ip, d) ; } - pidip[numconn].left = pid ; - pidip[numconn++].right = ip ; + + num = genset_new(pidis) ; + PIDI(num)->pid = pid ; + PIDI(num)->i = d ; + avltreen_insert(by_pid, num) ; if (verbosity >= 2) { - log_accept(pid, ip, port, ipnum[i].right) ; + log_accept(pid, ip, port, IPNUM(d)->right) ; log_status() ; } } - - /* And the main */ - int main (int argc, char const *const *argv) { iopause_fd x[2] = { { .events = IOPAUSE_READ }, { .fd = 0, .events = IOPAUSE_READ | IOPAUSE_EXCEPT } } ; + int flag1 = 0 ; PROG = "s6-tcpserver4d" ; { subgetopt l = SUBGETOPT_ZERO ; - int flag1 = 0 ; for (;;) { int opt = subgetopt_r(argc, argv, "1c:C:v:", &l) ; @@ -288,9 +298,9 @@ int main (int argc, char const *const *argv) switch (opt) { case '1' : flag1 = 1 ; break ; - case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; break ; - case 'C' : if (!uint0_scan(l.arg, &localmaxconn)) dieusage() ; break ; - case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; + case 'c' : if (!uint320_scan(l.arg, &maxconn)) dieusage() ; break ; + case 'C' : if (!uint320_scan(l.arg, &localmaxconn)) dieusage() ; break ; + case 'v' : if (!uint320_scan(l.arg, &verbosity)) dieusage() ; break ; default : dieusage() ; } } @@ -301,7 +311,8 @@ int main (int argc, char const *const *argv) if (fstat(0, &st) < 0) strerr_diefu1sys(111, "fstat stdin") ; if (!S_ISSOCK(st.st_mode)) strerr_dief1x(100, "stdin is not a socket") ; } - if (coe(0) < 0) strerr_diefu1sys(111, "make socket close-on-exec") ; + if (coe(0) == -1 || ndelay_on(0) == -1) + strerr_diefu1sys(111, "set socket flags") ; if (flag1) { if (fcntl(1, F_GETFD) < 0) @@ -325,13 +336,40 @@ int main (int argc, char const *const *argv) sigaddset(&set, SIGABRT) ; if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "trap signals") ; } - fmtlocalmaxconn[1+uint_fmt(fmtlocalmaxconn+1, localmaxconn)] = 0 ; + fmtlocalmaxconn[1+uint32_fmt(fmtlocalmaxconn+1, localmaxconn)] = 0 ; + } + + { + diuint32 ipnum_storage[maxconn] ; + uint32_t ipnum_freelist[maxconn] ; + avlnode byip_storage[maxconn] ; + uint32_t byip_freelist[maxconn] ; + pidi pidi_storage[maxconn] ; + uint32_t pidi_freelist[maxconn] ; + avlnode bypid_storage[maxconn] ; + uint32_t bypid_freelist[maxconn] ; + genset ipnum_info ; + genset pidi_info ; + avltreen byip_info ; + avltreen bypid_info ; + size_t envlen = env_len((char const *const *)environ) ; + + GENSET_init(&ipnum_info, diuint32, ipnum_storage, ipnum_freelist, maxconn) ; + GENSET_init(&pidi_info, pidi, pidi_storage, pidi_freelist, maxconn) ; + avltreen_init(&byip_info, byip_storage, byip_freelist, maxconn, &byip_dtok, &byip_cmp, &ipnum_info) ; + avltreen_init(&bypid_info, bypid_storage, bypid_freelist, maxconn, &bypid_dtok, &bypid_cmp, &pidi_info) ; + ipnums = &ipnum_info ; + pidis = &pidi_info ; + by_ip = &byip_info ; + by_pid = &bypid_info ; + if (verbosity >= 2) { - fmtmaxconn[1+uint_fmt(fmtmaxconn+1, maxconn)] = 0 ; + fmtmaxconn[1+uint32_fmt(fmtmaxconn+1, maxconn)] = 0 ; log_start() ; log_status() ; } + if (flag1) { uint16_t port ; @@ -345,14 +383,9 @@ int main (int argc, char const *const *argv) else m = uint16_fmt(fmtport, port) ; fmtport[m++] = '\n' ; allwrite(1, fmtport, m) ; - fd_close(1) ; + close(1) ; } - } - { - pidip_t pidip_inyostack[maxconn] ; - diuint32 ipnum_inyostack[maxconn] ; - pidip = pidip_inyostack ; ipnum = ipnum_inyostack ; while (cont) { if (iopause_g(x, 1 + (numconn < maxconn), 0) < 0) strerr_diefu1sys(111, "iopause") ; @@ -366,7 +399,7 @@ int main (int argc, char const *const *argv) char packedip[4] ; uint16_t port ; int fd = socket_accept4(x[1].fd, packedip, &port) ; - if (fd < 0) + if (fd == -1) { if (verbosity) strerr_warnwu1sys("accept") ; } @@ -374,7 +407,7 @@ int main (int argc, char const *const *argv) { uint32_t ip ; uint32_unpack_big(packedip, &ip) ; - new_connection(fd, ip, port, argv) ; + new_connection(fd, ip, port, argv, (char const *const *)environ, envlen) ; fd_close(fd) ; } } diff --git a/src/conn-tools/s6-tcpserver6d.c b/src/conn-tools/s6-tcpserver6d.c index b345d72..e3c66bd 100644 --- a/src/conn-tools/s6-tcpserver6d.c +++ b/src/conn-tools/s6-tcpserver6d.c @@ -9,7 +9,7 @@ #include <fcntl.h> #include <signal.h> -#include <skalibs/gccattributes.h> +#include <skalibs/posixplz.h> #include <skalibs/allreadwrite.h> #include <skalibs/types.h> #include <skalibs/sgetopt.h> @@ -21,9 +21,10 @@ #include <skalibs/selfpipe.h> #include <skalibs/iopause.h> #include <skalibs/socket.h> -#include <skalibs/exec.h> -#define ABSOLUTE_MAXCONN 1000 +#include <s6/ucspiserver.h> + +#define ABSOLUTE_MAXCONN 16384 #define USAGE "s6-tcpserver6d [ -v verbosity ] [ -1 ] [ -c maxconn ] [ -C localmaxconn ] prog..." @@ -53,9 +54,6 @@ static unsigned int iplen = 0 ; static char fmtmaxconn[UINT_FMT+1] = "/" ; static char fmtlocalmaxconn[UINT_FMT+1] = "/" ; - - /* Utility functions */ - static inline void dieusage () { strerr_dieusage(100, USAGE) ; @@ -66,9 +64,6 @@ static inline void X (void) strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ; } - - /* Lookup primitives */ - static inline unsigned int lookup_pid (pid_t pid) { unsigned int i = 0 ; @@ -83,9 +78,6 @@ static inline unsigned int lookup_ip (char const *ip) return i ; } - - /* Logging */ - static inline void log_start (void) { strerr_warni1x("starting") ; @@ -140,9 +132,6 @@ static inline void log_close (pid_t pid, char const *ip, int w) strerr_warni6x("end pid ", fmtpid, " ip ", fmtip, WIFSIGNALED(w) ? " signal " : " exitcode ", fmtw) ; } - - /* Signal handling */ - static void killthem (int sig) { unsigned int i = 0 ; @@ -220,47 +209,33 @@ static inline void handle_signals (void) } } - - /* New connection handling */ - -static inline void run_child (int, char const *, uint16_t, unsigned int, char const *const *) gccattr_noreturn ; -static inline void run_child (int s, char const *ip, uint16_t port, unsigned int num, char const *const *argv) -{ - char fmt[98] ; - size_t n = 0 ; - PROG = "s6-tcpserver6d (child)" ; - if ((fd_move(1, s) < 0) || (fd_copy(0, 1) < 0)) - strerr_diefu1sys(111, "move fds") ; - memcpy(fmt+n, "PROTO=TCP\0TCPREMOTEIP=", 22) ; n += 22 ; - n += ip6_fmt(fmt+n, ip) ; fmt[n++] = 0 ; - memcpy(fmt+n, "TCPREMOTEPORT=", 14) ; n += 14 ; - n += uint16_fmt(fmt+n, port) ; fmt[n++] = 0 ; - memcpy(fmt+n, "TCPCONNNUM=", 11) ; n += 11 ; - n += uint_fmt(fmt+n, num) ; fmt[n++] = 0 ; - xmexec_n(argv, fmt, n, 4) ; -} - -static inline void new_connection (int s, char const *ip, uint16_t port, char const *const *argv) +static inline void new_connection (int s, char const *ip, uint16_t port, char const *const *argv, char const *const *envp, size_t envlen) { + pid_t pid ; unsigned int i = lookup_ip(ip) ; unsigned int num = (i < iplen) ? ipnum[i].num : 0 ; - pid_t pid ; + size_t m = 0 ; + char fmt[47 + IP6_FMT + UINT16_FMT + UINT_FMT] ; + if (num >= localmaxconn) { log_deny(ip, port, num) ; return ; } - pid = fork() ; - if (pid < 0) + + memcpy(fmt + m, "PROTO=TCP\0TCPREMOTEIP=", 22) ; m += 22 ; + m += ip6_fmt(fmt + m, ip) ; fmt[m++] = 0 ; + memcpy(fmt + m, "TCPREMOTEPORT=", 14) ; m += 14 ; + m += uint16_fmt(fmt + m, port) ; fmt[m++] = 0 ; + memcpy(fmt + m, "TCPCONNNUM=", 11) ; m += 11 ; + m += uint_fmt(fmt + m, num) ; fmt[m++] = 0 ; + + pid = s6_ucspiserver_spawn(s, argv, envp, envlen, fmt, m, 4) ; + if (!pid) { - if (verbosity) strerr_warnwu1sys("fork") ; + if (verbosity) strerr_warnwu2sys("spawn ", argv[0]) ; return ; } - else if (!pid) - { - selfpipe_finish() ; - run_child(s, ip, port, num+1, argv) ; - } if (i < iplen) ipnum[i].num = num + 1 ; else @@ -277,7 +252,6 @@ static inline void new_connection (int s, char const *ip, uint16_t port, char co } } - int main (int argc, char const *const *argv) { iopause_fd x[2] = { { .events = IOPAUSE_READ }, { .fd = 0, .events = IOPAUSE_READ | IOPAUSE_EXCEPT } } ; @@ -356,6 +330,7 @@ int main (int argc, char const *const *argv) { pidip_t pidip_inyostack[maxconn] ; ipnum_t ipnum_inyostack[maxconn] ; + size_t envlen = env_len((char const *const *)environ) ; pidip = pidip_inyostack ; ipnum = ipnum_inyostack ; while (cont) @@ -379,7 +354,7 @@ int main (int argc, char const *const *argv) } else { - new_connection(fd, ip, port, argv) ; + new_connection(fd, ip, port, argv, (char const *const *)environ, envlen) ; fd_close(fd) ; } } |