sd-dhcp6-client: Fix DHCPv6 client file descriptor handling
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Tue, 23 Jan 2018 10:34:31 +0000 (12:34 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 23 Jan 2018 12:42:12 +0000 (13:42 +0100)
The DHCPv6 client will set its state to DHCP6_STATE_STOPPED if
an error occurs or when receiving an Information Reply DHCPv6
message. Once in DHCP6_STATE_STOPPED, the DHCPv6 client needs
to be restarted by calling sd_dhcp6_client_start().

As of pull request #7796 client_reset() no longer closes the
network socket, thus a call to sd_dhcp6_client_start() needs to
check whether the file descriptor already exists in order not to
create a new one. Likewise, a call to sd_dhcp6_client_unref()
must now close the network socket as client_reset() is not
closing it.

Reported by asavah and Yu Watanabe.

src/libsystemd-network/sd-dhcp6-client.c

index a8ad8eb..ec34843 100644 (file)
@@ -1353,17 +1353,19 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
         if (r < 0)
                 return r;
 
-        r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
-        if (r < 0) {
-                _cleanup_free_ char *p = NULL;
+        if (client->fd < 0) {
+                r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address);
+                if (r < 0) {
+                        _cleanup_free_ char *p = NULL;
+
+                        (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
+                        return log_dhcp6_client_errno(client, r,
+                                                      "Failed to bind to UDP socket at address %s: %m", strna(p));
+                }
 
-                (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
-                return log_dhcp6_client_errno(client, r,
-                                              "Failed to bind to UDP socket at address %s: %m", strna(p));
+                client->fd = r;
         }
 
-        client->fd = r;
-
         if (client->information_request)
                 state = DHCP6_STATE_INFORMATION_REQUEST;
 
@@ -1431,6 +1433,8 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
 
         client_reset(client);
 
+        client->fd = safe_close(client->fd);
+
         sd_dhcp6_client_detach_event(client);
 
         free(client->req_opts);