chiark / gitweb /
sd-bus: when the server-side disconnects, make sure to dispatch all tracking objects...
[elogind.git] / src / libelogind / sd-bus / sd-bus.c
index c35bd5a01189e819d297d95d2610a5f63787fb1d..0b8d2fffdf6ee41430e238d2db15e5c1700b0048 100644 (file)
@@ -109,6 +109,7 @@ static void bus_free(sd_bus *b) {
 
         assert(b);
         assert(!b->track_queue);
+        assert(!b->tracks);
 
         b->state = BUS_CLOSED;
 
@@ -2664,62 +2665,76 @@ null_message:
         return r;
 }
 
-static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        struct reply_callback *c;
+        sd_bus_slot *slot;
         int r;
 
         assert(bus);
-        assert(bus->state == BUS_CLOSING);
+        assert(c);
 
-        c = ordered_hashmap_first(bus->reply_callbacks);
-        if (c) {
-                _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-                sd_bus_slot *slot;
+        r = bus_message_new_synthetic_error(
+                        bus,
+                        c->cookie,
+                        &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
+                        &m);
+        if (r < 0)
+                return r;
 
-                /* First, fail all outstanding method calls */
-                r = bus_message_new_synthetic_error(
-                                bus,
-                                c->cookie,
-                                &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
-                                &m);
-                if (r < 0)
-                        return r;
+        r = bus_seal_synthetic_message(bus, m);
+        if (r < 0)
+                return r;
 
-                r = bus_seal_synthetic_message(bus, m);
-                if (r < 0)
-                        return r;
+        if (c->timeout != 0) {
+                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                c->timeout = 0;
+        }
 
-                if (c->timeout != 0) {
-                        prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-                        c->timeout = 0;
-                }
+        ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
+        c->cookie = 0;
 
-                ordered_hashmap_remove(bus->reply_callbacks, &c->cookie);
-                c->cookie = 0;
+        slot = container_of(c, sd_bus_slot, reply_callback);
 
-                slot = container_of(c, sd_bus_slot, reply_callback);
+        bus->iteration_counter++;
 
-                bus->iteration_counter++;
+        bus->current_message = m;
+        bus->current_slot = sd_bus_slot_ref(slot);
+        bus->current_handler = c->callback;
+        bus->current_userdata = slot->userdata;
+        r = c->callback(m, slot->userdata, &error_buffer);
+        bus->current_userdata = NULL;
+        bus->current_handler = NULL;
+        bus->current_slot = NULL;
+        bus->current_message = NULL;
 
-                bus->current_message = m;
-                bus->current_slot = sd_bus_slot_ref(slot);
-                bus->current_handler = c->callback;
-                bus->current_userdata = slot->userdata;
-                r = c->callback(m, slot->userdata, &error_buffer);
-                bus->current_userdata = NULL;
-                bus->current_handler = NULL;
-                bus->current_slot = NULL;
-                bus->current_message = NULL;
+        if (slot->floating) {
+                bus_slot_disconnect(slot);
+                sd_bus_slot_unref(slot);
+        }
 
-                if (slot->floating) {
-                        bus_slot_disconnect(slot);
-                        sd_bus_slot_unref(slot);
-                }
+        sd_bus_slot_unref(slot);
 
-                sd_bus_slot_unref(slot);
+        return bus_maybe_reply_error(m, r, &error_buffer);
+}
+
+static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        struct reply_callback *c;
+        int r;
+
+        assert(bus);
+        assert(bus->state == BUS_CLOSING);
 
-                return bus_maybe_reply_error(m, r, &error_buffer);
+        /* First, fail all outstanding method calls */
+        c = ordered_hashmap_first(bus->reply_callbacks);
+        if (c)
+                return process_closing_reply_callback(bus, c);
+
+        /* Then, fake-drop all remaining bus tracking references */
+        if (bus->tracks) {
+                bus_track_close(bus->tracks);
+                return 1;
         }
 
         /* Then, synthesize a Disconnected message */