chiark / gitweb /
bus-proxy: ECONNRESET/ENOTCONN can hit us on every step, hence handle it on every...
[elogind.git] / src / bus-proxyd / proxy.c
index fb2409233c54a6d0cd7e17eea146f10e131687bb..73f68b7874c28e901886e74aaff838602dbe30ef 100644 (file)
@@ -376,7 +376,7 @@ static int proxy_wait(Proxy *p) {
         }
 
         pollfd = (struct pollfd[3]) {
-                { .fd = fd,           .events = events_destination,            },
+                { .fd = fd,           .events = events_destination,     },
                 { .fd = p->local_in,  .events = events_local & POLLIN,  },
                 { .fd = p->local_out, .events = events_local & POLLOUT, },
         };
@@ -576,11 +576,11 @@ static int process_hello(Proxy *p, sd_bus_message *m) {
                 if (p->got_hello)
                         return 0;
 
-                return log_error_errno(-EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
+                return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
         }
 
         if (p->got_hello)
-                return log_error_errno(-EIO, "Got duplicate hello, aborting.");
+                return log_error_errno(EIO, "Got duplicate hello, aborting.");
 
         p->got_hello = true;
 
@@ -673,13 +673,12 @@ static int proxy_process_destination_to_local(Proxy *p) {
         assert(p);
 
         r = sd_bus_process(p->destination_bus, &m);
+        if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
+                return r;
         if (r < 0) {
-                /* treat 'connection reset by peer' as clean exit condition */
-                if (r != -ECONNRESET)
-                        log_error_errno(r, "Failed to process destination bus: %m");
+                log_error_errno(r, "Failed to process destination bus: %m");
                 return r;
         }
-
         if (r == 0)
                 return 0;
         if (!m)
@@ -690,6 +689,8 @@ static int proxy_process_destination_to_local(Proxy *p) {
                 return -ECONNRESET;
 
         r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
+        if (r == -ECONNRESET || r == -ENOTCONN)
+                return r;
         if (r < 0)
                 return log_error_errno(r, "Failed to synthesize message: %m");
 
@@ -697,31 +698,39 @@ static int proxy_process_destination_to_local(Proxy *p) {
 
         if (p->policy) {
                 r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
+                if (r == -ECONNRESET || r == -ENOTCONN)
+                        return r;
                 if (r < 0)
                         return log_error_errno(r, "Failed to process policy: %m");
-                else if (r > 0)
+                if (r > 0)
                         return 1;
         }
 
         r = sd_bus_send(p->local_bus, m, NULL);
         if (r < 0) {
-                if (r == -EPERM && m->reply_cookie > 0) {
-                        /* If the peer tries to send a reply and it is rejected with EPERM
-                         * by the kernel, we ignore the error. This catches cases where the
-                         * original method-call didn't had EXPECT_REPLY set, but the proxy-peer
-                         * still sends a reply. This is allowed in dbus1, but not in kdbus. We
-                         * don't want to track reply-windows in the proxy, so we simply ignore
-                         * EPERM for all replies. The only downside is, that callers are no
-                         * longer notified if their replies are dropped. However, this is
-                         * equivalent to the caller's timeout to expire, so this should be
-                         * acceptable. Nobody sane sends replies without a matching method-call,
-                         * so nobody should care. */
-                        return 1;
-                } else {
-                        if (r != -ECONNRESET)
-                                log_error_errno(r, "Failed to send message to client: %m");
+                if (r == -ECONNRESET || r == -ENOTCONN)
                         return r;
-                }
+
+                /* If the peer tries to send a reply and it is
+                 * rejected with EPERM by the kernel, we ignore the
+                 * error. This catches cases where the original
+                 * method-call didn't had EXPECT_REPLY set, but the
+                 * proxy-peer still sends a reply. This is allowed in
+                 * dbus1, but not in kdbus. We don't want to track
+                 * reply-windows in the proxy, so we simply ignore
+                 * EPERM for all replies. The only downside is, that
+                 * callers are no longer notified if their replies are
+                 * dropped. However, this is equivalent to the
+                 * caller's timeout to expire, so this should be
+                 * acceptable. Nobody sane sends replies without a
+                 * matching method-call, so nobody should care. */
+                if (r == -EPERM && m->reply_cookie > 0)
+                        return 1;
+
+                /* Return the error to the client, if we can */
+                synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
+                log_error_errno(r, "Failed to send message to client, ignoring: %m");
+                return 1;
         }
 
         return 1;
@@ -734,13 +743,12 @@ static int proxy_process_local_to_destination(Proxy *p) {
         assert(p);
 
         r = sd_bus_process(p->local_bus, &m);
+        if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
+                return r;
         if (r < 0) {
-                /* treat 'connection reset by peer' as clean exit condition */
-                if (r != -ECONNRESET)
-                        log_error_errno(r, "Failed to process local bus: %m");
+                log_error_errno(r, "Failed to process local bus: %m");
                 return r;
         }
-
         if (r == 0)
                 return 0;
         if (!m)
@@ -751,39 +759,48 @@ static int proxy_process_local_to_destination(Proxy *p) {
                 return -ECONNRESET;
 
         r = process_hello(p, m);
+        if (r == -ECONNRESET || r == -ENOTCONN)
+                return r;
         if (r < 0)
                 return log_error_errno(r, "Failed to process HELLO: %m");
-        else if (r > 0)
+        if (r > 0)
                 return 1;
 
         r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
+        if (r == -ECONNRESET || r == -ENOTCONN)
+                return r;
         if (r < 0)
                 return log_error_errno(r, "Failed to process driver calls: %m");
-        else if (r > 0)
+        if (r > 0)
                 return 1;
 
         for (;;) {
                 if (p->policy) {
                         r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
+                        if (r == -ECONNRESET || r == -ENOTCONN)
+                                return r;
                         if (r < 0)
                                 return log_error_errno(r, "Failed to process policy: %m");
-                        else if (r > 0)
+                        if (r > 0)
                                 return 1;
                 }
 
                 r = sd_bus_send(p->destination_bus, m, NULL);
                 if (r < 0) {
-                        if (r == -EREMCHG) {
-                                /* The name database changed since the policy check, hence let's check again */
+                        if (r == -ECONNRESET || r == -ENOTCONN)
+                                return r;
+
+                        /* The name database changed since the policy check, hence let's check again */
+                        if (r == -EREMCHG)
                                 continue;
-                        } else if (r == -EPERM && m->reply_cookie > 0) {
-                                /* see above why EPERM is ignored for replies */
+
+                        /* see above why EPERM is ignored for replies */
+                        if (r == -EPERM && m->reply_cookie > 0)
                                 return 1;
-                        } else {
-                                if (r != -ECONNRESET)
-                                        log_error_errno(r, "Failed to send message to bus: %m");
-                                return r;
-                        }
+
+                        synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
+                        log_error_errno(r, "Failed to send message to bus: %m");
+                        return 1;
                 }
 
                 break;
@@ -803,25 +820,27 @@ int proxy_run(Proxy *p) {
                 if (p->got_hello) {
                         /* Read messages from bus, to pass them on to our client */
                         r = proxy_process_destination_to_local(p);
-                        if (r == -ECONNRESET)
+                        if (r == -ECONNRESET || r == -ENOTCONN)
                                 return 0;
-                        else if (r < 0)
+                        if (r < 0)
                                 return r;
-                        else if (r > 0)
+                        if (r > 0)
                                 busy = true;
                 }
 
                 /* Read messages from our client, to pass them on to the bus */
                 r = proxy_process_local_to_destination(p);
-                if (r == -ECONNRESET)
+                if (r == -ECONNRESET || r == -ENOTCONN)
                         return 0;
-                else if (r < 0)
+                if (r < 0)
                         return r;
-                else if (r > 0)
+                if (r > 0)
                         busy = true;
 
                 if (!busy) {
                         r = proxy_wait(p);
+                        if (r == -ECONNRESET || r == -ENOTCONN)
+                                return 0;
                         if (r < 0)
                                 return r;
                 }