chiark / gitweb /
bus: synthesize local error reply when we cannot deliver a message to kdbus because...
authorLennart Poettering <lennart@poettering.net>
Sat, 30 Nov 2013 00:02:51 +0000 (01:02 +0100)
committerLennart Poettering <lennart@poettering.net>
Sat, 30 Nov 2013 00:02:51 +0000 (01:02 +0100)
src/libsystemd-bus/bus-kernel.c
src/libsystemd-bus/sd-bus.c
src/libsystemd-bus/test-bus-kernel.c

index a8579c98fa80fa67b8ef532d9448db118f7e5d66..69143434b3cf9729f085a25f699552a328d678d0 100644 (file)
@@ -393,13 +393,60 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
         assert(m);
         assert(bus->state == BUS_RUNNING);
 
         assert(m);
         assert(bus->state == BUS_RUNNING);
 
+        /* If we can't deliver, we want room for the error message */
+        r = bus_rqueue_make_room(bus);
+        if (r < 0)
+                return r;
+
         r = bus_message_setup_kmsg(bus, m);
         if (r < 0)
                 return r;
 
         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
         r = bus_message_setup_kmsg(bus, m);
         if (r < 0)
                 return r;
 
         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
-        if (r < 0)
-                return errno == EAGAIN ? 0 : -errno;
+        if (r < 0) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                sd_bus_message *reply;
+
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+                else if (errno == ENXIO || errno == ESRCH) {
+
+                        /* ENXIO: unique name not known
+                         * ESRCH: well-known name not known */
+
+                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
+                        else
+                                return 0;
+
+                } else if (errno == EADDRNOTAVAIL) {
+
+                        /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
+
+                        if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+                                sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
+                        else
+                                return 0;
+                } else
+                        return -errno;
+
+                r = bus_message_new_synthetic_error(
+                                bus,
+                                BUS_MESSAGE_SERIAL(m),
+                                &error,
+                                &reply);
+
+                if (r < 0)
+                        return r;
+
+                r = bus_seal_synthetic_message(bus, reply);
+                if (r < 0)
+                        return r;
+
+                bus->rqueue[bus->rqueue_size++] = reply;
+
+                return 0;
+        }
 
         return 1;
 }
 
         return 1;
 }
index 0eb61c4bd3cf3a8dd1dfa6866afdc3682a24bc7e..05c5d8d1bc666274984582c0d7a2213dc7d82f99 100644 (file)
@@ -1274,9 +1274,9 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx)
         assert(message);
 
         if (bus->is_kernel)
         assert(message);
 
         if (bus->is_kernel)
-                r = bus_kernel_write_message(bus, message);
+                return bus_kernel_write_message(bus, message);
         else
         else
-                r = bus_socket_write_message(bus, message, idx);
+                return bus_socket_write_message(bus, message, idx);
 
         return r;
 }
 
         return r;
 }
@@ -1627,20 +1627,17 @@ _public_ int sd_bus_call(
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+        i = bus->rqueue_size;
+
         r = sd_bus_send(bus, m, &serial);
         if (r < 0)
                 return r;
 
         timeout = calc_elapse(usec);
         r = sd_bus_send(bus, m, &serial);
         if (r < 0)
                 return r;
 
         timeout = calc_elapse(usec);
-        i = bus->rqueue_size;
 
         for (;;) {
                 usec_t left;
 
 
         for (;;) {
                 usec_t left;
 
-                r = bus_read_message(bus);
-                if (r < 0)
-                        return r;
-
                 while (i < bus->rqueue_size) {
                         sd_bus_message *incoming = NULL;
 
                 while (i < bus->rqueue_size) {
                         sd_bus_message *incoming = NULL;
 
@@ -1660,24 +1657,13 @@ _public_ int sd_bus_call(
                                                 sd_bus_message_unref(incoming);
 
                                         return 1;
                                                 sd_bus_message_unref(incoming);
 
                                         return 1;
-                                }
-
-                                if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
-                                        int k;
-
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
                                         r = sd_bus_error_copy(error, &incoming->error);
                                         r = sd_bus_error_copy(error, &incoming->error);
-                                        if (r < 0) {
-                                                sd_bus_message_unref(incoming);
-                                                return r;
-                                        }
-
-                                        k = sd_bus_error_get_errno(&incoming->error);
-                                        sd_bus_message_unref(incoming);
-                                        return -k;
-                                }
+                                else
+                                        r = -EIO;
 
                                 sd_bus_message_unref(incoming);
 
                                 sd_bus_message_unref(incoming);
-                                return -EIO;
+                                return r;
 
                         } else if (incoming->header->serial == serial &&
                                    bus->unique_name &&
 
                         } else if (incoming->header->serial == serial &&
                                    bus->unique_name &&
@@ -1700,6 +1686,9 @@ _public_ int sd_bus_call(
                         i++;
                 }
 
                         i++;
                 }
 
+                r = bus_read_message(bus);
+                if (r < 0)
+                        return r;
                 if (r > 0)
                         continue;
 
                 if (r > 0)
                         continue;
 
index f970ca5ca4b5f10bcb9746974608824ecdb59672..04dbc998dc13eeed67aa01b3d850011d2a822dfc 100644 (file)
@@ -35,6 +35,7 @@ int main(int argc, char *argv[]) {
         _cleanup_close_ int bus_ref = -1;
         _cleanup_free_ char *bus_name = NULL, *address = NULL;
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         _cleanup_close_ int bus_ref = -1;
         _cleanup_free_ char *bus_name = NULL, *address = NULL;
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         const char *ua = NULL, *ub = NULL, *the_string = NULL;
         sd_bus *a, *b;
         int r, pipe_fds[2];
         const char *ua = NULL, *ub = NULL, *the_string = NULL;
         sd_bus *a, *b;
         int r, pipe_fds[2];
@@ -84,6 +85,10 @@ int main(int argc, char *argv[]) {
 
         printf("unique b: %s\n", ub);
 
 
         printf("unique b: %s\n", ub);
 
+        r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
+        assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
+        assert_se(r == -EHOSTUNREACH);
+
         r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
         assert_se(r >= 0);