bus: synthesize local error reply when we cannot deliver a message to kdbus because the destination is unavailable

This commit is contained in:
Lennart Poettering
2013-11-30 01:02:51 +01:00
parent 7adc46fcce
commit a43b9ca304
3 changed files with 65 additions and 24 deletions

View File

@@ -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;
}

View 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)
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;

View 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_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);