From 0126aaa88a1973c88192a7c5be4c7195288ed762 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 8 Mar 2025 17:46:52 +0000 Subject: [PATCH 1/4] sockets: Abstract datum_sockets_setup_listen_sock out of datum_gateway_listener_thread --- src/datum_sockets.c | 47 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/datum_sockets.c b/src/datum_sockets.c index f849664..ef57b68 100644 --- a/src/datum_sockets.c +++ b/src/datum_sockets.c @@ -537,10 +537,32 @@ int assign_to_thread(T_DATUM_SOCKET_APP *app, int fd) { return 1; } +const char *datum_sockets_setup_listen_sock(const int listen_sock, const struct sockaddr * const sa, const size_t sa_len) { + if (-1 == listen_sock) { + return "Could not create listening socket"; + } + + datum_socket_setoptions(listen_sock); + + static const int reuse = 1; + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) { + return "setsockopt(SO_REUSEADDR) failed"; + } + + if (bind(listen_sock, sa, sa_len) < 0) { + return "bind failed"; + } + + if (listen(listen_sock, 10) < 0) { + return "listen failed"; + } + + return NULL; +} + void *datum_gateway_listener_thread(void *arg) { struct sockaddr_in serveraddr; int i, ret; - int reuse = 1; bool rejecting_now = false; uint64_t last_reject_msg_tsms = 0, curtime_tsms = 0; uint64_t reject_count = 0; @@ -578,13 +600,7 @@ void *datum_gateway_listener_thread(void *arg) { app->datum_active_threads = 0; listen_sock = socket(AF_INET, SOCK_STREAM, 0); - if (-1 == listen_sock) { - DLOG_FATAL("Could not create listening socket: %s", strerror(errno)); - panic_from_thread(__LINE__); - return NULL; - } - datum_socket_setoptions(listen_sock); memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(app->listen_port); @@ -592,20 +608,9 @@ void *datum_gateway_listener_thread(void *arg) { // TODO: Add option to bind to specific IP per configuration! serveraddr.sin_addr.s_addr = INADDR_ANY; - if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) { - DLOG_FATAL("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno)); - panic_from_thread(__LINE__); - return NULL; - } - - if(bind(listen_sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { - DLOG_FATAL("bind failed: %s", strerror(errno)); - panic_from_thread(__LINE__); - return NULL; - } - - if (listen(listen_sock, 10) < 0) { - DLOG_FATAL("listen failed: %s", strerror(errno)); + const char *errstr = datum_sockets_setup_listen_sock(listen_sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); + if (errstr) { + DLOG_FATAL("%s: %s", errstr, strerror(errno)); panic_from_thread(__LINE__); return NULL; } From eef0e44dd2d17f84babeb91a336008cefd3eddcd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 8 Mar 2025 18:15:08 +0000 Subject: [PATCH 2/4] sockets: Attempt to listen on both IPv4 and IPv6 --- src/datum_sockets.c | 60 +++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/datum_sockets.c b/src/datum_sockets.c index ef57b68..4afa6e3 100644 --- a/src/datum_sockets.c +++ b/src/datum_sockets.c @@ -561,7 +561,6 @@ const char *datum_sockets_setup_listen_sock(const int listen_sock, const struct } void *datum_gateway_listener_thread(void *arg) { - struct sockaddr_in serveraddr; int i, ret; bool rejecting_now = false; uint64_t last_reject_msg_tsms = 0, curtime_tsms = 0; @@ -570,7 +569,7 @@ void *datum_gateway_listener_thread(void *arg) { T_DATUM_SOCKET_APP *app = (T_DATUM_SOCKET_APP *)arg; struct epoll_event ev, events[MAX_EVENTS]; - int listen_sock, conn_sock, nfds, epollfd; + int listen_socks[2], conn_sock, nfds, epollfd; if (!app) { DLOG_FATAL("Called without application data structure. :("); @@ -599,21 +598,37 @@ void *datum_gateway_listener_thread(void *arg) { app->datum_active_threads = 0; - listen_sock = socket(AF_INET, SOCK_STREAM, 0); + const struct sockaddr_in6 anyaddr6 = { + .sin6_family = AF_INET6, + .sin6_port = htons(app->listen_port), + .sin6_addr = IN6ADDR_ANY_INIT, + }; + listen_socks[0] = socket(AF_INET6, SOCK_STREAM, 0); + const char * const errstr6 = datum_sockets_setup_listen_sock(listen_socks[0], (const struct sockaddr *)&anyaddr6, sizeof(anyaddr6)); + const int errno6 = errno; + if (errstr6 && listen_socks[0] != -1) { + close(listen_socks[0]); + listen_socks[0] = -1; + } - memset(&serveraddr, 0, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - serveraddr.sin_port = htons(app->listen_port); - - // TODO: Add option to bind to specific IP per configuration! - serveraddr.sin_addr.s_addr = INADDR_ANY; - - const char *errstr = datum_sockets_setup_listen_sock(listen_sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); - if (errstr) { - DLOG_FATAL("%s: %s", errstr, strerror(errno)); + const struct sockaddr_in anyaddr4 = { + .sin_family = AF_INET, + .sin_port = htons(app->listen_port), + .sin_addr.s_addr = INADDR_ANY, + }; + listen_socks[1] = socket(AF_INET, SOCK_STREAM, 0); + const char *errstr = datum_sockets_setup_listen_sock(listen_socks[1], (const struct sockaddr *)&anyaddr4, sizeof(anyaddr4)); + if (errstr && errstr6) { + const int errno4 = errno; + DLOG_FATAL("%s (IPv6): %s", errstr6, strerror(errno6)); + DLOG_FATAL("%s (IPv4): %s", errstr, strerror(errno4)); panic_from_thread(__LINE__); return NULL; } + if (errstr && listen_socks[1] != -1) { + close(listen_socks[1]); + listen_socks[1] = -1; + } epollfd = epoll_create1(0); if (epollfd < 0) { @@ -622,12 +637,15 @@ void *datum_gateway_listener_thread(void *arg) { return NULL; } - ev.events = EPOLLIN; - ev.data.fd = listen_sock; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev)<0) { - DLOG_FATAL("epoll_ctl failed: %s", strerror(errno)); - panic_from_thread(__LINE__); - return NULL; + for (i = 0; i < 2; ++i) { + if (listen_socks[i] == -1) continue; + ev.events = EPOLLIN; + ev.data.fd = listen_socks[i]; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) { + DLOG_FATAL("epoll_ctl failed: %s", strerror(errno)); + panic_from_thread(__LINE__); + return NULL; + } } DLOG_INFO("DATUM Socket listener thread active for '%s'", app->name); @@ -646,8 +664,8 @@ void *datum_gateway_listener_thread(void *arg) { } } for (int n = 0; n < nfds; ++n) { - if (events[n].data.fd == listen_sock) { - conn_sock = accept(listen_sock, NULL, NULL); + if (events[n].data.fd == listen_socks[0] || events[n].data.fd == listen_socks[1]) { + conn_sock = accept(events[n].data.fd, NULL, NULL); if (conn_sock < 0) { DLOG_ERROR("accept failed: %s", strerror(errno)); continue; From 591a1d763c05ca433b3b52227d346ef464dc00b0 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 8 Mar 2025 19:22:15 +0000 Subject: [PATCH 3/4] api: Abstract datum_api_try_start out of datum_api_thread --- src/datum_api.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/datum_api.c b/src/datum_api.c index ef0d8da..ca698ed 100644 --- a/src/datum_api.c +++ b/src/datum_api.c @@ -1128,6 +1128,20 @@ enum MHD_Result datum_api_answer(void *cls, struct MHD_Connection *connection, c return ret; } +static struct MHD_Daemon *datum_api_try_start(unsigned int flags) { + flags |= MHD_USE_AUTO; // event loop API + flags |= MHD_USE_INTERNAL_POLLING_THREAD; + return MHD_start_daemon( + flags, + datum_config.api_listen_port, + NULL, NULL, // accept policy filter + &datum_api_answer, NULL, // default URI handler + MHD_OPTION_CONNECTION_LIMIT, 128, + MHD_OPTION_NOTIFY_COMPLETED, datum_api_request_completed, NULL, + MHD_OPTION_LISTENING_ADDRESS_REUSE, (unsigned int)1, + MHD_OPTION_END); +} + void *datum_api_thread(void *ptr) { struct MHD_Daemon *daemon; @@ -1136,11 +1150,7 @@ void *datum_api_thread(void *ptr) { return NULL; } - daemon = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, datum_config.api_listen_port, NULL, NULL, &datum_api_answer, NULL, - MHD_OPTION_CONNECTION_LIMIT, 128, - MHD_OPTION_NOTIFY_COMPLETED, datum_api_request_completed, NULL, - MHD_OPTION_LISTENING_ADDRESS_REUSE, (unsigned int)1, - MHD_OPTION_END); + daemon = datum_api_try_start(0); if (!daemon) { DLOG_FATAL("Unable to start daemon for API"); From ce841b9bc1a1c3b332beb137793afe1e94513c2d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 8 Mar 2025 19:35:46 +0000 Subject: [PATCH 4/4] api: Attempt to use dual-stack (IPv6 & IPv4) --- src/datum_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/datum_api.c b/src/datum_api.c index ca698ed..9e42264 100644 --- a/src/datum_api.c +++ b/src/datum_api.c @@ -1150,7 +1150,8 @@ void *datum_api_thread(void *ptr) { return NULL; } - daemon = datum_api_try_start(0); + daemon = datum_api_try_start(MHD_USE_DUAL_STACK); + if (!daemon) daemon = datum_api_try_start(0); if (!daemon) { DLOG_FATAL("Unable to start daemon for API");