+static void socket_enter_dead(Socket *s, bool success) {
+ assert(s);
+
+ if (!success)
+ s->failure = true;
+
+ socket_set_state(s, s->failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, bool success);
+
+static void socket_enter_stop_post(Socket *s, bool success) {
+ int r;
+ assert(s);
+
+ if (!success)
+ s->failure = true;
+
+ socket_unwatch_control_pid(s);
+
+ s->control_command_id = SOCKET_EXEC_STOP_POST;
+
+ if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) {
+ if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+ goto fail;
+
+ socket_set_state(s, SOCKET_STOP_POST);
+ } else
+ socket_enter_signal(s, SOCKET_FINAL_SIGTERM, true);
+
+ return;
+
+fail:
+ log_warning("%s failed to run stop-post executable: %s", s->meta.id, strerror(-r));
+ socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+}
+
+static void socket_enter_signal(Socket *s, SocketState state, bool success) {
+ int r;
+ bool sent = false;
+
+ assert(s);
+
+ if (!success)
+ s->failure = true;
+
+ if (s->kill_mode != KILL_NONE) {
+ int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? SIGTERM : SIGKILL;
+
+ if (s->kill_mode == KILL_CONTROL_GROUP) {
+
+ if ((r = cgroup_bonding_kill_list(UNIT(s)->meta.cgroup_bondings, sig)) < 0) {
+ if (r != -EAGAIN && r != -ESRCH)
+ goto fail;
+ } else
+ sent = true;
+ }
+
+ if (!sent && s->control_pid > 0)
+ if (kill(s->kill_mode == KILL_PROCESS ? s->control_pid : -s->control_pid, sig) < 0 && errno != ESRCH) {
+ r = -errno;
+ goto fail;
+ }
+ }
+
+ if (sent) {
+ if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+ goto fail;
+
+ socket_set_state(s, state);
+ } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+ socket_enter_stop_post(s, true);
+ else
+ socket_enter_dead(s, true);
+
+ return;
+
+fail:
+ log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r));
+
+ if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+ socket_enter_stop_post(s, false);
+ else
+ socket_enter_dead(s, false);
+}
+
+static void socket_enter_stop_pre(Socket *s, bool success) {
+ int r;
+ assert(s);
+
+ if (!success)
+ s->failure = true;
+
+ socket_unwatch_control_pid(s);
+
+ s->control_command_id = SOCKET_EXEC_STOP_PRE;
+
+ if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) {
+ if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+ goto fail;
+
+ socket_set_state(s, SOCKET_STOP_PRE);
+ } else
+ socket_enter_stop_post(s, true);
+
+ return;
+
+fail:
+ log_warning("%s failed to run stop-pre executable: %s", s->meta.id, strerror(-r));
+ socket_enter_stop_post(s, false);
+}
+
+static void socket_enter_listening(Socket *s) {
+ int r;
+ assert(s);
+
+ if ((r = socket_watch_fds(s)) < 0) {
+ log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r));
+ goto fail;
+ }
+
+ socket_set_state(s, SOCKET_LISTENING);
+ return;
+
+fail:
+ socket_enter_stop_pre(s, false);
+}
+
+static void socket_enter_start_post(Socket *s) {
+ int r;
+ assert(s);
+
+ if ((r = socket_open_fds(s)) < 0) {
+ log_warning("%s failed to listen on sockets: %s", s->meta.id, strerror(-r));
+ goto fail;
+ }
+
+ socket_unwatch_control_pid(s);
+
+ s->control_command_id = SOCKET_EXEC_START_POST;
+
+ if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) {
+ if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) {
+ log_warning("%s failed to run start-post executable: %s", s->meta.id, strerror(-r));
+ goto fail;
+ }
+
+ socket_set_state(s, SOCKET_START_POST);
+ } else
+ socket_enter_listening(s);
+
+ return;
+
+fail:
+ socket_enter_stop_pre(s, false);
+}
+
+static void socket_enter_start_pre(Socket *s) {
+ int r;
+ assert(s);
+
+ socket_unwatch_control_pid(s);
+
+ s->control_command_id = SOCKET_EXEC_START_PRE;
+
+ if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) {
+ if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
+ goto fail;
+
+ socket_set_state(s, SOCKET_START_PRE);
+ } else
+ socket_enter_start_post(s);
+
+ return;
+
+fail:
+ log_warning("%s failed to run start-pre exectuable: %s", s->meta.id, strerror(-r));
+ socket_enter_dead(s, false);
+}
+
+static void socket_enter_running(Socket *s, int cfd) {
+ int r;