chiark / gitweb /
sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached...
[elogind.git] / src / libsystemd / sd-bus / bus-slot.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "sd-bus.h"
23 #include "bus-control.h"
24 #include "bus-objects.h"
25 #include "bus-slot.h"
26
27 sd_bus_slot *bus_slot_allocate(
28                 sd_bus *bus,
29                 bool floating,
30                 BusSlotType type,
31                 size_t extra,
32                 void *userdata) {
33
34         sd_bus_slot *slot;
35
36         assert(bus);
37
38         slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
39         if (!slot)
40                 return NULL;
41
42         slot->n_ref = 1;
43         slot->type = type;
44         slot->bus = bus;
45         slot->floating = floating;
46         slot->userdata = userdata;
47
48         if (!floating)
49                 sd_bus_ref(bus);
50
51         LIST_PREPEND(slots, bus->slots, slot);
52
53         return slot;
54 }
55
56 _public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) {
57         assert_return(slot, NULL);
58
59         assert(slot->n_ref > 0);
60
61         slot->n_ref++;
62         return slot;
63 }
64
65 void bus_slot_disconnect(sd_bus_slot *slot) {
66         sd_bus *bus;
67
68         assert(slot);
69
70         switch (slot->type) {
71
72         case _BUS_SLOT_DISCONNECTED:
73                 /* Already disconnected... */
74                 return;
75
76         case BUS_REPLY_CALLBACK:
77
78                 if (slot->reply_callback.cookie != 0)
79                         hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
80
81                 if (slot->reply_callback.timeout != 0)
82                         prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
83
84                 break;
85
86         case BUS_FILTER_CALLBACK:
87                 slot->bus->filter_callbacks_modified = true;
88                 LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
89                 break;
90
91         case BUS_MATCH_CALLBACK:
92
93                 if (slot->bus->bus_client)
94                         bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
95
96                 slot->bus->match_callbacks_modified = true;
97                 bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
98
99                 free(slot->match_callback.match_string);
100
101                 break;
102
103         case BUS_NODE_CALLBACK:
104
105                 if (slot->node_callback.node) {
106                         LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
107                         slot->bus->nodes_modified = true;
108
109                         bus_node_gc(slot->bus, slot->node_callback.node);
110                 }
111
112                 break;
113
114         case BUS_NODE_ENUMERATOR:
115
116                 if (slot->node_enumerator.node) {
117                         LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
118                         slot->bus->nodes_modified = true;
119
120                         bus_node_gc(slot->bus, slot->node_enumerator.node);
121                 }
122
123                 break;
124
125         case BUS_NODE_OBJECT_MANAGER:
126
127                 if (slot->node_object_manager.node) {
128                         LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
129                         slot->bus->nodes_modified = true;
130
131                         bus_node_gc(slot->bus, slot->node_object_manager.node);
132                 }
133
134                 break;
135
136         case BUS_NODE_VTABLE:
137
138                 if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
139                         const sd_bus_vtable *v;
140
141                         for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v++) {
142                                 struct vtable_member *x = NULL;
143
144                                 switch (v->type) {
145
146                                 case _SD_BUS_VTABLE_METHOD: {
147                                         struct vtable_member key;
148
149                                         key.path = slot->node_vtable.node->path;
150                                         key.interface = slot->node_vtable.interface;
151                                         key.member = v->x.method.member;
152
153                                         x = hashmap_remove(slot->bus->vtable_methods, &key);
154                                         break;
155                                 }
156
157                                 case _SD_BUS_VTABLE_PROPERTY:
158                                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
159                                         struct vtable_member key;
160
161                                         key.path = slot->node_vtable.node->path;
162                                         key.interface = slot->node_vtable.interface;
163                                         key.member = v->x.method.member;
164
165
166                                         x = hashmap_remove(slot->bus->vtable_properties, &key);
167                                         break;
168                                 }}
169
170                                 free(x);
171                         }
172                 }
173
174                 free(slot->node_vtable.interface);
175
176                 if (slot->node_vtable.node) {
177                         LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
178                         slot->bus->nodes_modified = true;
179
180                         bus_node_gc(slot->bus, slot->node_vtable.node);
181                 }
182
183                 break;
184         }
185         bus = slot->bus;
186
187         slot->type = _BUS_SLOT_DISCONNECTED;
188         slot->bus = NULL;
189         LIST_REMOVE(slots, bus->slots, slot);
190
191         if (!slot->floating)
192                 sd_bus_unref(bus);
193 }
194
195 _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
196
197         if (!slot)
198                 return NULL;
199
200         assert(slot->n_ref > 0);
201
202         if (slot->n_ref > 1) {
203                 slot->n_ref --;
204                 return NULL;
205         }
206
207         bus_slot_disconnect(slot);
208         free(slot);
209
210         return NULL;
211 }
212
213 _public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
214         assert_return(slot, NULL);
215
216         return slot->bus;
217 }
218
219 _public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
220         assert_return(slot, NULL);
221
222         return slot->userdata;
223 }
224
225 _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
226         void *ret;
227
228         assert_return(slot, NULL);
229
230         ret = slot->userdata;
231         slot->userdata = userdata;
232
233         return ret;
234 }
235
236 _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
237         assert_return(slot, NULL);
238         assert_return(slot->type != _BUS_SLOT_DISCONNECTED, NULL);
239
240         if (slot->bus->current_slot != slot)
241                 return NULL;
242
243         return slot->bus->current_message;
244 }