chiark / gitweb /
install: various improvements
[elogind.git] / src / socket.c
index 7a8624c848fc962495eeb90371aab6863137c077..acd49a50457cdb49ba06b278922a56243026a40a 100644 (file)
@@ -36,6 +36,9 @@
 #include "strv.h"
 #include "unit-name.h"
 #include "dbus-socket.h"
+#include "missing.h"
+#include "special.h"
+#include "bus-errors.h"
 
 static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = UNIT_INACTIVE,
@@ -49,7 +52,7 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
         [SOCKET_STOP_POST] = UNIT_DEACTIVATING,
         [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING,
         [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING,
-        [SOCKET_MAINTENANCE] = UNIT_INACTIVE,
+        [SOCKET_MAINTENANCE] = UNIT_MAINTENANCE
 };
 
 static void socket_init(Unit *u) {
@@ -65,6 +68,11 @@ static void socket_init(Unit *u) {
 
         s->max_connections = 64;
 
+        s->priority = -1;
+        s->ip_tos = -1;
+        s->ip_ttl = -1;
+        s->mark = -1;
+
         exec_context_init(&s->exec_context);
 
         s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
@@ -198,10 +206,7 @@ int socket_add_one_mount_link(Socket *s, Mount *m) {
         if (!socket_needs_mount(s, m->where))
                 return 0;
 
-        if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(s), true)) < 0)
-                return r;
-
-        if ((r = unit_add_dependency(UNIT(s), UNIT_REQUIRES, UNIT(m), true)) < 0)
+        if ((r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
                 return r;
 
         return 0;
@@ -238,6 +243,17 @@ static int socket_add_device_link(Socket *s) {
         return r;
 }
 
+static int socket_add_default_dependencies(Socket *s) {
+        int r;
+        assert(s);
+
+        if (s->meta.manager->running_as == MANAGER_SYSTEM)
+                if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+                        return r;
+
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+}
+
 static int socket_load(Unit *u) {
         Socket *s = SOCKET(u);
         int r;
@@ -270,6 +286,10 @@ static int socket_load(Unit *u) {
 
                 if ((r = unit_add_default_cgroup(u)) < 0)
                         return r;
+
+                if (s->meta.default_dependencies)
+                        if ((r = socket_add_default_dependencies(s)) < 0)
+                                return r;
         }
 
         return socket_verify(s);
@@ -308,13 +328,17 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sBacklog: %u\n"
                 "%sKillMode: %s\n"
                 "%sSocketMode: %04o\n"
-                "%sDirectoryMode: %04o\n",
+                "%sDirectoryMode: %04o\n"
+                "%sKeepAlive: %s\n"
+                "%sFreeBind: %s\n",
                 prefix, socket_state_to_string(s->state),
                 prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
                 prefix, s->backlog,
                 prefix, kill_mode_to_string(s->kill_mode),
                 prefix, s->socket_mode,
-                prefix, s->directory_mode);
+                prefix, s->directory_mode,
+                prefix, yes_no(s->keep_alive),
+                prefix, yes_no(s->free_bind));
 
         if (s->control_pid > 0)
                 fprintf(f,
@@ -335,6 +359,41 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                         prefix, s->n_connections,
                         prefix, s->max_connections);
 
+        if (s->priority >= 0)
+                fprintf(f,
+                        "%sPriority: %i\n",
+                        prefix, s->priority);
+
+        if (s->receive_buffer > 0)
+                fprintf(f,
+                        "%sReceiveBuffer: %zu\n",
+                        prefix, s->receive_buffer);
+
+        if (s->send_buffer > 0)
+                fprintf(f,
+                        "%sSendBuffer: %zu\n",
+                        prefix, s->send_buffer);
+
+        if (s->ip_tos >= 0)
+                fprintf(f,
+                        "%sIPTOS: %i\n",
+                        prefix, s->ip_tos);
+
+        if (s->ip_ttl >= 0)
+                fprintf(f,
+                        "%sIPTTL: %i\n",
+                        prefix, s->ip_ttl);
+
+        if (s->pipe_size > 0)
+                fprintf(f,
+                        "%sPipeSize: %zu\n",
+                        prefix, s->pipe_size);
+
+        if (s->mark >= 0)
+                fprintf(f,
+                        "%sMark: %i\n",
+                        prefix, s->mark);
+
         LIST_FOREACH(port, p, s->ports) {
 
                 if (p->type == SOCKET_SOCKET) {
@@ -493,6 +552,60 @@ static void socket_close_fds(Socket *s) {
         }
 }
 
+static void socket_apply_socket_options(Socket *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        if (s->keep_alive) {
+                int b = s->keep_alive;
+                if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
+                        log_warning("SO_KEEPALIVE failed: %m");
+        }
+
+        if (s->priority >= 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
+                        log_warning("SO_PRIORITY failed: %m");
+
+        if (s->receive_buffer > 0) {
+                int value = (int) s->receive_buffer;
+                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+                        log_warning("SO_RCVBUF failed: %m");
+        }
+
+        if (s->send_buffer > 0) {
+                int value = (int) s->send_buffer;
+                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+                        log_warning("SO_SNDBUF failed: %m");
+        }
+
+        if (s->mark >= 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
+                        log_warning("SO_MARK failed: %m");
+
+        if (s->ip_tos >= 0)
+                if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
+                        log_warning("IP_TOS failed: %m");
+
+        if (s->ip_ttl >= 0) {
+                int r, x;
+
+                r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
+                x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
+
+                if (r < 0 && x < 0)
+                        log_warning("IP_TTL/IPV6_UNICAST_HOPS failed: %m");
+        }
+}
+
+static void socket_apply_pipe_options(Socket *s, int fd) {
+        assert(s);
+        assert(fd >= 0);
+
+        if (s->pipe_size > 0)
+                if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
+                        log_warning("F_SETPIPE_SZ: %m");
+}
+
 static int socket_open_fds(Socket *s) {
         SocketPort *p;
         int r;
@@ -511,11 +624,14 @@ static int socket_open_fds(Socket *s) {
                                              s->backlog,
                                              s->bind_ipv6_only,
                                              s->bind_to_device,
+                                             s->free_bind,
                                              s->directory_mode,
                                              s->socket_mode,
                                              &p->fd)) < 0)
                                 goto rollback;
 
+                        socket_apply_socket_options(s, p->fd);
+
                 } else {
                         struct stat st;
                         assert(p->type == SOCKET_FIFO);
@@ -543,6 +659,8 @@ static int socket_open_fds(Socket *s) {
                                 r = -EEXIST;
                                 goto rollback;
                         }
+
+                        socket_apply_pipe_options(s, p->fd);
                 }
         }
 
@@ -704,6 +822,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
                        s->meta.manager->environment,
                        true,
                        true,
+                       true,
                        s->meta.manager->confirm_spawn,
                        s->meta.cgroup_bondings,
                        &pid);
@@ -908,17 +1027,19 @@ fail:
 
 static void socket_enter_running(Socket *s, int cfd) {
         int r;
+        DBusError error;
 
         assert(s);
+        dbus_error_init(&error);
 
         if (cfd < 0) {
-                if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0)
+                if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
                         goto fail;
 
                 socket_set_state(s, SOCKET_RUNNING);
         } else {
                 Unit *u;
-                char *prefix, *instance, *name;
+                char *prefix, *instance = NULL, *name;
 
                 if (s->n_connections >= s->max_connections) {
                         log_warning("Too many incoming connections (%u)", s->n_connections);
@@ -944,7 +1065,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                         goto fail;
                 }
 
-                r = manager_load_unit(s->meta.manager, name, NULL, &u);
+                r = manager_load_unit(s->meta.manager, name, NULL, NULL, &u);
                 free(name);
 
                 if (r < 0)
@@ -957,18 +1078,20 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 s->n_connections ++;
 
-                if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, NULL)) < 0)
+                if ((r = manager_add_job(u->meta.manager, JOB_START, u, JOB_REPLACE, true, &error, NULL)) < 0)
                         goto fail;
         }
 
         return;
 
 fail:
-        log_warning("%s failed to queue socket startup job: %s", s->meta.id, strerror(-r));
+        log_warning("%s failed to queue socket startup job: %s", s->meta.id, bus_error(&error, r));
         socket_enter_stop_pre(s, false);
 
         if (cfd >= 0)
                 close_nointr_nofail(cfd);
+
+        dbus_error_free(&error);
 }
 
 static void socket_run_next(Socket *s, bool success) {
@@ -1253,6 +1376,8 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
 
                         break;
                 }
+
+                socket_apply_socket_options(s, cfd);
         }
 
         socket_enter_running(s, cfd);
@@ -1278,7 +1403,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         s->failure = s->failure || !success;
 
         if (s->control_command)
-                exec_status_fill(&s->control_command->exec_status, pid, code, status);
+                exec_status_exit(&s->control_command->exec_status, pid, code, status);
 
         log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);