+ 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_reply(bus, m);
+ if (r != 0)
+ return r;
+
+ r = process_filter(bus, m);
+ if (r != 0)
+ return r;
+
+ r = process_builtin(bus, m);
+ if (r != 0)
+ return r;
+
+ 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) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+ assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+
+ r = process_timeout(bus);
+ if (r != 0)
+ goto null_message;
+
+ r = dispatch_wqueue(bus);
+ if (r != 0)
+ goto null_message;
+
+ r = dispatch_rqueue(bus, &m);
+ if (r < 0)
+ return r;
+ if (!m)
+ goto null_message;
+
+ r = process_message(bus, m);
+ if (r != 0)
+ goto null_message;
+
+ if (ret) {
+ *ret = m;
+ m = NULL;
+ return 1;
+ }
+
+ if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_INIT;
+
+ sd_bus_error_set(&error, "org.freedesktop.DBus.Error.UnknownObject", "Unknown object '%s'.", m->path);
+
+ r = sd_bus_message_new_method_error(bus, m, &error, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_send(bus, reply, NULL);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+
+null_message:
+ if (r >= 0 && ret)
+ *ret = NULL;
+
+ return r;
+}
+
+int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
+ int r;
+
+ /* Returns 0 when we didn't do anything. This should cause the
+ * caller to invoke sd_bus_wait() before returning the next
+ * time. Returns > 0 when we did something, which possibly
+ * means *ret is filled in with an unprocessed message. */
+
+ if (!bus)
+ return -EINVAL;
+ if (bus->fd < 0)
+ return -ENOTCONN;
+
+ switch (bus->state) {
+
+ case BUS_UNSET:
+ return -ENOTCONN;
+
+ case BUS_OPENING:
+ r = bus_socket_process_opening(bus);
+ if (r < 0)
+ return r;
+ if (ret)
+ *ret = NULL;
+ return r;
+
+ case BUS_AUTHENTICATING:
+
+ r = bus_socket_process_authenticating(bus);
+ if (r < 0)
+ return r;
+ if (ret)
+ *ret = NULL;
+ return r;
+
+ case BUS_RUNNING:
+ case BUS_HELLO:
+
+ return process_running(bus, ret);