summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-11-30 01:02:51 +0100
committerLennart Poettering <lennart@poettering.net>2013-11-30 01:02:51 +0100
commita43b9ca3049d0f27cdb3bc8dad703e688cba31b3 (patch)
tree3a459cde6758bdb6f2cad5b280251930eee4f7d4
parent7adc46fcce257fcf4c83faa18b8c78f2a577e4f1 (diff)
bus: synthesize local error reply when we cannot deliver a message to kdbus because the destination is unavailable
-rw-r--r--src/libsystemd-bus/bus-kernel.c51
-rw-r--r--src/libsystemd-bus/sd-bus.c33
-rw-r--r--src/libsystemd-bus/test-bus-kernel.c5
3 files changed, 65 insertions, 24 deletions
diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c
index a8579c98fa..69143434b3 100644
--- a/src/libsystemd-bus/bus-kernel.c
+++ b/src/libsystemd-bus/bus-kernel.c
@@ -393,13 +393,60 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
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);
- 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;
}
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 0eb61c4bd3..05c5d8d1bc 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -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)
- r = bus_kernel_write_message(bus, message);
+ return bus_kernel_write_message(bus, message);
else
- r = bus_socket_write_message(bus, message, idx);
+ return bus_socket_write_message(bus, message, idx);
return r;
}
@@ -1627,20 +1627,17 @@ _public_ int sd_bus_call(
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);
- i = bus->rqueue_size;
for (;;) {
usec_t left;
- r = bus_read_message(bus);
- if (r < 0)
- return r;
-
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;
- }
-
- 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);
- 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);
- return -EIO;
+ return r;
} else if (incoming->header->serial == serial &&
bus->unique_name &&
@@ -1700,6 +1686,9 @@ _public_ int sd_bus_call(
i++;
}
+ r = bus_read_message(bus);
+ if (r < 0)
+ return r;
if (r > 0)
continue;
diff --git a/src/libsystemd-bus/test-bus-kernel.c b/src/libsystemd-bus/test-bus-kernel.c
index f970ca5ca4..04dbc998dc 100644
--- a/src/libsystemd-bus/test-bus-kernel.c
+++ b/src/libsystemd-bus/test-bus-kernel.c
@@ -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_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];
@@ -84,6 +85,10 @@ int main(int argc, char *argv[]) {
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);