X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fsd-bus.c;h=4f004add2e72b953be5d47e9eed5c4e5292629d0;hp=6acc59e82c49401ce486e618401a4afbd1c93b78;hb=2b4ac8896bdc6cc5159088d7d208559d53caacf3;hpb=531991b64d1fd28218c48bab364ef8c4e80354fa diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 6acc59e82..4f004add2 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -37,6 +37,7 @@ #include "bus-message.h" #include "bus-type.h" #include "bus-socket.h" +#include "bus-control.h" static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); @@ -47,12 +48,11 @@ static void bus_free(sd_bus *b) { assert(b); - if (b->fd >= 0) - close_nointr_nofail(b->fd); + sd_bus_close(b); free(b->rbuffer); free(b->unique_name); - free(b->auth_uid); + free(b->auth_buffer); free(b->address); free(b->exec_path); @@ -84,6 +84,8 @@ static void bus_free(sd_bus *b) { hashmap_free(b->object_callbacks); + bus_match_free(&b->match_callbacks); + free(b); } @@ -98,7 +100,7 @@ int sd_bus_new(sd_bus **ret) { return -ENOMEM; r->n_ref = 1; - r->fd = -1; + r->input_fd = r->output_fd = -1; r->message_version = 1; r->negotiate_fds = true; @@ -134,15 +136,18 @@ int sd_bus_set_address(sd_bus *bus, const char *address) { return 0; } -int sd_bus_set_fd(sd_bus *bus, int fd) { +int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { if (!bus) return -EINVAL; if (bus->state != BUS_UNSET) return -EPERM; - if (fd < 0) + if (input_fd < 0) + return -EINVAL; + if (output_fd < 0) return -EINVAL; - bus->fd = fd; + bus->input_fd = input_fd; + bus->output_fd = output_fd; return 0; } @@ -197,6 +202,29 @@ int sd_bus_set_negotiate_fds(sd_bus *bus, int b) { return 0; } +int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) { + if (!bus) + return -EINVAL; + if (!b && !sd_id128_equal(server_id, SD_ID128_NULL)) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + + bus->is_server = !!b; + bus->server_id = server_id; + return 0; +} + +int sd_bus_set_anonymous(sd_bus *bus, int b) { + if (!bus) + return -EINVAL; + if (bus->state != BUS_UNSET) + return -EPERM; + + bus->anonymous_auth = !!b; + return 0; +} + static int hello_callback(sd_bus *bus, int error, sd_bus_message *reply, void *userdata) { const char *s; int r; @@ -244,11 +272,7 @@ static int bus_send_hello(sd_bus *bus) { if (r < 0) return r; - r = sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, NULL); - if (r < 0) - return r; - - return r; + return sd_bus_send_with_reply(bus, m, hello_callback, NULL, 0, &bus->hello_serial); } int bus_start_running(sd_bus *bus) { @@ -507,7 +531,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { errno = 0; ul = strtoul(*p + 4, (char**) p, 10); - if (errno != 0 || **p != '=' || ul > 256) { + if (errno > 0 || **p != '=' || ul > 256) { r = -EINVAL; goto fail; } @@ -582,7 +606,7 @@ static void bus_reset_parsed_address(sd_bus *b) { free(b->exec_path); b->exec_path = NULL; b->exec_argv = NULL; - b->peer = SD_ID128_NULL; + b->server_id = SD_ID128_NULL; } static int bus_parse_next_address(sd_bus *b) { @@ -642,7 +666,7 @@ static int bus_parse_next_address(sd_bus *b) { } if (guid) { - r = sd_id128_from_string(guid, &b->peer); + r = sd_id128_from_string(guid, &b->server_id); if (r < 0) return r; } @@ -657,10 +681,7 @@ static int bus_start_address(sd_bus *b) { assert(b); for (;;) { - if (b->fd >= 0) { - close_nointr_nofail(b->fd); - b->fd = -1; - } + sd_bus_close(b); if (b->sockaddr.sa.sa_family != AF_UNSPEC) { @@ -698,15 +719,27 @@ static int bus_start_fd(sd_bus *b) { int r; assert(b); + assert(b->input_fd >= 0); + assert(b->output_fd >= 0); - r = fd_nonblock(b->fd, true); + r = fd_nonblock(b->input_fd, true); if (r < 0) return r; - r = fd_cloexec(b->fd, true); + r = fd_cloexec(b->input_fd, true); if (r < 0) return r; + if (b->input_fd != b->output_fd) { + r = fd_nonblock(b->output_fd, true); + if (r < 0) + return r; + + r = fd_cloexec(b->output_fd, true); + if (r < 0) + return r; + } + return bus_socket_take_fd(b); } @@ -720,9 +753,12 @@ int sd_bus_start(sd_bus *bus) { bus->state = BUS_OPENING; - if (bus->fd >= 0) + if (bus->is_server && bus->bus_client) + return -EINVAL; + + if (bus->input_fd >= 0) r = bus_start_fd(bus); - else if (bus->address) + else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path) r = bus_start_address(bus); else return -EINVAL; @@ -823,11 +859,13 @@ fail: void sd_bus_close(sd_bus *bus) { if (!bus) return; - if (bus->fd < 0) - return; - close_nointr_nofail(bus->fd); - bus->fd = -1; + if (bus->input_fd >= 0) + close_nointr_nofail(bus->input_fd); + if (bus->output_fd >= 0 && bus->output_fd != bus->input_fd) + close_nointr_nofail(bus->output_fd); + + bus->input_fd = bus->output_fd = -1; } sd_bus *sd_bus_ref(sd_bus *bus) { @@ -857,7 +895,7 @@ int sd_bus_is_open(sd_bus *bus) { if (!bus) return -EINVAL; - return bus->state != BUS_UNSET && bus->fd >= 0; + return bus->state != BUS_UNSET && bus->input_fd >= 0; } int sd_bus_can_send(sd_bus *bus, char type) { @@ -865,7 +903,7 @@ int sd_bus_can_send(sd_bus *bus, char type) { if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (type == SD_BUS_TYPE_UNIX_FD) { @@ -882,19 +920,19 @@ int sd_bus_can_send(sd_bus *bus, char type) { return bus_type_is_valid(type); } -int sd_bus_get_peer(sd_bus *bus, sd_id128_t *peer) { +int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) { int r; if (!bus) return -EINVAL; - if (!peer) + if (!server_id) return -EINVAL; r = bus_ensure_running(bus); if (r < 0) return r; - *peer = bus->peer; + *server_id = bus->server_id; return 0; } @@ -916,7 +954,7 @@ static int dispatch_wqueue(sd_bus *bus) { assert(bus); assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; while (bus->wqueue_size > 0) { @@ -959,7 +997,7 @@ static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { assert(m); assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->rqueue_size > 0) { @@ -995,7 +1033,7 @@ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (!m) return -EINVAL; @@ -1092,7 +1130,7 @@ static int timeout_compare(const void *a, const void *b) { int sd_bus_send_with_reply( sd_bus *bus, sd_bus_message *m, - sd_message_handler_t callback, + sd_bus_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *serial) { @@ -1104,7 +1142,7 @@ int sd_bus_send_with_reply( return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (!m) return -EINVAL; @@ -1186,7 +1224,7 @@ int bus_ensure_running(sd_bus *bus) { assert(bus); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_UNSET) return -ENOTCONN; @@ -1223,7 +1261,7 @@ int sd_bus_send_with_reply_and_block( if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; if (bus->state == BUS_UNSET) return -ENOTCONN; @@ -1333,11 +1371,12 @@ int sd_bus_send_with_reply_and_block( int sd_bus_get_fd(sd_bus *bus) { if (!bus) return -EINVAL; - - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; + if (bus->input_fd != bus->output_fd) + return -EPERM; - return bus->fd; + return bus->input_fd; } int sd_bus_get_events(sd_bus *bus) { @@ -1347,14 +1386,14 @@ int sd_bus_get_events(sd_bus *bus) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_OPENING) flags |= POLLOUT; else if (bus->state == BUS_AUTHENTICATING) { - if (bus->auth_index < ELEMENTSOF(bus->auth_iovec)) + if (bus_socket_auth_needs_write(bus)) flags |= POLLOUT; flags |= POLLIN; @@ -1378,7 +1417,7 @@ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->state == BUS_AUTHENTICATING) { @@ -1421,6 +1460,28 @@ static int process_timeout(sd_bus *bus) { return r < 0 ? r : 1; } +static int process_hello(sd_bus *bus, sd_bus_message *m) { + assert(bus); + assert(m); + + if (bus->state != BUS_HELLO) + return 0; + + /* Let's make sure the first message on the bus is the HELLO + * reply. But note that we don't actually parse the message + * here (we leave that to the usual handling), we just verify + * we don't let any earlier msg through. */ + + if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN && + m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR) + return -EIO; + + if (m->reply_serial != bus->hello_serial) + return -EIO; + + return 0; +} + static int process_reply(sd_bus *bus, sd_bus_message *m) { struct reply_callback *c; int r; @@ -1449,6 +1510,9 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) { struct filter_callback *l; int r; + assert(bus); + assert(m); + LIST_FOREACH(callbacks, l, bus->filter_callbacks) { r = l->callback(bus, 0, m, l->userdata); if (r != 0) @@ -1458,6 +1522,13 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) { return 0; } +static int process_match(sd_bus *bus, sd_bus_message *m) { + assert(bus); + assert(m); + + return bus_match_run(bus, &bus->match_callbacks, 0, m); +} + static int process_builtin(sd_bus *bus, sd_bus_message *m) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int r; @@ -1675,6 +1746,10 @@ static int process_message(sd_bus *bus, sd_bus_message *m) { assert(bus); assert(m); + r = process_hello(bus, m); + if (r != 0) + return r; + r = process_reply(bus, m); if (r != 0) return r; @@ -1683,6 +1758,10 @@ static int process_message(sd_bus *bus, sd_bus_message *m) { if (r != 0) return r; + r = process_match(bus, m); + if (r != 0) + return r; + r = process_builtin(bus, m); if (r != 0) return r; @@ -1759,7 +1838,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { if (!bus) return -EINVAL; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; switch (bus->state) { @@ -1794,14 +1873,14 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) { } static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { - struct pollfd p; - int r, e; + struct pollfd p[2]; + int r, e, n; struct timespec ts; usec_t until, m; assert(bus); - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; e = sd_bus_get_events(bus); @@ -1817,19 +1896,28 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { if (r == 0) m = (uint64_t) -1; else { - usec_t n; - n = now(CLOCK_MONOTONIC); - m = until > n ? until - n : 0; + usec_t nw; + nw = now(CLOCK_MONOTONIC); + m = until > nw ? until - nw : 0; } if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m)) m = timeout_usec; zero(p); - p.fd = bus->fd; - p.events = e; + p[0].fd = bus->input_fd; + + if (bus->output_fd == bus->input_fd) { + p[0].events = e; + n = 1; + } else { + p[0].events = e & POLLIN; + p[1].fd = bus->output_fd; + p[1].events = e & POLLOUT; + n = 2; + } - r = ppoll(&p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); + r = ppoll(p, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL); if (r < 0) return -errno; @@ -1842,7 +1930,7 @@ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->input_fd < 0) return -ENOTCONN; if (bus->rqueue_size > 0) return 0; @@ -1857,7 +1945,7 @@ int sd_bus_flush(sd_bus *bus) { return -EINVAL; if (bus->state == BUS_UNSET) return -ENOTCONN; - if (bus->fd < 0) + if (bus->output_fd < 0) return -ENOTCONN; r = bus_ensure_running(bus); @@ -1881,7 +1969,7 @@ int sd_bus_flush(sd_bus *bus) { } } -int sd_bus_add_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata) { +int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) { struct filter_callback *f; if (!bus) @@ -1899,7 +1987,7 @@ int sd_bus_add_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata return 0; } -int sd_bus_remove_filter(sd_bus *bus, sd_message_handler_t callback, void *userdata) { +int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata) { struct filter_callback *f; if (!bus) @@ -1922,7 +2010,7 @@ static int bus_add_object( sd_bus *bus, bool fallback, const char *path, - sd_message_handler_t callback, + sd_bus_message_handler_t callback, void *userdata) { struct object_callback *c; @@ -1967,7 +2055,7 @@ static int bus_remove_object( sd_bus *bus, bool fallback, const char *path, - sd_message_handler_t callback, + sd_bus_message_handler_t callback, void *userdata) { struct object_callback *c; @@ -1994,18 +2082,63 @@ static int bus_remove_object( return 1; } -int sd_bus_add_object(sd_bus *bus, const char *path, sd_message_handler_t callback, void *userdata) { +int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) { return bus_add_object(bus, false, path, callback, userdata); } -int sd_bus_remove_object(sd_bus *bus, const char *path, sd_message_handler_t callback, void *userdata) { +int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata) { return bus_remove_object(bus, false, path, callback, userdata); } -int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t callback, void *userdata) { +int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) { return bus_add_object(bus, true, prefix, callback, userdata); } -int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_message_handler_t callback, void *userdata) { +int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata) { return bus_remove_object(bus, true, prefix, callback, userdata); } + +int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) { + int r = 0; + + if (!bus) + return -EINVAL; + if (!match) + return -EINVAL; + + if (bus->bus_client) { + r = bus_add_match_internal(bus, match); + if (r < 0) + return r; + } + + if (callback) { + r = bus_match_add(&bus->match_callbacks, match, callback, userdata, NULL); + if (r < 0) { + + if (bus->bus_client) + bus_remove_match_internal(bus, match); + } + } + + return r; +} + +int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata) { + int r = 0, q = 0; + + if (!bus) + return -EINVAL; + if (!match) + return -EINVAL; + + if (bus->bus_client) + r = bus_remove_match_internal(bus, match); + + if (callback) + q = bus_match_remove(&bus->match_callbacks, match, callback, userdata); + + if (r < 0) + return r; + return q; +}