#include "bus-introspect.h"
#include "bus-signature.h"
#include "bus-objects.h"
+#include "bus-util.h"
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
assert(b);
+ sd_bus_detach_event(b);
+
bus_close_fds(b);
if (b->kdbus_buffer)
assert(bus->state == BUS_HELLO);
assert(reply);
- r = bus_message_to_errno(reply);
+ r = sd_bus_message_get_errno(reply);
if (r < 0)
return r;
+ if (r > 0)
+ return -r;
r = sd_bus_message_read(reply, "s", &s);
if (r < 0)
return r;
}
+int sd_bus_open_system_remote(const char *host, sd_bus **ret) {
+ _cleanup_free_ char *e = NULL;
+ char *p = NULL;
+ sd_bus *bus;
+ int r;
+
+ assert_return(host, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ e = bus_address_escape(host);
+ if (!e)
+ return -ENOMEM;
+
+ p = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", NULL);
+ if (!p)
+ return -ENOMEM;
+
+ r = sd_bus_new(&bus);
+ if (r < 0) {
+ free(p);
+ return r;
+ }
+
+ bus->address = p;
+ bus->bus_client = true;
+
+ r = sd_bus_start(bus);
+ if (r < 0) {
+ bus_free(bus);
+ return r;
+ }
+
+ *ret = bus;
+ return 0;
+}
+
void sd_bus_close(sd_bus *bus) {
if (!bus)
return;
bus->state = BUS_CLOSED;
+ sd_bus_detach_event(bus);
+
if (!bus->is_kernel)
bus_close_fds(bus);
/* If this is a reply and no reply was requested, then let's
* suppress this, if we can */
if (m->dont_send && !serial)
- return 0;
+ return 1;
if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
if (serial)
*serial = BUS_MESSAGE_SERIAL(m);
- return 0;
+ return 1;
}
static usec_t calc_elapse(uint64_t usec) {
assert_return(bus, -EINVAL);
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(m, -EINVAL);
- assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+ assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(bus, -EINVAL);
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(m, -EINVAL);
- assert_return(m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
+ assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(!bus_error_is_dirty(error), -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
if (incoming->reply_serial == serial) {
/* Found a match! */
- if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) {
+ if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
if (reply)
*reply = incoming;
else
sd_bus_message_unref(incoming);
- return 0;
+ return 1;
}
- if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR) {
+ if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
int k;
r = sd_bus_error_copy(error, &incoming->error);
return r;
}
- k = bus_error_to_errno(&incoming->error);
+ k = sd_bus_error_get_errno(&incoming->error);
sd_bus_message_unref(incoming);
- return k;
+ return -k;
}
sd_bus_message_unref(incoming);
return 0;
}
+ if (bus->rqueue_size > 0) {
+ *timeout_usec = 0;
+ return 1;
+ }
+
c = prioq_peek(bus->reply_callbacks_prioq);
if (!c) {
*timeout_usec = (uint64_t) -1;
r = bus_message_new_synthetic_error(
bus,
c->serial,
- &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.Timeout", "Timed out"),
+ &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_REPLY, "Method call timed out"),
&m);
if (r < 0)
return r;
* 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)
+ if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
+ m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
return -EIO;
if (m->reply_serial != bus->hello_serial)
assert(bus);
assert(m);
- if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_RETURN &&
- m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+ if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
+ m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
return 0;
c = hashmap_remove(bus->reply_callbacks, &m->reply_serial);
assert(bus);
assert(m);
- if (m->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+ if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
return 0;
if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
} else {
r = sd_bus_message_new_method_errorf(
bus, m, &reply,
- "org.freedesktop.DBus.Error.UnknownMethod",
+ SD_BUS_ERROR_UNKNOWN_METHOD,
"Unknown method '%s' on interface '%s'.", m->member, m->interface);
}
bus->iteration_counter++;
+ log_debug("Got message sender=%s object=%s interface=%s member=%s",
+ strna(sd_bus_message_get_sender(m)),
+ strna(sd_bus_message_get_path(m)),
+ strna(sd_bus_message_get_interface(m)),
+ strna(sd_bus_message_get_member(m)));
+
r = process_hello(bus, m);
if (r != 0)
return r;
return 1;
}
- if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) {
r = sd_bus_reply_method_errorf(
bus, m,
- "org.freedesktop.DBus.Error.UnknownObject",
+ SD_BUS_ERROR_UNKNOWN_OBJECT,
"Unknown object '%s'.", m->path);
if (r < 0)
return r;
}
int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
+ BUS_DONT_DESTROY(bus);
int r;
/* Returns 0 when we didn't do anything. This should cause the
struct pollfd p[2] = {};
int r, e, n;
struct timespec ts;
- usec_t until, m;
+ usec_t m = (usec_t) -1;
assert(bus);
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
return e;
if (need_more)
+ /* The caller really needs some more data, he doesn't
+ * care about what's already read, or any timeouts
+ * except its own.*/
e |= POLLIN;
-
- r = sd_bus_get_timeout(bus, &until);
- if (r < 0)
- return r;
- if (r == 0)
- m = (uint64_t) -1;
else {
- usec_t nw;
- nw = now(CLOCK_MONOTONIC);
- m = until > nw ? until - nw : 0;
+ usec_t until;
+ /* The caller wants to process if there's something to
+ * process, but doesn't care otherwise */
+
+ r = sd_bus_get_timeout(bus, &until);
+ if (r < 0)
+ return r;
+ if (r > 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))
return bus->original_pid != getpid();
}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ void *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
+ void *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int prepare_callback(sd_event_source *s, void *userdata) {
+ sd_bus *bus = userdata;
+ int r, e;
+ usec_t until;
+
+ assert(s);
+ assert(bus);
+
+ e = sd_bus_get_events(bus);
+ if (e < 0)
+ return e;
+
+ if (bus->output_fd != bus->input_fd) {
+
+ r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT);
+ if (r < 0)
+ return r;
+ } else {
+ r = sd_event_source_set_io_events(bus->input_io_event_source, e);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_get_timeout(bus, &until);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ int j;
+
+ j = sd_event_source_set_time(bus->time_event_source, until);
+ if (j < 0)
+ return j;
+ }
+
+ r = sd_event_source_set_enabled(bus->time_event_source, r > 0);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int quit_callback(sd_event_source *event, void *userdata) {
+ sd_bus *bus = userdata;
+
+ assert(event);
+
+ sd_bus_flush(bus);
+
+ return 1;
+}
+
+int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(event, -EINVAL);
+ assert_return(!bus->event, -EBUSY);
+
+ assert(!bus->input_io_event_source);
+ assert(!bus->output_io_event_source);
+ assert(!bus->time_event_source);
+
+ bus->event = sd_event_ref(event);
+
+ r = sd_event_add_io(event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->input_io_event_source, priority);
+ if (r < 0)
+ goto fail;
+
+ if (bus->output_fd != bus->input_fd) {
+ r = sd_event_add_io(event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->output_io_event_source, priority);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_add_monotonic(event, 0, 0, time_callback, bus, &bus->time_event_source);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(bus->time_event_source, priority);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_add_quit(event, quit_callback, bus, &bus->quit_event_source);
+ if (r < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ sd_bus_detach_event(bus);
+ return r;
+}
+
+int sd_bus_detach_event(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(bus->event, -ENXIO);
+
+ if (bus->input_io_event_source)
+ bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
+
+ if (bus->output_io_event_source)
+ bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
+
+ if (bus->time_event_source)
+ bus->time_event_source = sd_event_source_unref(bus->time_event_source);
+
+ if (bus->quit_event_source)
+ bus->quit_event_source = sd_event_source_unref(bus->quit_event_source);
+
+ if (bus->event)
+ bus->event = sd_event_unref(bus->event);
+
+ return 0;
+}