]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/socket.c
tree-wide: drop assignments to r when we only need errno
[thirdparty/systemd.git] / src / core / socket.c
index ac8d1e7aea08983883a8ca677618357307b44d14..f71fa34300b8a3b5a86e44755d2be29fdc46120a 100644 (file)
@@ -18,6 +18,7 @@
 #include "dbus-socket.h"
 #include "dbus-unit.h"
 #include "def.h"
+#include "errno-list.h"
 #include "exit-status.h"
 #include "fd-util.h"
 #include "format-util.h"
@@ -206,27 +207,6 @@ static int socket_arm_timer(Socket *s, usec_t usec) {
         return 0;
 }
 
-static int socket_instantiate_service(Socket *s, int cfd) {
-        Unit *service;
-        int r;
-
-        assert(s);
-        assert(cfd >= 0);
-
-        /* This fills in s->service if it isn't filled in yet. For Accept=yes sockets we create the next
-         * connection service here. For Accept=no this is mostly a NOP since the service is figured out at
-         * load time anyway. */
-
-        r = socket_load_service_unit(s, cfd, &service);
-        if (r < 0)
-                return r;
-
-        unit_ref_set(&s->service, UNIT(s), service);
-
-        return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
-                                         false, UNIT_DEPENDENCY_IMPLICIT);
-}
-
 static bool have_non_accept_socket(Socket *s) {
         SocketPort *p;
 
@@ -546,8 +526,7 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) {
         assert(fd >= 0);
         assert(s);
 
-        r = getpeername(fd, &sa.peer.sa, &salen);
-        if (r < 0)
+        if (getpeername(fd, &sa.peer.sa, &salen) < 0)
                 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)) {
@@ -999,10 +978,11 @@ static void socket_close_fds(Socket *s) {
                         (void) unlink(*i);
 }
 
-static void socket_apply_socket_options(Socket *s, int fd) {
+static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) {
         int r;
 
         assert(s);
+        assert(p);
         assert(fd >= 0);
 
         if (s->keep_alive) {
@@ -1066,7 +1046,7 @@ static void socket_apply_socket_options(Socket *s, int fd) {
         }
 
         if (s->pass_pktinfo) {
-                r = socket_pass_pktinfo(fd, true);
+                r = socket_set_recvpktinfo(fd, socket_address_family(&p->address), true);
                 if (r < 0)
                         log_unit_warning_errno(UNIT(s), r, "Failed to enable packet info socket option: %m");
         }
@@ -1078,20 +1058,17 @@ static void socket_apply_socket_options(Socket *s, int fd) {
         }
 
         if (s->receive_buffer > 0) {
-                /* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
-                if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, s->receive_buffer) < 0) {
-                        r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, s->receive_buffer);
-                        if (r < 0)
-                                log_unit_warning_errno(UNIT(s), r, "SO_RCVBUF failed: %m");
-                }
+                r = fd_set_rcvbuf(fd, s->receive_buffer, false);
+                if (r < 0)
+                        log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r,
+                                            "SO_RCVBUF/SO_RCVBUFFORCE failed: %m");
         }
 
         if (s->send_buffer > 0) {
-                if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, s->send_buffer) < 0) {
-                        r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, s->send_buffer);
-                        if (r < 0)
-                                log_unit_warning_errno(UNIT(s), r, "SO_SNDBUF failed: %m");
-                }
+                r = fd_set_sndbuf(fd, s->send_buffer, false);
+                if (r < 0)
+                        log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r,
+                                            "SO_SNDBUF/SO_SNDBUFFORCE failed: %m");
         }
 
         if (s->mark >= 0) {
@@ -1107,16 +1084,8 @@ static void socket_apply_socket_options(Socket *s, int fd) {
         }
 
         if (s->ip_ttl >= 0) {
-                int x;
-
-                r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, s->ip_ttl);
-
-                if (socket_ipv6_is_supported())
-                        x = setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, s->ip_ttl);
-                else
-                        x = -EAFNOSUPPORT;
-
-                if (r < 0 && x < 0)
+                r = socket_set_ttl(fd, socket_address_family(&p->address), s->ip_ttl);
+                if (r < 0)
                         log_unit_warning_errno(UNIT(s), r, "IP_TTL/IPV6_UNICAST_HOPS failed: %m");
         }
 
@@ -1424,11 +1393,12 @@ int socket_load_service_unit(Socket *s, int cfd, Unit **ret) {
 
         if (cfd >= 0) {
                 r = instance_from_socket(cfd, s->n_accepted, &instance);
-                if (r == -ENOTCONN)
-                        /* ENOTCONN is legitimate if TCP RST was received.
-                         * This connection is over, but the socket unit lives on. */
+                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 ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
+                                                    "Got %s on incoming socket, assuming aborted connection attempt, ignoring.",
+                                                    errno_to_name(r));
                 if (r < 0)
                         return r;
         }
@@ -1688,7 +1658,7 @@ static int socket_open_fds(Socket *_s) {
                         if (p->fd < 0)
                                 return p->fd;
 
-                        socket_apply_socket_options(s, p->fd);
+                        socket_apply_socket_options(s, p, p->fd);
                         socket_symlink(s);
                         break;
 
@@ -2326,13 +2296,14 @@ static void flush_ports(Socket *s) {
         }
 }
 
-static void socket_enter_running(Socket *s, int cfd) {
+static void socket_enter_running(Socket *s, int cfd_in) {
+        /* Note that this call takes possession of the connection fd passed. It either has to assign it
+         * somewhere or close it. */
+        _cleanup_close_ int cfd = cfd_in;
+
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
-        /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or
-         * close it. */
-
         assert(s);
 
         /* We don't take connections anymore if we are supposed to shut down anyway */
@@ -2342,9 +2313,8 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 if (cfd >= 0)
                         goto refuse;
-                else
-                        flush_ports(s);
 
+                flush_ports(s);
                 return;
         }
 
@@ -2357,12 +2327,11 @@ static void socket_enter_running(Socket *s, int cfd) {
         if (cfd < 0) {
                 bool pending = false;
                 Unit *other;
-                Iterator i;
                 void *v;
 
                 /* If there's already a start pending don't bother to
                  * do anything */
-                HASHMAP_FOREACH_KEY(v, other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
+                HASHMAP_FOREACH_KEY(v, other, UNIT(s)->dependencies[UNIT_TRIGGERS])
                         if (unit_active_or_pending(other)) {
                                 pending = true;
                                 break;
@@ -2370,8 +2339,8 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 if (!pending) {
                         if (!UNIT_ISSET(s->service)) {
-                                log_unit_error(UNIT(s), "Service to activate vanished, refusing activation.");
-                                r = -ENOENT;
+                                r = log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
+                                                         "Service to activate vanished, refusing activation.");
                                 goto fail;
                         }
 
@@ -2383,7 +2352,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                 socket_set_state(s, SOCKET_RUNNING);
         } else {
                 _cleanup_(socket_peer_unrefp) SocketPeer *p = NULL;
-                Service *service;
+                Unit *service;
 
                 if (s->n_connections >= s->max_connections) {
                         log_unit_warning(UNIT(s), "Too many incoming connections (%u), dropping connection.",
@@ -2393,8 +2362,10 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 if (s->max_connections_per_source > 0) {
                         r = socket_acquire_peer(s, cfd, &p);
-                        if (r < 0)
-                                goto refuse;
+                        if (ERRNO_IS_DISCONNECT(r))
+                                return;
+                        if (r < 0) /* We didn't have enough resources to acquire peer information, let's fail. */
+                                goto fail;
                         if (r > 0 && p->n_ref > s->max_connections_per_source) {
                                 _cleanup_free_ char *t = NULL;
 
@@ -2407,29 +2378,35 @@ static void socket_enter_running(Socket *s, int cfd) {
                         }
                 }
 
-                r = socket_instantiate_service(s, cfd);
+                r = socket_load_service_unit(s, cfd, &service);
+                if (ERRNO_IS_DISCONNECT(r))
+                        return;
                 if (r < 0)
                         goto fail;
 
-                service = SERVICE(UNIT_DEREF(s->service));
-                unit_ref_unset(&s->service);
+                r = unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
+                                              false, UNIT_DEPENDENCY_IMPLICIT);
+                if (r < 0)
+                        goto fail;
 
                 s->n_accepted++;
 
-                r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
+                r = service_set_socket_fd(SERVICE(service), cfd, s, s->selinux_context_from_net);
+                if (ERRNO_IS_DISCONNECT(r))
+                        return;
                 if (r < 0)
                         goto fail;
 
                 TAKE_FD(cfd); /* We passed ownership of the fd to the service now. Forget it here. */
                 s->n_connections++;
 
-                service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
+                SERVICE(service)->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
 
-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
+                r = manager_add_job(UNIT(s)->manager, JOB_START, service, JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0) {
                         /* 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_close_socket_fd(service);
+                        service_close_socket_fd(SERVICE(service));
                         goto fail;
                 }
 
@@ -2437,20 +2414,23 @@ static void socket_enter_running(Socket *s, int cfd) {
                 unit_add_to_dbus_queue(UNIT(s));
         }
 
+        TAKE_FD(cfd);
         return;
 
 refuse:
         s->n_refused++;
-        safe_close(cfd);
         return;
 
 fail:
-        log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
-                         cfd >= 0 ? "template" : "non-template",
-                         bus_error_message(&error, r));
+        if (ERRNO_IS_RESOURCE(r))
+                log_unit_warning(UNIT(s), "Failed to queue service startup job: %s",
+                                 bus_error_message(&error, r));
+        else
+                log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
+                                 cfd >= 0 ? "template" : "non-template",
+                                 bus_error_message(&error, r));
 
         socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-        safe_close(cfd);
 }
 
 static void socket_run_next(Socket *s) {
@@ -2796,7 +2776,6 @@ static void socket_distribute_fds(Unit *u, FDSet *fds) {
         assert(u);
 
         LIST_FOREACH(port, p, s->ports) {
-                Iterator i;
                 int fd;
 
                 if (p->type != SOCKET_SOCKET)
@@ -2805,7 +2784,7 @@ static void socket_distribute_fds(Unit *u, FDSet *fds) {
                 if (p->fd >= 0)
                         continue;
 
-                FDSET_FOREACH(fd, fds, i) {
+                FDSET_FOREACH(fd, fds) {
                         if (socket_address_matches_fd(&p->address, fd)) {
                                 p->fd = fdset_remove(fds, fd);
                                 s->deserialized_state = SOCKET_LISTENING;
@@ -3019,7 +2998,7 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                 if (cfd < 0)
                         goto fail;
 
-                socket_apply_socket_options(p->socket, cfd);
+                socket_apply_socket_options(p->socket, p, cfd);
         }
 
         socket_enter_running(p->socket, cfd);
@@ -3285,13 +3264,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
         assert(other);
 
         /* Filter out invocations with bogus state */
-        if (!IN_SET(other->load_state,
-                    UNIT_LOADED,
-                    UNIT_NOT_FOUND,
-                    UNIT_BAD_SETTING,
-                    UNIT_ERROR,
-                    UNIT_MASKED) || other->type != UNIT_SERVICE)
-                return;
+        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
+        assert(other->type == UNIT_SERVICE);
 
         /* Don't propagate state changes from the service if we are already down */
         if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))