#include "util.h"
#include "macro.h"
#include "strv.h"
+#include "set.h"
#include "sd-bus.h"
#include "bus-internal.h"
#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);
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 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) {
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;
}
skip_address_key(p);
}
- if (!path)
+ if (!path) {
+ r = -EINVAL;
goto fail;
+ }
/* Make sure there are no holes in the array, with the
* exception of argv[0] */
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;
}
bus->state = BUS_OPENING;
+ if (bus->is_server && bus->bus_client)
+ return -EINVAL;
+
if (bus->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;
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;
}
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) {
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 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;
}
}
- if (!found)
+ /* We found some handlers but none wanted to take this, then
+ * return this -- with one exception, we can handle
+ * introspection minimally ourselves */
+ if (!found || sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
return 0;
sd_bus_error_set(&error,
return 1;
}
+static int process_introspect(sd_bus *bus, sd_bus_message *m) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_free_ char *introspection = NULL;
+ _cleanup_set_free_free_ Set *s = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct object_callback *c;
+ Iterator i;
+ size_t size = 0;
+ char *node;
+ int r;
+
+ assert(bus);
+ assert(m);
+
+ if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect"))
+ return 0;
+
+ if (!m->path)
+ return 0;
+
+ s = set_new(string_hash_func, string_compare_func);
+ if (!s)
+ return -ENOMEM;
+
+ HASHMAP_FOREACH(c, bus->object_callbacks, i) {
+ const char *e;
+ char *a, *p;
+
+ if (streq(c->path, "/"))
+ continue;
+
+ if (streq(m->path, "/"))
+ e = c->path;
+ else {
+ e = startswith(c->path, m->path);
+ if (!e || *e != '/')
+ continue;
+ }
+
+ a = strdup(e+1);
+ if (!a)
+ return -ENOMEM;
+
+ p = strchr(a, '/');
+ if (p)
+ *p = 0;
+
+ r = set_put(s, a);
+ if (r < 0) {
+ free(a);
+
+ if (r != -EEXIST)
+ return r;
+ }
+ }
+
+ f = open_memstream(&introspection, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fputs(SD_BUS_INTROSPECT_DOCTYPE, f);
+ fputs("<node>\n", f);
+ fputs(SD_BUS_INTROSPECT_INTERFACE_PEER, f);
+ fputs(SD_BUS_INTROSPECT_INTERFACE_INTROSPECTABLE, f);
+
+ while ((node = set_steal_first(s))) {
+ fprintf(f, " <node name=\"%s\"/>\n", node);
+ free(node);
+ }
+
+ fputs("</node>\n", f);
+
+ fflush(f);
+
+ if (ferror(f))
+ return -ENOMEM;
+
+ r = sd_bus_message_new_method_return(bus, m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "s", introspection);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_send(bus, reply, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
static int process_message(sd_bus *bus, sd_bus_message *m) {
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;
- return process_object(bus, m);
+ r = process_object(bus, m);
+ if (r != 0)
+ return r;
+
+ return process_introspect(bus, m);
}
static int process_running(sd_bus *bus, sd_bus_message **ret) {
}
}
-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;
return -ENOMEM;
c->path = strdup(path);
- if (!path) {
+ if (!c->path) {
free(c);
return -ENOMEM;
}
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;
+}