# HG changeset patch # User Olaf Wintermann # Date 1670070416 -3600 # Node ID 240ed6f945ca31d63da08b173544044f7f200ccd # Parent 834351da593b898b4cfc1896adb36921c15435dd implement acceptor thread shutdown diff -r 834351da593b -r 240ed6f945ca src/server/daemon/httplistener.c --- a/src/server/daemon/httplistener.c Sat Dec 03 12:27:00 2022 +0100 +++ b/src/server/daemon/httplistener.c Sat Dec 03 13:26:56 2022 +0100 @@ -30,15 +30,10 @@ #include #include -#include + #include -#include #include -#include #include -#include -#include -#include #include #include #include @@ -48,12 +43,8 @@ #include #include -#include -#include #include #include -#include -#include #include @@ -269,26 +260,25 @@ #endif // bind server socket to address - struct sockaddr_in servaddr4; - struct sockaddr_in6 servaddr6; + union ws_socketaddr addr; struct sockaddr *servaddr; size_t servaddr_size; if(ipv4) { // ipv4 - memset(&servaddr4, 0, sizeof(servaddr4)); - servaddr4.sin_family = AF_INET; - servaddr4.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr4.sin_port = htons(conf->port); - servaddr = (struct sockaddr *)&servaddr4; - servaddr_size = sizeof(servaddr4); + memset(&addr.addr4, 0, sizeof(addr.addr4)); + addr.addr4.sin_family = AF_INET; + addr.addr4.sin_addr.s_addr = htonl(INADDR_ANY); + addr.addr4.sin_port = htons(conf->port); + servaddr = (struct sockaddr *)&addr.addr4; + servaddr_size = sizeof(addr.addr4); } else { // ipv6 - memset(&servaddr6, 0, sizeof(servaddr6)); - servaddr6.sin6_family = AF_INET6; - servaddr6.sin6_addr = in6addr_any; - servaddr6.sin6_port = htons(conf->port); - servaddr = (struct sockaddr *)&servaddr6; - servaddr_size = sizeof(servaddr6); + memset(&addr.addr6, 0, sizeof(addr.addr6)); + addr.addr6.sin6_family = AF_INET6; + addr.addr6.sin6_addr = in6addr_any; + addr.addr6.sin6_port = htons(conf->port); + servaddr = (struct sockaddr *)&addr.addr6; + servaddr_size = sizeof(addr.addr6); } if(bind(s, servaddr, servaddr_size)) { @@ -310,6 +300,13 @@ } ZERO(wssocket, sizeof(WSSocket)); wssocket->socket = s; + wssocket->addr = addr; + if(ipv4) { + wssocket->sockaddr = (struct sockaddr *)&wssocket->addr.addr4; + } else { + wssocket->sockaddr = (struct sockaddr *)&wssocket->addr.addr6; + } + wssocket->sockaddr_size = servaddr_size; return wssocket; } @@ -476,10 +473,52 @@ listener->next = next; } +int http_listener_connect(HttpListener *listener, WSBool ipv6) { + int domain = ipv6 ? AF_INET6 : AF_INET; + int client = socket(domain, SOCK_STREAM, 0); + if(client < 0) { + return -1; + } + + struct sockaddr *sockaddr; + size_t sockaddr_size; + if(ipv6) { + sockaddr = listener->server_socket6->sockaddr; + sockaddr_size = listener->server_socket6->sockaddr_size; + } else { + sockaddr = listener->server_socket->sockaddr; + sockaddr_size = listener->server_socket->sockaddr_size; + } + + if(connect(client, sockaddr, sockaddr_size) < 0) { + close(client); + return -1; + } + + return client; +} void http_listener_shutdown_acceptors(HttpListener *listener) { - // not implemented yet + // + + for(int i=0;inacceptors;i++) { + listener->acceptors[i]->exit = TRUE; + int client4 = http_listener_connect(listener, FALSE); + if(client4 < 0) { + log_ereport(LOG_FAILURE, "http_listener_shutdown_acceptors: cannot connect to ipv4 server socket: %s", strerror(errno)); + } else { + close(client4); + } + + listener->acceptors6[i]->exit = TRUE; + int client6 = http_listener_connect(listener, TRUE); + if(client6 < 0) { + log_ereport(LOG_FAILURE, "http_listener_shutdown_acceptors: cannot connect to ipv6 server socket: %s", strerror(errno)); + } else { + close(client6); + } + } } @@ -547,6 +586,11 @@ log_ereport(LOG_DEBUG, "acceptor: %p listener: %p: accept(): %d", acceptor, acceptor->listener, clientfd); if (clientfd == -1) { log_ereport(LOG_FAILURE, "accept %s failed: %s", acceptor->ipv6 ? "ipv6" : "ipv4", strerror(errno)); + + if(acceptor->exit) { + log_ereport(LOG_VERBOSE, "acceptor thread %p: listener: %p exit", acceptor, acceptor->listener); + break; + } continue; } @@ -613,13 +657,12 @@ if(acceptor_exit || acceptor->exit) { // this acceptor is outdated - log_ereport(LOG_VERBOSE, "acceptor thread %p: exit", (void*)acceptor->tid); + log_ereport(LOG_VERBOSE, "acceptor thread %p: listener: %p exit", acceptor, acceptor->listener); break; } } acceptor->running = FALSE; - log_ereport(LOG_DEBUG, "acceptor: %p listener %p exit thread", acceptor, acceptor->listener); cfg_unref(acceptor->listener->cfg); diff -r 834351da593b -r 240ed6f945ca src/server/daemon/httplistener.h --- a/src/server/daemon/httplistener.h Sat Dec 03 12:27:00 2022 +0100 +++ b/src/server/daemon/httplistener.h Sat Dec 03 13:26:56 2022 +0100 @@ -34,6 +34,13 @@ #include "config.h" #include "../util/systems.h" +#include +#include +#include +#include +#include +#include + #include #include #include @@ -112,7 +119,15 @@ // TODO: ssl/tls cipher, ... config }; +union ws_socketaddr { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; +}; + struct _ws_socket { + union ws_socketaddr addr; + struct sockaddr *sockaddr; + size_t sockaddr_size; int socket; WSBool listening; HttpSSL *ssl; @@ -143,7 +158,15 @@ void http_listener_set_next(HttpListener *listener, HttpListener *next); /* + * Connect to the listener's server socket + * Returns a file descriptor or -1 + */ +int http_listener_connect(HttpListener *listener, WSBool ipv6); + +/* * shutdown all acceptor threads + * this should be called, before any new acceptors for the same socket + * are started */ void http_listener_shutdown_acceptors(HttpListener *listener);