From patchwork Wed Jan 11 22:13:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew John Cheetham X-Patchwork-Id: 13097280 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0924C5479D for ; Wed, 11 Jan 2023 22:13:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234866AbjAKWNT (ORCPT ); Wed, 11 Jan 2023 17:13:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235894AbjAKWNQ (ORCPT ); Wed, 11 Jan 2023 17:13:16 -0500 Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B56636337 for ; Wed, 11 Jan 2023 14:13:15 -0800 (PST) Received: by mail-wm1-x330.google.com with SMTP id k22-20020a05600c1c9600b003d1ee3a6289so13740557wms.2 for ; Wed, 11 Jan 2023 14:13:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=qZfvZ8RTcDBAofAevq0+3MPqq1v9AIkhChP91QQElkQ=; b=bdRspmaPhoB6Ye3Y5Lgabn4ax77jKUz6Jxv0HUBr1GgQFqwSB6m3glf9+oTKXjpsD3 aosy4OyUeYQS8oFSaI5GzdDbSd4V/RCe9fmx7ad3clpJs3m+svj7TfNxijwOOK3zGEI1 ystcJII7KkoHchgHxgzM30Hl8o0P0UzHcRPJeWQVaccLRb2zvlEDVmmNhwbizJnroGD9 G9m8z8vAPiyssA18ebBAS0f7n7tlX6tqDdgegDHngEr/GXuZpMj9SIIgqQezZaRJSNu9 gbANYNNN911KabMaXfr6ifidoX1QvVsaXdKAbLOqHIH4YVEBSZuAny4UJuE+x3AkNkOj ar2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qZfvZ8RTcDBAofAevq0+3MPqq1v9AIkhChP91QQElkQ=; b=t1xh+kdPwHKQ0qODHzHq8cyeQYgvavj8kRwdSoIgzTkxcVP9OIttq8L5r+lnriEJkY 3zS0Vr09eqgoQsqxlktR5dGR27V97W034XJ1dQxUGuFS+epRFRSmMmYLiN1fn8xb+gqr P5SH4v3ys2dcUzfpaann0yCCNAzYFb687WOGnRxJnUU4Qp2oqneHs+mffOqN52zpDEVI CHCZVTPmO64c/uhv3iA4ThzCGmMsedO8a7tY0un+r7XFkjbU3Qmaj4MLFZTpU46WtKfI ganFu4ik664JlZ9b11SxSeUUGZeXtj1emfT83hjtWpymDccEneFvbUy5Ek4WxisBMmde dfOQ== X-Gm-Message-State: AFqh2koAhSRVel8DHLU0hL79NkJYX4QNWbpI5EXct6meEwOqvvwPW0cn 5qwj2nEIL2tMsFJ+Qlwqt3P0gMUJ+9Q= X-Google-Smtp-Source: AMrXdXuQRZgZvWu8JWKXg/RepOsfpvmIAodeN6ms3NuCZP11YLKZRxbWVaoxtCQ3SrCrkzJlF5regQ== X-Received: by 2002:a05:600c:6016:b0:3d3:3c93:af5e with SMTP id az22-20020a05600c601600b003d33c93af5emr54130252wmb.35.1673475193434; Wed, 11 Jan 2023 14:13:13 -0800 (PST) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id m18-20020a05600c4f5200b003c6b70a4d69sm22415101wmq.42.2023.01.11.14.13.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Jan 2023 14:13:13 -0800 (PST) Message-Id: <74b0de14185120c9d53d7470e59f57fa20a1927f.1673475190.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Wed, 11 Jan 2023 22:13:01 +0000 Subject: [PATCH v5 01/10] daemon: libify socket setup and option functions Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Lessley Dennington , Matthew John Cheetham , M Hickford , Jeff Hostetler , Glen Choo , Victoria Dye , Matthew John Cheetham , Matthew John Cheetham Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Matthew John Cheetham From: Matthew John Cheetham Extract functions for setting up listening sockets and keep-alive options from `daemon.c` to new `daemon-utils.{c,h}` files. Remove direct dependencies on global state by inlining the behaviour at the callsites for all libified functions. Signed-off-by: Matthew John Cheetham --- Makefile | 1 + daemon-utils.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++ daemon-utils.h | 23 ++++++ daemon.c | 214 +------------------------------------------------ 4 files changed, 237 insertions(+), 210 deletions(-) create mode 100644 daemon-utils.c create mode 100644 daemon-utils.h diff --git a/Makefile b/Makefile index b258fdbed86..2654094dbb5 100644 --- a/Makefile +++ b/Makefile @@ -1003,6 +1003,7 @@ LIB_OBJS += credential.o LIB_OBJS += csum-file.o LIB_OBJS += ctype.o LIB_OBJS += date.o +LIB_OBJS += daemon-utils.o LIB_OBJS += decorate.o LIB_OBJS += delta-islands.o LIB_OBJS += diagnose.o diff --git a/daemon-utils.c b/daemon-utils.c new file mode 100644 index 00000000000..b96b55962db --- /dev/null +++ b/daemon-utils.c @@ -0,0 +1,209 @@ +#include "cache.h" +#include "daemon-utils.h" + +void set_keep_alive(int sockfd, log_fn logerror) +{ + int ka = 1; + + if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0) { + if (errno != ENOTSOCK) + logerror("unable to set SO_KEEPALIVE on socket: %s", + strerror(errno)); + } +} + +static int set_reuse_addr(int sockfd) +{ + int on = 1; + + return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)); +} + +static const char *ip2str(int family, struct sockaddr *sin, socklen_t len) +{ +#ifdef NO_IPV6 + static char ip[INET_ADDRSTRLEN]; +#else + static char ip[INET6_ADDRSTRLEN]; +#endif + + switch (family) { +#ifndef NO_IPV6 + case AF_INET6: + inet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len); + break; +#endif + case AF_INET: + inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len); + break; + default: + xsnprintf(ip, sizeof(ip), ""); + } + return ip; +} + +#ifndef NO_IPV6 + +static int setup_named_sock(char *listen_addr, int listen_port, + struct socketlist *socklist, int reuseaddr, + log_fn logerror) +{ + int socknum = 0; + char pbuf[NI_MAXSERV]; + struct addrinfo hints, *ai0, *ai; + int gai; + long flags; + + xsnprintf(pbuf, sizeof(pbuf), "%d", listen_port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); + if (gai) { + logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai)); + return 0; + } + + for (ai = ai0; ai; ai = ai->ai_next) { + int sockfd; + + sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sockfd < 0) + continue; + if (sockfd >= FD_SETSIZE) { + logerror("Socket descriptor too large"); + close(sockfd); + continue; + } + +#ifdef IPV6_V6ONLY + if (ai->ai_family == AF_INET6) { + int on = 1; + setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, + &on, sizeof(on)); + /* Note: error is not fatal */ + } +#endif + + if (reuseaddr && set_reuse_addr(sockfd)) { + logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); + close(sockfd); + continue; + } + + set_keep_alive(sockfd, logerror); + + if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { + logerror("Could not bind to %s: %s", + ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), + strerror(errno)); + close(sockfd); + continue; /* not fatal */ + } + if (listen(sockfd, 5) < 0) { + logerror("Could not listen to %s: %s", + ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), + strerror(errno)); + close(sockfd); + continue; /* not fatal */ + } + + flags = fcntl(sockfd, F_GETFD, 0); + if (flags >= 0) + fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); + + ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); + socklist->list[socklist->nr++] = sockfd; + socknum++; + } + + freeaddrinfo(ai0); + + return socknum; +} + +#else /* NO_IPV6 */ + +static int setup_named_sock(char *listen_addr, int listen_port, + struct socketlist *socklist, int reuseaddr, + log_fn logerror) +{ + struct sockaddr_in sin; + int sockfd; + long flags; + + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(listen_port); + + if (listen_addr) { + /* Well, host better be an IP address here. */ + if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) + return 0; + } else { + sin.sin_addr.s_addr = htonl(INADDR_ANY); + } + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + return 0; + + if (reuseaddr && set_reuse_addr(sockfd)) { + logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); + close(sockfd); + return 0; + } + + set_keep_alive(sockfd, logerror); + + if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) { + logerror("Could not bind to %s: %s", + ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), + strerror(errno)); + close(sockfd); + return 0; + } + + if (listen(sockfd, 5) < 0) { + logerror("Could not listen to %s: %s", + ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), + strerror(errno)); + close(sockfd); + return 0; + } + + flags = fcntl(sockfd, F_GETFD, 0); + if (flags >= 0) + fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); + + ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); + socklist->list[socklist->nr++] = sockfd; + return 1; +} + +#endif + +void socksetup(struct string_list *listen_addr, int listen_port, + struct socketlist *socklist, int reuseaddr, + log_fn logerror) +{ + if (!listen_addr->nr) + setup_named_sock(NULL, listen_port, socklist, reuseaddr, + logerror); + else { + int i, socknum; + for (i = 0; i < listen_addr->nr; i++) { + socknum = setup_named_sock(listen_addr->items[i].string, + listen_port, socklist, reuseaddr, + logerror); + + if (socknum == 0) + logerror("unable to allocate any listen sockets for host %s on port %u", + listen_addr->items[i].string, listen_port); + } + } +} diff --git a/daemon-utils.h b/daemon-utils.h new file mode 100644 index 00000000000..6710a2a6dc0 --- /dev/null +++ b/daemon-utils.h @@ -0,0 +1,23 @@ +#ifndef DAEMON_UTILS_H +#define DAEMON_UTILS_H + +#include "git-compat-util.h" +#include "string-list.h" + +typedef void (*log_fn)(const char *msg, ...); + +struct socketlist { + int *list; + size_t nr; + size_t alloc; +}; + +/* Enable sending of keep-alive messages on the socket. */ +void set_keep_alive(int sockfd, log_fn logerror); + +/* Setup a number of sockets to listen on the provided addresses. */ +void socksetup(struct string_list *listen_addr, int listen_port, + struct socketlist *socklist, int reuseaddr, + log_fn logerror); + +#endif diff --git a/daemon.c b/daemon.c index 0ae7d12b5c1..1ed4e705680 100644 --- a/daemon.c +++ b/daemon.c @@ -1,9 +1,9 @@ #include "cache.h" #include "config.h" +#include "daemon-utils.h" #include "pkt-line.h" #include "run-command.h" #include "strbuf.h" -#include "string-list.h" #ifdef NO_INITGROUPS #define initgroups(x, y) (0) /* nothing */ @@ -737,17 +737,6 @@ static void hostinfo_clear(struct hostinfo *hi) strbuf_release(&hi->tcp_port); } -static void set_keep_alive(int sockfd) -{ - int ka = 1; - - if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0) { - if (errno != ENOTSOCK) - logerror("unable to set SO_KEEPALIVE on socket: %s", - strerror(errno)); - } -} - static int execute(void) { char *line = packet_buffer; @@ -759,7 +748,7 @@ static int execute(void) if (addr) loginfo("Connection from %s:%s", addr, port); - set_keep_alive(0); + set_keep_alive(0, logerror); alarm(init_timeout ? init_timeout : timeout); pktlen = packet_read(0, packet_buffer, sizeof(packet_buffer), 0); alarm(0); @@ -938,202 +927,6 @@ static void child_handler(int signo) signal(SIGCHLD, child_handler); } -static int set_reuse_addr(int sockfd) -{ - int on = 1; - - if (!reuseaddr) - return 0; - return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - &on, sizeof(on)); -} - -struct socketlist { - int *list; - size_t nr; - size_t alloc; -}; - -static const char *ip2str(int family, struct sockaddr *sin, socklen_t len) -{ -#ifdef NO_IPV6 - static char ip[INET_ADDRSTRLEN]; -#else - static char ip[INET6_ADDRSTRLEN]; -#endif - - switch (family) { -#ifndef NO_IPV6 - case AF_INET6: - inet_ntop(family, &((struct sockaddr_in6*)sin)->sin6_addr, ip, len); - break; -#endif - case AF_INET: - inet_ntop(family, &((struct sockaddr_in*)sin)->sin_addr, ip, len); - break; - default: - xsnprintf(ip, sizeof(ip), ""); - } - return ip; -} - -#ifndef NO_IPV6 - -static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist) -{ - int socknum = 0; - char pbuf[NI_MAXSERV]; - struct addrinfo hints, *ai0, *ai; - int gai; - long flags; - - xsnprintf(pbuf, sizeof(pbuf), "%d", listen_port); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE; - - gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); - if (gai) { - logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai)); - return 0; - } - - for (ai = ai0; ai; ai = ai->ai_next) { - int sockfd; - - sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sockfd < 0) - continue; - if (sockfd >= FD_SETSIZE) { - logerror("Socket descriptor too large"); - close(sockfd); - continue; - } - -#ifdef IPV6_V6ONLY - if (ai->ai_family == AF_INET6) { - int on = 1; - setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, - &on, sizeof(on)); - /* Note: error is not fatal */ - } -#endif - - if (set_reuse_addr(sockfd)) { - logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); - close(sockfd); - continue; - } - - set_keep_alive(sockfd); - - if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { - logerror("Could not bind to %s: %s", - ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), - strerror(errno)); - close(sockfd); - continue; /* not fatal */ - } - if (listen(sockfd, 5) < 0) { - logerror("Could not listen to %s: %s", - ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), - strerror(errno)); - close(sockfd); - continue; /* not fatal */ - } - - flags = fcntl(sockfd, F_GETFD, 0); - if (flags >= 0) - fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); - - ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); - socklist->list[socklist->nr++] = sockfd; - socknum++; - } - - freeaddrinfo(ai0); - - return socknum; -} - -#else /* NO_IPV6 */ - -static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist) -{ - struct sockaddr_in sin; - int sockfd; - long flags; - - memset(&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_port = htons(listen_port); - - if (listen_addr) { - /* Well, host better be an IP address here. */ - if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) - return 0; - } else { - sin.sin_addr.s_addr = htonl(INADDR_ANY); - } - - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) - return 0; - - if (set_reuse_addr(sockfd)) { - logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); - close(sockfd); - return 0; - } - - set_keep_alive(sockfd); - - if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) { - logerror("Could not bind to %s: %s", - ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), - strerror(errno)); - close(sockfd); - return 0; - } - - if (listen(sockfd, 5) < 0) { - logerror("Could not listen to %s: %s", - ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), - strerror(errno)); - close(sockfd); - return 0; - } - - flags = fcntl(sockfd, F_GETFD, 0); - if (flags >= 0) - fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); - - ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); - socklist->list[socklist->nr++] = sockfd; - return 1; -} - -#endif - -static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist) -{ - if (!listen_addr->nr) - setup_named_sock(NULL, listen_port, socklist); - else { - int i, socknum; - for (i = 0; i < listen_addr->nr; i++) { - socknum = setup_named_sock(listen_addr->items[i].string, - listen_port, socklist); - - if (socknum == 0) - logerror("unable to allocate any listen sockets for host %s on port %u", - listen_addr->items[i].string, listen_port); - } - } -} - static int service_loop(struct socketlist *socklist) { struct pollfd *pfd; @@ -1246,7 +1039,8 @@ static int serve(struct string_list *listen_addr, int listen_port, { struct socketlist socklist = { NULL, 0, 0 }; - socksetup(listen_addr, listen_port, &socklist); + socksetup(listen_addr, listen_port, &socklist, reuseaddr, + logerror); if (socklist.nr == 0) die("unable to allocate any listen sockets on port %u", listen_port);