]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/socket.c
core: move pid watch/unwatch logic of the service manager to pidfd
[thirdparty/systemd.git] / src / core / socket.c
index 05a5e31be9801a8faa59a7f740f85e4cc978bce5..e5b2e8ae762ac2bddc8618323372b00609d6b508 100644 (file)
@@ -83,7 +83,7 @@ static void socket_init(Unit *u) {
         assert(u->load_state == UNIT_STUB);
 
         s->backlog = SOMAXCONN_DELUXE;
-        s->timeout_usec = u->manager->default_timeout_start_usec;
+        s->timeout_usec = u->manager->defaults.timeout_start_usec;
         s->directory_mode = 0755;
         s->socket_mode = 0666;
 
@@ -94,22 +94,27 @@ static void socket_init(Unit *u) {
         s->ip_ttl = -1;
         s->mark = -1;
 
-        s->exec_context.std_output = u->manager->default_std_output;
-        s->exec_context.std_error = u->manager->default_std_error;
+        s->exec_context.std_output = u->manager->defaults.std_output;
+        s->exec_context.std_error = u->manager->defaults.std_error;
 
+        s->control_pid = PIDREF_NULL;
         s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
 
         s->trigger_limit.interval = USEC_INFINITY;
         s->trigger_limit.burst = UINT_MAX;
+
+        s->poll_limit_interval = USEC_INFINITY;
+        s->poll_limit_burst = UINT_MAX;
 }
 
 static void socket_unwatch_control_pid(Socket *s) {
         assert(s);
 
-        if (s->control_pid <= 0)
+        if (!pidref_is_set(&s->control_pid))
                 return;
 
-        unit_unwatch_pid(UNIT(s), TAKE_PID(s->control_pid));
+        unit_unwatch_pidref(UNIT(s), &s->control_pid);
+        pidref_done(&s->control_pid);
 }
 
 static void socket_cleanup_fd_list(SocketPort *p) {
@@ -134,14 +139,9 @@ SocketPort *socket_port_free(SocketPort *p) {
 }
 
 void socket_free_ports(Socket *s) {
-        SocketPort *p;
-
         assert(s);
 
-        while ((p = s->ports)) {
-                LIST_REMOVE(port, s->ports, p);
-                socket_port_free(p);
-        }
+        LIST_CLEAR(port, s->ports, socket_port_free);
 }
 
 static void socket_done(Unit *u) {
@@ -182,34 +182,10 @@ static void socket_done(Unit *u) {
         s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
 }
 
-static int socket_arm_timer(Socket *s, usec_t usec) {
-        int r;
-
+static int socket_arm_timer(Socket *s, bool relative, usec_t usec) {
         assert(s);
 
-        if (s->timer_event_source) {
-                r = sd_event_source_set_time(s->timer_event_source, usec);
-                if (r < 0)
-                        return r;
-
-                return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
-        }
-
-        if (usec == USEC_INFINITY)
-                return 0;
-
-        r = sd_event_add_time(
-                        UNIT(s)->manager->event,
-                        &s->timer_event_source,
-                        CLOCK_MONOTONIC,
-                        usec, 0,
-                        socket_dispatch_timer, s);
-        if (r < 0)
-                return r;
-
-        (void) sd_event_source_set_description(s->timer_event_source, "socket-timer");
-
-        return 0;
+        return unit_arm_timer(UNIT(s), &s->timer_event_source, relative, usec, socket_dispatch_timer);
 }
 
 static bool have_non_accept_socket(Socket *s) {
@@ -278,27 +254,15 @@ static int socket_add_default_dependencies(Socket *s) {
                 return r;
 
         if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
-                r = unit_add_two_dependencies_by_name(UNIT(s),
-                                UNIT_AFTER,
-                                UNIT(s)->ignore_on_soft_reboot ? -EINVAL : UNIT_REQUIRES,
-                                SPECIAL_SYSINIT_TARGET,
-                                true,
-                                UNIT_DEPENDENCY_DEFAULT);
+                r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
                 if (r < 0)
                         return r;
         }
 
-        if (!UNIT(s)->ignore_on_soft_reboot)
-                return unit_add_two_dependencies_by_name(
-                                UNIT(s),
-                                UNIT_BEFORE, UNIT_CONFLICTS,
-                                SPECIAL_SHUTDOWN_TARGET, true,
-                                UNIT_DEPENDENCY_DEFAULT);
-
-        return unit_add_dependencies_on_real_shutdown_targets(UNIT(s));
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
 }
 
-_pure_ static bool socket_has_exec(Socket *s) {
+static bool socket_has_exec(Socket *s) {
         unsigned i;
         assert(s);
 
@@ -322,17 +286,20 @@ static int socket_add_extras(Socket *s) {
          * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to
          * process whatever is queued in one go, and thus should normally never have to be started frequently. This is
          * different for Accept=yes where each connection is processed by a new service instance, and thus frequent
-         * service starts are typical. */
+         * service starts are typical.
+         *
+         * For the poll limit we follow a similar rule, but use 3/4th of the trigger limit parameters, to
+         * trigger this earlier. */
 
         if (s->trigger_limit.interval == USEC_INFINITY)
                 s->trigger_limit.interval = 2 * USEC_PER_SEC;
+        if (s->trigger_limit.burst == UINT_MAX)
+                s->trigger_limit.burst = s->accept ? 200 : 20;
 
-        if (s->trigger_limit.burst == UINT_MAX) {
-                if (s->accept)
-                        s->trigger_limit.burst = 200;
-                else
-                        s->trigger_limit.burst = 20;
-        }
+        if (s->poll_limit_interval == USEC_INFINITY)
+                s->poll_limit_interval = 2 * USEC_PER_SEC;
+        if (s->poll_limit_burst == UINT_MAX)
+                s->poll_limit_burst = s->accept ? 150 : 15;
 
         if (have_non_accept_socket(s)) {
 
@@ -515,7 +482,7 @@ static SocketPeer *socket_peer_free(SocketPeer *p) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(SocketPeer, socket_peer, socket_peer_free);
 
-int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
+int socket_acquire_peer(Socket *s, int fd, SocketPeer **ret) {
         _cleanup_(socket_peer_unrefp) SocketPeer *remote = NULL;
         SocketPeer sa = {
                 .peer_salen = sizeof(union sockaddr_union),
@@ -524,22 +491,19 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
 
         assert(fd >= 0);
         assert(s);
+        assert(ret);
 
         if (getpeername(fd, &sa.peer.sa, &sa.peer_salen) < 0)
-                return log_unit_error_errno(UNIT(s), errno, "getpeername failed: %m");
+                return log_unit_error_errno(UNIT(s), errno, "getpeername() failed: %m");
 
         if (!IN_SET(sa.peer.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) {
-                *p = NULL;
+                *ret = NULL;
                 return 0;
         }
 
-        r = set_ensure_allocated(&s->peers_by_address, &peer_address_hash_ops);
-        if (r < 0)
-                return r;
-
         i = set_get(s->peers_by_address, &sa);
         if (i) {
-                *p = socket_peer_ref(i);
+                *ret = socket_peer_ref(i);
                 return 1;
         }
 
@@ -550,17 +514,17 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
         remote->peer = sa.peer;
         remote->peer_salen = sa.peer_salen;
 
-        r = set_put(s->peers_by_address, remote);
+        r = set_ensure_put(&s->peers_by_address, &peer_address_hash_ops, remote);
         if (r < 0)
-                return r;
+                return log_unit_error_errno(UNIT(s), r, "Failed to insert peer info into hash table: %m");
 
         remote->socket = s;
 
-        *p = TAKE_PTR(remote);
+        *ret = TAKE_PTR(remote);
         return 1;
 }
 
-_const_ static const char* listen_lookup(int family, int type) {
+static const char* listen_lookup(int family, int type) {
 
         if (family == AF_NETLINK)
                 return "ListenNetlink";
@@ -633,10 +597,10 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                         "%sTimestamping: %s\n",
                         prefix, socket_timestamping_to_string(s->timestamping));
 
-        if (s->control_pid > 0)
+        if (pidref_is_set(&s->control_pid))
                 fprintf(f,
                         "%sControl PID: "PID_FMT"\n",
-                        prefix, s->control_pid);
+                        prefix, s->control_pid.pid);
 
         if (s->bind_to_device)
                 fprintf(f,
@@ -782,9 +746,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
 
         fprintf(f,
                 "%sTriggerLimitIntervalSec: %s\n"
-                "%sTriggerLimitBurst: %u\n",
+                "%sTriggerLimitBurst: %u\n"
+                "%sPollLimitIntervalSec: %s\n"
+                "%sPollLimitBurst: %u\n",
                 prefix, FORMAT_TIMESPAN(s->trigger_limit.interval, USEC_PER_SEC),
-                prefix, s->trigger_limit.burst);
+                prefix, s->trigger_limit.burst,
+                prefix, FORMAT_TIMESPAN(s->poll_limit_interval, USEC_PER_SEC),
+                prefix, s->poll_limit_burst);
 
         str = ip_protocol_to_name(s->socket_protocol);
         if (str)
@@ -1367,9 +1335,7 @@ fail:
         p->n_auxiliary_fds = 0;
 
 clear:
-        for (size_t i = 0; i < n; ++i)
-                free(ent[i]);
-
+        free_many((void**) ent, n);
         return r;
 }
 
@@ -1398,14 +1364,15 @@ int socket_load_service_unit(Socket *s, int cfd, Unit **ret) {
 
         if (cfd >= 0) {
                 r = instance_from_socket(cfd, s->n_accepted, &instance);
-                if (ERRNO_IS_DISCONNECT(r))
-                        /* ENOTCONN is legitimate if TCP RST was received. Other socket families might return
-                         * different errors. This connection is over, but the socket unit lives on. */
-                        return log_unit_debug_errno(UNIT(s), r,
-                                                    "Got %s on incoming socket, assuming aborted connection attempt, ignoring.",
-                                                    errno_to_name(r));
-                if (r < 0)
+                if (r < 0) {
+                        if (ERRNO_IS_DISCONNECT(r))
+                                /* ENOTCONN is legitimate if TCP RST was received. Other socket families might return
+                                 * different errors. This connection is over, but the socket unit lives on. */
+                                return log_unit_debug_errno(UNIT(s), r,
+                                                            "Got %s on incoming socket, assuming aborted connection attempt, ignoring.",
+                                                            errno_to_name(r));
                         return r;
+                }
         }
 
         /* For accepting sockets, we don't know how the instance will be called until we get a connection and
@@ -1495,14 +1462,22 @@ static int socket_address_listen_do(
                 log_unit_error_errno(u, error, fmt, strna(_t));  \
         })
 
-static int fork_needed(const SocketAddress *address, const ExecContext *context) {
+static int fork_needed(const SocketAddress *address, Socket *s) {
         int r;
 
         assert(address);
-        assert(context);
+        assert(s);
 
         /* Check if we need to do the cgroup or netns stuff. If not we can do things much simpler. */
 
+        /* If there are any NFTSet= directives with cgroup source, we need the cgroup */
+        Unit *u = UNIT(s);
+        CGroupContext *c = unit_get_cgroup_context(u);
+        if (c)
+                FOREACH_ARRAY(nft_set, c->nft_set_context.sets, c->nft_set_context.n_sets)
+                        if (nft_set->source == NFT_SET_SOURCE_CGROUP)
+                                return true;
+
         if (IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6)) {
                 r = bpf_firewall_supported();
                 if (r < 0)
@@ -1511,7 +1486,7 @@ static int fork_needed(const SocketAddress *address, const ExecContext *context)
                         return true;
         }
 
-        return exec_needs_network_namespace(context);
+        return exec_needs_network_namespace(&s->exec_context);
 }
 
 static int socket_address_listen_in_cgroup(
@@ -1519,9 +1494,9 @@ static int socket_address_listen_in_cgroup(
                 const SocketAddress *address,
                 const char *label) {
 
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         _cleanup_close_pair_ int pair[2] = PIPE_EBADF;
         int fd, r;
-        pid_t pid;
 
         assert(s);
         assert(address);
@@ -1531,7 +1506,7 @@ static int socket_address_listen_in_cgroup(
          * the socket is actually properly attached to the unit's cgroup for the purpose of BPF filtering and
          * such. */
 
-        r = fork_needed(address, &s->exec_context);
+        r = fork_needed(address, s);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -1613,7 +1588,7 @@ static int socket_address_listen_in_cgroup(
         fd = receive_one_fd(pair[0], 0);
 
         /* We synchronously wait for the helper, as it shouldn't be slow */
-        r = wait_for_terminate_and_check("(sd-listen)", pid, WAIT_LOG_ABNORMAL);
+        r = wait_for_terminate_and_check("(sd-listen)", pid.pid, WAIT_LOG_ABNORMAL);
         if (r < 0) {
                 safe_close(fd);
                 return r;
@@ -1777,6 +1752,10 @@ static int socket_watch_fds(Socket *s) {
 
                         (void) sd_event_source_set_description(p->event_source, "socket-port-io");
                 }
+
+                r = sd_event_source_set_ratelimit(p->event_source, s->poll_limit_interval, s->poll_limit_burst);
+                if (r < 0)
+                        log_unit_debug_errno(UNIT(s), r, "Failed to set poll limit on I/O event source, ignoring: %m");
         }
 
         return 0;
@@ -1872,8 +1851,8 @@ static int socket_coldplug(Unit *u) {
         if (s->deserialized_state == s->state)
                 return 0;
 
-        if (s->control_pid > 0 &&
-            pid_is_unwaited(s->control_pid) &&
+        if (pidref_is_set(&s->control_pid) &&
+            pid_is_unwaited(s->control_pid.pid) &&
             IN_SET(s->deserialized_state,
                    SOCKET_START_PRE,
                    SOCKET_START_CHOWN,
@@ -1886,11 +1865,11 @@ static int socket_coldplug(Unit *u) {
                    SOCKET_FINAL_SIGKILL,
                    SOCKET_CLEANING)) {
 
-                r = unit_watch_pid(UNIT(s), s->control_pid, false);
+                r = unit_watch_pidref(UNIT(s), &s->control_pid, /* exclusive= */ false);
                 if (r < 0)
                         return r;
 
-                r = socket_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
+                r = socket_arm_timer(s, /* relative= */ false, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
                 if (r < 0)
                         return r;
         }
@@ -1932,7 +1911,7 @@ static int socket_coldplug(Unit *u) {
         return 0;
 }
 
-static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
+static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
 
         _cleanup_(exec_params_clear) ExecParameters exec_params = {
                 .flags     = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
@@ -1941,18 +1920,19 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
                 .stderr_fd = -EBADF,
                 .exec_fd   = -EBADF,
         };
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         pid_t pid;
         int r;
 
         assert(s);
         assert(c);
-        assert(_pid);
+        assert(ret_pid);
 
         r = unit_prepare_exec(UNIT(s));
         if (r < 0)
                 return r;
 
-        r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
+        r = socket_arm_timer(s, /* relative= */ true, s->timeout_usec);
         if (r < 0)
                 return r;
 
@@ -1970,22 +1950,27 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pid, true);
+        r = pidref_set_pid(&pidref, pid);
         if (r < 0)
                 return r;
 
-        *_pid = pid;
+        r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
+        if (r < 0)
+                return r;
 
+        *ret_pid = TAKE_PIDREF(pidref);
         return 0;
 }
 
-static int socket_chown(Socket *s, pid_t *_pid) {
-        pid_t pid;
+static int socket_chown(Socket *s, PidRef *ret_pid) {
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         int r;
 
-        r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
+        assert(s);
+
+        r = socket_arm_timer(s, /* relative= */ true, s->timeout_usec);
         if (r < 0)
-                goto fail;
+                return r;
 
         /* We have to resolve the user names out-of-process, hence
          * let's fork here. It's messy, but well, what can we do? */
@@ -2039,16 +2024,12 @@ static int socket_chown(Socket *s, pid_t *_pid) {
                 _exit(EXIT_SUCCESS);
         }
 
-        r = unit_watch_pid(UNIT(s), pid, true);
+        r = unit_watch_pidref(UNIT(s), &pid, /* exclusive= */ true);
         if (r < 0)
-                goto fail;
+                return r;
 
-        *_pid = pid;
+        *ret_pid = TAKE_PIDREF(pid);
         return 0;
-
-fail:
-        s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
-        return r;
 }
 
 static void socket_enter_dead(Socket *s, SocketResult f) {
@@ -2087,19 +2068,18 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
         s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST];
 
         if (s->control_command) {
+                pidref_done(&s->control_pid);
+
                 r = socket_spawn(s, s->control_command, &s->control_pid);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-post' task: %m");
+                        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
+                        return;
+                }
 
                 socket_set_state(s, SOCKET_STOP_POST);
         } else
                 socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_SUCCESS);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
-        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
 }
 
 static int state_to_kill_operation(Socket *s, SocketState state) {
@@ -2124,16 +2104,20 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
                         UNIT(s),
                         &s->kill_context,
                         state_to_kill_operation(s, state),
-                        -1,
-                        s->control_pid,
-                        false);
-        if (r < 0)
+                        /* main_pid= */ NULL,
+                        &s->control_pid,
+                        /* main_pid_alien= */ false);
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
                 goto fail;
+        }
 
         if (r > 0) {
-                r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
-                if (r < 0)
+                r = socket_arm_timer(s, /* relative= */ true, s->timeout_usec);
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
                         goto fail;
+                }
 
                 socket_set_state(s, state);
         } else if (state == SOCKET_STOP_PRE_SIGTERM)
@@ -2148,8 +2132,6 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
         return;
 
 fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
-
         if (IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_STOP_PRE_SIGKILL))
                 socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
         else
@@ -2168,19 +2150,18 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
         s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE];
 
         if (s->control_command) {
+                pidref_done(&s->control_pid);
+
                 r = socket_spawn(s, s->control_command, &s->control_pid);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-pre' task: %m");
+                        socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
+                        return;
+                }
 
                 socket_set_state(s, SOCKET_STOP_PRE);
         } else
                 socket_enter_stop_post(s, SOCKET_SUCCESS);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-pre' task: %m");
-        socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
 }
 
 static void socket_enter_listening(Socket *s) {
@@ -2195,14 +2176,11 @@ static void socket_enter_listening(Socket *s) {
         r = socket_watch_fds(s);
         if (r < 0) {
                 log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
-                goto fail;
+                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+                return;
         }
 
         socket_set_state(s, SOCKET_LISTENING);
-        return;
-
-fail:
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
 }
 
 static void socket_enter_start_post(Socket *s) {
@@ -2214,20 +2192,18 @@ static void socket_enter_start_post(Socket *s) {
         s->control_command = s->exec_command[SOCKET_EXEC_START_POST];
 
         if (s->control_command) {
+                pidref_done(&s->control_pid);
+
                 r = socket_spawn(s, s->control_command, &s->control_pid);
                 if (r < 0) {
-                        log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-post' task: %m");
-                        goto fail;
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-post' task: %m");
+                        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+                        return;
                 }
 
                 socket_set_state(s, SOCKET_START_POST);
         } else
                 socket_enter_listening(s);
-
-        return;
-
-fail:
-        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
 }
 
 static void socket_enter_start_chown(Socket *s) {
@@ -2249,7 +2225,7 @@ static void socket_enter_start_chown(Socket *s) {
 
                 r = socket_chown(s, &s->control_pid);
                 if (r < 0) {
-                        log_unit_warning_errno(UNIT(s), r, "Failed to fork 'start-chown' task: %m");
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-chown' task: %m");
                         goto fail;
                 }
 
@@ -2275,20 +2251,18 @@ static void socket_enter_start_pre(Socket *s) {
         s->control_command = s->exec_command[SOCKET_EXEC_START_PRE];
 
         if (s->control_command) {
+                pidref_done(&s->control_pid);
+
                 r = socket_spawn(s, s->control_command, &s->control_pid);
                 if (r < 0) {
-                        log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-pre' task: %m");
-                        goto fail;
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-pre' task: %m");
+                        socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
+                        return;
                 }
 
                 socket_set_state(s, SOCKET_START_PRE);
         } else
                 socket_enter_start_chown(s);
-
-        return;
-
-fail:
-        socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
 }
 
 static void flush_ports(Socket *s) {
@@ -2334,7 +2308,7 @@ static void socket_enter_running(Socket *s, int cfd_in) {
                 goto refuse;
         }
 
-        if (cfd < 0) {
+        if (cfd < 0) { /* Accept=no case */
                 bool pending = false;
                 Unit *other;
 
@@ -2347,18 +2321,18 @@ static void socket_enter_running(Socket *s, int cfd_in) {
 
                 if (!pending) {
                         if (!UNIT_ISSET(s->service)) {
-                                r = log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
-                                                         "Service to activate vanished, refusing activation.");
+                                r = log_unit_warning_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
+                                                           "Service to activate vanished, refusing activation.");
                                 goto fail;
                         }
 
                         r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, NULL, &error, NULL);
                         if (r < 0)
-                                goto fail;
+                                goto queue_error;
                 }
 
                 socket_set_state(s, SOCKET_RUNNING);
-        } else {
+        } else { /* Accept=yes case */
                 _cleanup_(socket_peer_unrefp) SocketPeer *p = NULL;
                 Unit *service;
 
@@ -2389,23 +2363,31 @@ static void socket_enter_running(Socket *s, int cfd_in) {
                 }
 
                 r = socket_load_service_unit(s, cfd, &service);
-                if (ERRNO_IS_DISCONNECT(r))
-                        return;
-                if (r < 0)
+                if (r < 0) {
+                        if (ERRNO_IS_DISCONNECT(r))
+                                return;
+
+                        log_unit_warning_errno(UNIT(s), r, "Failed to load connection service unit: %m");
                         goto fail;
+                }
 
                 r = unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
                                               false, UNIT_DEPENDENCY_IMPLICIT);
-                if (r < 0)
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to add Before=/Triggers= dependencies on connection unit: %m");
                         goto fail;
+                }
 
                 s->n_accepted++;
 
                 r = service_set_socket_fd(SERVICE(service), cfd, s, p, s->selinux_context_from_net);
-                if (ERRNO_IS_DISCONNECT(r))
-                        return;
-                if (r < 0)
+                if (r < 0) {
+                        if (ERRNO_IS_DISCONNECT(r))
+                                return;
+
+                        log_unit_warning_errno(UNIT(s), r, "Failed to set socket on service: %m");
                         goto fail;
+                }
 
                 TAKE_FD(cfd); /* We passed ownership of the fd to the service now. Forget it here. */
                 s->n_connections++;
@@ -2415,21 +2397,20 @@ static void socket_enter_running(Socket *s, int cfd_in) {
                         /* We failed to activate the new service, but it still exists. Let's make sure the
                          * service closes and forgets the connection fd again, immediately. */
                         service_release_socket_fd(SERVICE(service));
-                        goto fail;
+                        goto queue_error;
                 }
 
                 /* Notify clients about changed counters */
                 unit_add_to_dbus_queue(UNIT(s));
         }
 
-        TAKE_FD(cfd);
         return;
 
 refuse:
         s->n_refused++;
         return;
 
-fail:
+queue_error:
         if (ERRNO_IS_RESOURCE(r))
                 log_unit_warning(UNIT(s), "Failed to queue service startup job: %s",
                                  bus_error_message(&error, r));
@@ -2438,6 +2419,7 @@ fail:
                                  cfd >= 0 ? "template" : "non-template",
                                  bus_error_message(&error, r));
 
+fail:
         socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
 }
 
@@ -2452,21 +2434,19 @@ static void socket_run_next(Socket *s) {
 
         s->control_command = s->control_command->command_next;
 
-        r = socket_spawn(s, s->control_command, &s->control_pid);
-        if (r < 0)
-                goto fail;
-
-        return;
+        pidref_done(&s->control_pid);
 
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run next task: %m");
+        r = socket_spawn(s, s->control_command, &s->control_pid);
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to spawn next task: %m");
 
-        if (s->state == SOCKET_START_POST)
-                socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-        else if (s->state == SOCKET_STOP_POST)
-                socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-        else
-                socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
+                if (s->state == SOCKET_START_POST)
+                        socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
+                else if (s->state == SOCKET_STOP_POST)
+                        socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
+                else
+                        socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
+        }
 }
 
 static int socket_start(Unit *u) {
@@ -2501,12 +2481,16 @@ static int socket_start(Unit *u) {
                 service = SERVICE(UNIT_DEREF(s->service));
 
                 if (UNIT(service)->load_state != UNIT_LOADED)
-                        return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Socket service %s not loaded, refusing.", UNIT(service)->id);
+                        return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT),
+                                                    "Socket service %s not loaded, refusing.", UNIT(service)->id);
 
                 /* If the service is already active we cannot start the
                  * socket */
-                if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
-                        return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY), "Socket service %s already active, refusing.", UNIT(service)->id);
+                if (!IN_SET(service->state,
+                            SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
+                            SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART_QUEUED))
+                        return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY),
+                                                    "Socket service %s already active, refusing.", UNIT(service)->id);
         }
 
         assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
@@ -2574,8 +2558,8 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
         (void) serialize_item_format(f, "n-accepted", "%u", s->n_accepted);
         (void) serialize_item_format(f, "n-refused", "%u", s->n_refused);
 
-        if (s->control_pid > 0)
-                (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid);
+        if (pidref_is_set(&s->control_pid))
+                (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid);
 
         if (s->control_command_id >= 0)
                 (void) serialize_item(f, "control-command", socket_exec_command_to_string(s->control_command_id));
@@ -2656,12 +2640,10 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
                 else
                         s->n_refused += k;
         } else if (streq(key, "control-pid")) {
-                pid_t pid;
-
-                if (parse_pid(value, &pid) < 0)
-                        log_unit_debug(u, "Failed to parse control-pid value: %s", value);
-                else
-                        s->control_pid = pid;
+                pidref_done(&s->control_pid);
+                r = pidref_set_pidstr(&s->control_pid, value);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to pin control PID '%s', ignoring: %m", value);
         } else if (streq(key, "control-command")) {
                 SocketExecCommand id;
 
@@ -2880,13 +2862,13 @@ static void socket_distribute_fds(Unit *u, FDSet *fds) {
         }
 }
 
-_pure_ static UnitActiveState socket_active_state(Unit *u) {
+static UnitActiveState socket_active_state(Unit *u) {
         assert(u);
 
         return state_translation_table[SOCKET(u)->state];
 }
 
-_pure_ static const char *socket_sub_state_to_string(Unit *u) {
+static const char *socket_sub_state_to_string(Unit *u) {
         assert(u);
 
         return socket_state_to_string(SOCKET(u)->state);
@@ -2954,7 +2936,7 @@ SocketType socket_port_type_from_string(const char *s) {
                 return _SOCKET_TYPE_INVALID;
 }
 
-_pure_ static bool socket_may_gc(Unit *u) {
+static bool socket_may_gc(Unit *u) {
         Socket *s = SOCKET(u);
 
         assert(u);
@@ -2977,9 +2959,9 @@ static int socket_accept_do(Socket *s, int fd) {
 }
 
 static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         _cleanup_close_pair_ int pair[2] = PIPE_EBADF;
         int cfd, r;
-        pid_t pid;
 
         assert(s);
         assert(p);
@@ -3029,7 +3011,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
         cfd = receive_one_fd(pair[0], 0);
 
         /* We synchronously wait for the helper, as it shouldn't be slow */
-        r = wait_for_terminate_and_check("(sd-accept)", pid, WAIT_LOG_ABNORMAL);
+        r = wait_for_terminate_and_check("(sd-accept)", pid.pid, WAIT_LOG_ABNORMAL);
         if (r < 0) {
                 safe_close(cfd);
                 return r;
@@ -3101,10 +3083,10 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         assert(s);
         assert(pid >= 0);
 
-        if (pid != s->control_pid)
+        if (pid != s->control_pid.pid)
                 return;
 
-        s->control_pid = 0;
+        pidref_done(&s->control_pid);
 
         if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
                 f = SOCKET_SUCCESS;
@@ -3370,17 +3352,13 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
         if (IN_SET(SERVICE(other)->state,
                    SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
-                   SERVICE_AUTO_RESTART))
+                   SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART_QUEUED))
                socket_enter_listening(s);
 
         if (SERVICE(other)->state == SERVICE_RUNNING)
                 socket_set_state(s, SOCKET_RUNNING);
 }
 
-static int socket_kill(Unit *u, KillWho who, int signo, int code, int value, sd_bus_error *error) {
-        return unit_kill_common(u, who, signo, code, value, -1, SOCKET(u)->control_pid, error);
-}
-
 static int socket_get_timeout(Unit *u, usec_t *timeout) {
         Socket *s = SOCKET(u);
         usec_t t;
@@ -3409,12 +3387,8 @@ char *socket_fdname(Socket *s) {
         return s->fdname ?: UNIT(s)->id;
 }
 
-static int socket_control_pid(Unit *u) {
-        Socket *s = SOCKET(u);
-
-        assert(s);
-
-        return s->control_pid;
+static PidRef *socket_control_pid(Unit *u) {
+        return &ASSERT_PTR(SOCKET(u))->control_pid;
 }
 
 static int socket_clean(Unit *u, ExecCleanMask mask) {
@@ -3440,20 +3414,22 @@ static int socket_clean(Unit *u, ExecCleanMask mask) {
         s->control_command = NULL;
         s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
 
-        r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->exec_context.timeout_clean_usec));
-        if (r < 0)
+        r = socket_arm_timer(s, /* relative= */ true, s->exec_context.timeout_clean_usec);
+        if (r < 0) {
+                log_unit_warning_errno(u, r, "Failed to install timer: %m");
                 goto fail;
+        }
 
         r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
-        if (r < 0)
+        if (r < 0) {
+                log_unit_warning_errno(u, r, "Failed to spawn cleaning task: %m");
                 goto fail;
+        }
 
         socket_set_state(s, SOCKET_CLEANING);
-
         return 0;
 
 fail:
-        log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m");
         s->clean_result = SOCKET_FAILURE_RESOURCES;
         s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
         return r;
@@ -3567,7 +3543,6 @@ const UnitVTable socket_vtable = {
         .start = socket_start,
         .stop = socket_stop,
 
-        .kill = socket_kill,
         .clean = socket_clean,
         .can_clean = socket_can_clean,