#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);
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);
hashmap_free(b->object_callbacks);
+ bus_match_free(&b->match_callbacks);
+
free(b);
}
return -ENOMEM;
r->n_ref = 1;
- r->fd = -1;
+ r->input_fd = r->output_fd = -1;
r->message_version = 1;
r->negotiate_fds = true;
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;
}
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;
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) {
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) {
}
if (guid) {
- r = sd_id128_from_string(guid, &b->peer);
+ r = sd_id128_from_string(guid, &b->server_id);
if (r < 0)
return r;
}
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) {
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);
}
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;
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) {
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) {
if (!bus)
return -EINVAL;
- if (bus->fd < 0)
+ if (bus->output_fd < 0)
return -ENOTCONN;
if (type == SD_BUS_TYPE_UNIX_FD) {
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;
}
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) {
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) {
return -EINVAL;
if (bus->state == BUS_UNSET)
return -ENOTCONN;
- if (bus->fd < 0)
+ if (bus->output_fd < 0)
return -ENOTCONN;
if (!m)
return -EINVAL;
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) {
return -EINVAL;
if (bus->state == BUS_UNSET)
return -ENOTCONN;
- if (bus->fd < 0)
+ if (bus->output_fd < 0)
return -ENOTCONN;
if (!m)
return -EINVAL;
assert(bus);
- if (bus->fd < 0)
+ if (bus->input_fd < 0)
return -ENOTCONN;
if (bus->state == BUS_UNSET)
return -ENOTCONN;
if (!bus)
return -EINVAL;
- if (bus->fd < 0)
+ if (bus->output_fd < 0)
return -ENOTCONN;
if (bus->state == BUS_UNSET)
return -ENOTCONN;
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) {
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;
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) {
return 1;
}
- if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO)
+ if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
+ *timeout_usec = (uint64_t) -1;
return 0;
+ }
c = prioq_peek(bus->reply_callbacks_prioq);
- if (!c)
+ if (!c) {
+ *timeout_usec = (uint64_t) -1;
return 0;
+ }
*timeout_usec = c->timeout;
return 1;
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;
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)
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;
assert(bus);
assert(m);
+ r = process_hello(bus, m);
+ if (r != 0)
+ return r;
+
r = process_reply(bus, m);
if (r != 0)
return r;
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;
if (!bus)
return -EINVAL;
- if (bus->fd < 0)
+ if (bus->input_fd < 0)
return -ENOTCONN;
+ /* We don't allow recursively invoking sd_bus_process(). */
+ if (bus->processing)
+ return -EBUSY;
+
switch (bus->state) {
case BUS_UNSET:
case BUS_RUNNING:
case BUS_HELLO:
- return process_running(bus, ret);
+ bus->processing = true;
+ r = process_running(bus, ret);
+ bus->processing = false;
+
+ return r;
}
assert_not_reached("Unknown state");
}
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);
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;
- r = ppoll(&p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+ 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, n, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
if (r < 0)
return -errno;
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;
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);
}
}
-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)
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)
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;
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;
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;
+}