]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-client: allow to set socket fd externally
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 27 Apr 2026 05:31:10 +0000 (14:31 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 16 May 2026 19:13:47 +0000 (04:13 +0900)
It will be used by the unit test and fuzzer for the DHCP client.
Preparation for later changes.

src/libsystemd-network/dhcp-client-internal.h
src/libsystemd-network/dhcp-client-send.c
src/libsystemd-network/sd-dhcp-client.c

index 9e4d0dac8657f58049c3c90d5398c1ae14d76b04..ccae831284326e541a0d02aff77b050b804530bf 100644 (file)
@@ -30,6 +30,8 @@ DECLARE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_state, DHCPState);
 struct sd_dhcp_client {
         unsigned n_ref;
 
+        int socket_fd; /* socket fd set externally, used by unit tests */
+
         DHCPState state;
         sd_event *event;
         int event_priority;
index a77f3c2ae70f9bbcb8463c0a98a3c4565f42d928..5fe804db60fc9a7ca0afc5b39f772e3a3a442e78 100644 (file)
@@ -20,6 +20,10 @@ static int client_get_socket(sd_dhcp_client *client, int domain) {
         assert(client);
         assert(IN_SET(domain, AF_PACKET, AF_INET));
 
+        /* When a socket fd is given externally, unconditionally use it. */
+        if (client->socket_fd >= 0)
+                return client->socket_fd;
+
         if (!client->receive_message)
                 return -EBADF;
 
@@ -50,6 +54,12 @@ static int client_setup_io_event(
         assert(callback);
         assert(description);
 
+        /* When the socket fd is given externally, the fd is used for both UDP and RAW packet operations.
+         * Hence, first we need to disable the previous event source, otherwise sd_event_add_io() will fail
+         * with -EEXIST. */
+        if (fd == client->socket_fd)
+                client->receive_message = sd_event_source_disable_unref(client->receive_message);
+
         _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
         r = sd_event_add_io(client->event, &s, fd, EPOLLIN, callback, client);
         if (r < 0)
@@ -63,9 +73,14 @@ static int client_setup_io_event(
         if (r < 0)
                 return r;
 
-        r = sd_event_source_set_io_fd_own(s, true);
-        if (r < 0)
-                return r;
+        /* When the socket fd is given externally, do not close it while we are running. The IO event source
+         * is freed when not necessary, hence the lifetime of the socket fd should not be tied to the one of
+         * the event source in that case. */
+        if (fd != client->socket_fd) {
+                r = sd_event_source_set_io_fd_own(s, true);
+                if (r < 0)
+                        return r;
+        }
 
         sd_event_source_disable_unref(client->receive_message);
         client->receive_message = TAKE_PTR(s);
@@ -143,7 +158,7 @@ static int client_send_raw(
                 return 0;
         }
 
-        if (fd_close < 0)
+        if (fd_close < 0 && fd != client->socket_fd)
                 return 0; /* Already opened socket is reused. Not necessary to setup new IO event source. */
 
         r = client_setup_io_event(client, fd, client_receive_message_raw, "dhcp4-receive-message-raw");
@@ -200,7 +215,7 @@ static int client_send_udp(
                 return 0;
         }
 
-        if (fd_close < 0)
+        if (fd_close < 0 && fd != client->socket_fd)
                 return 0; /* Already opened socket is reused. Not necessary to setup new IO event source. */
 
         r = client_setup_io_event(client, fd, client_receive_message_udp, "dhcp4-receive-message-udp");
index 5b17a56a4d79bede4315124c5f450db53603ed28..d94e6057d5a4382083a16a86a58e3c1c553b57a5 100644 (file)
@@ -15,6 +15,7 @@
 #include "dns-domain.h"
 #include "errno-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "hostname-util.h"
 #include "iovec-util.h"
 #include "iovec-wrapper.h"
@@ -1387,6 +1388,8 @@ static sd_dhcp_client* dhcp_client_free(sd_dhcp_client *client) {
 
         client_initialize(client);
 
+        safe_close(client->socket_fd);
+
         sd_event_source_unref(client->timeout_resend);
         sd_event_source_unref(client->timeout_t1);
         sd_event_source_unref(client->timeout_t2);
@@ -1420,6 +1423,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
 
         *client = (sd_dhcp_client) {
                 .n_ref = 1,
+                .socket_fd = -EBADF,
                 .state = DHCP_STATE_STOPPED,
                 .ifindex = -1,
                 .port = DHCP_PORT_CLIENT,