Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include "sd-bus.h"
4 :
5 : #include "alloc-util.h"
6 : #include "bus-control.h"
7 : #include "bus-objects.h"
8 : #include "bus-slot.h"
9 : #include "string-util.h"
10 :
11 92 : sd_bus_slot *bus_slot_allocate(
12 : sd_bus *bus,
13 : bool floating,
14 : BusSlotType type,
15 : size_t extra,
16 : void *userdata) {
17 :
18 : sd_bus_slot *slot;
19 :
20 92 : assert(bus);
21 :
22 92 : slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
23 92 : if (!slot)
24 0 : return NULL;
25 :
26 92 : slot->n_ref = 1;
27 92 : slot->type = type;
28 92 : slot->bus = bus;
29 92 : slot->floating = floating;
30 92 : slot->userdata = userdata;
31 :
32 92 : if (!floating)
33 18 : sd_bus_ref(bus);
34 :
35 92 : LIST_PREPEND(slots, bus->slots, slot);
36 :
37 92 : return slot;
38 : }
39 :
40 193 : void bus_slot_disconnect(sd_bus_slot *slot, bool unref) {
41 : sd_bus *bus;
42 :
43 193 : assert(slot);
44 :
45 193 : if (!slot->bus)
46 101 : return;
47 :
48 92 : switch (slot->type) {
49 :
50 45 : case BUS_REPLY_CALLBACK:
51 :
52 45 : if (slot->reply_callback.cookie != 0)
53 16 : ordered_hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
54 :
55 45 : if (slot->reply_callback.timeout_usec != 0)
56 16 : prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
57 :
58 45 : break;
59 :
60 0 : case BUS_FILTER_CALLBACK:
61 0 : slot->bus->filter_callbacks_modified = true;
62 0 : LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
63 0 : break;
64 :
65 30 : case BUS_MATCH_CALLBACK:
66 :
67 30 : if (slot->match_added)
68 17 : (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
69 :
70 30 : if (slot->match_callback.install_slot) {
71 12 : bus_slot_disconnect(slot->match_callback.install_slot, true);
72 12 : slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot);
73 : }
74 :
75 30 : slot->bus->match_callbacks_modified = true;
76 30 : bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
77 :
78 30 : slot->match_callback.match_string = mfree(slot->match_callback.match_string);
79 :
80 30 : break;
81 :
82 1 : case BUS_NODE_CALLBACK:
83 :
84 1 : if (slot->node_callback.node) {
85 1 : LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
86 1 : slot->bus->nodes_modified = true;
87 :
88 1 : bus_node_gc(slot->bus, slot->node_callback.node);
89 : }
90 :
91 1 : break;
92 :
93 2 : case BUS_NODE_ENUMERATOR:
94 :
95 2 : if (slot->node_enumerator.node) {
96 2 : LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
97 2 : slot->bus->nodes_modified = true;
98 :
99 2 : bus_node_gc(slot->bus, slot->node_enumerator.node);
100 : }
101 :
102 2 : break;
103 :
104 2 : case BUS_NODE_OBJECT_MANAGER:
105 :
106 2 : if (slot->node_object_manager.node) {
107 2 : LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
108 2 : slot->bus->nodes_modified = true;
109 :
110 2 : bus_node_gc(slot->bus, slot->node_object_manager.node);
111 : }
112 :
113 2 : break;
114 :
115 12 : case BUS_NODE_VTABLE:
116 :
117 12 : if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
118 : const sd_bus_vtable *v;
119 :
120 131 : for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(slot->node_vtable.vtable, v)) {
121 119 : struct vtable_member *x = NULL;
122 :
123 119 : switch (v->type) {
124 :
125 52 : case _SD_BUS_VTABLE_METHOD: {
126 : struct vtable_member key;
127 :
128 52 : key.path = slot->node_vtable.node->path;
129 52 : key.interface = slot->node_vtable.interface;
130 52 : key.member = v->x.method.member;
131 :
132 52 : x = hashmap_remove(slot->bus->vtable_methods, &key);
133 52 : break;
134 : }
135 :
136 43 : case _SD_BUS_VTABLE_PROPERTY:
137 : case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
138 : struct vtable_member key;
139 :
140 43 : key.path = slot->node_vtable.node->path;
141 43 : key.interface = slot->node_vtable.interface;
142 43 : key.member = v->x.method.member;
143 :
144 43 : x = hashmap_remove(slot->bus->vtable_properties, &key);
145 43 : break;
146 : }}
147 :
148 119 : free(x);
149 : }
150 : }
151 :
152 12 : slot->node_vtable.interface = mfree(slot->node_vtable.interface);
153 :
154 12 : if (slot->node_vtable.node) {
155 12 : LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
156 12 : slot->bus->nodes_modified = true;
157 :
158 12 : bus_node_gc(slot->bus, slot->node_vtable.node);
159 : }
160 :
161 12 : break;
162 :
163 0 : default:
164 0 : assert_not_reached("Wut? Unknown slot type?");
165 : }
166 :
167 92 : bus = slot->bus;
168 :
169 92 : slot->type = _BUS_SLOT_INVALID;
170 92 : slot->bus = NULL;
171 92 : LIST_REMOVE(slots, bus->slots, slot);
172 :
173 92 : if (!slot->floating)
174 3 : sd_bus_unref(bus);
175 89 : else if (unref)
176 89 : sd_bus_slot_unref(slot);
177 : }
178 :
179 92 : static sd_bus_slot* bus_slot_free(sd_bus_slot *slot) {
180 92 : assert(slot);
181 :
182 92 : bus_slot_disconnect(slot, false);
183 :
184 92 : if (slot->destroy_callback)
185 1 : slot->destroy_callback(slot->userdata);
186 :
187 92 : free(slot->description);
188 92 : return mfree(slot);
189 : }
190 :
191 2500 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_slot, sd_bus_slot, bus_slot_free);
192 :
193 0 : _public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
194 0 : assert_return(slot, NULL);
195 :
196 0 : return slot->bus;
197 : }
198 :
199 0 : _public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
200 0 : assert_return(slot, NULL);
201 :
202 0 : return slot->userdata;
203 : }
204 :
205 0 : _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
206 : void *ret;
207 :
208 0 : assert_return(slot, NULL);
209 :
210 0 : ret = slot->userdata;
211 0 : slot->userdata = userdata;
212 :
213 0 : return ret;
214 : }
215 :
216 1 : _public_ int sd_bus_slot_set_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t callback) {
217 1 : assert_return(slot, -EINVAL);
218 :
219 1 : slot->destroy_callback = callback;
220 1 : return 0;
221 : }
222 :
223 4 : _public_ int sd_bus_slot_get_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t *callback) {
224 4 : assert_return(slot, -EINVAL);
225 :
226 4 : if (callback)
227 2 : *callback = slot->destroy_callback;
228 :
229 4 : return !!slot->destroy_callback;
230 : }
231 :
232 0 : _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
233 0 : assert_return(slot, NULL);
234 0 : assert_return(slot->type >= 0, NULL);
235 :
236 0 : if (slot->bus->current_slot != slot)
237 0 : return NULL;
238 :
239 0 : return slot->bus->current_message;
240 : }
241 :
242 0 : _public_ sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *slot) {
243 0 : assert_return(slot, NULL);
244 0 : assert_return(slot->type >= 0, NULL);
245 :
246 0 : if (slot->bus->current_slot != slot)
247 0 : return NULL;
248 :
249 0 : return slot->bus->current_handler;
250 : }
251 :
252 0 : _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) {
253 0 : assert_return(slot, NULL);
254 0 : assert_return(slot->type >= 0, NULL);
255 :
256 0 : if (slot->bus->current_slot != slot)
257 0 : return NULL;
258 :
259 0 : return slot->bus->current_userdata;
260 : }
261 :
262 0 : _public_ int sd_bus_slot_get_floating(sd_bus_slot *slot) {
263 0 : assert_return(slot, -EINVAL);
264 :
265 0 : return slot->floating;
266 : }
267 :
268 15 : _public_ int sd_bus_slot_set_floating(sd_bus_slot *slot, int b) {
269 15 : assert_return(slot, -EINVAL);
270 :
271 15 : if (slot->floating == !!b)
272 0 : return 0;
273 :
274 15 : if (!slot->bus) /* already disconnected slots can't be reconnected */
275 0 : return -ESTALE;
276 :
277 15 : slot->floating = b;
278 :
279 : /* When a slot is "floating" then the bus references the slot. Otherwise the slot references the bus. Hence,
280 : * when we move from one to the other, let's increase one reference and decrease the other. */
281 :
282 15 : if (b) {
283 15 : sd_bus_slot_ref(slot);
284 15 : sd_bus_unref(slot->bus);
285 : } else {
286 0 : sd_bus_ref(slot->bus);
287 0 : sd_bus_slot_unref(slot);
288 : }
289 :
290 15 : return 1;
291 : }
292 :
293 0 : _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) {
294 0 : assert_return(slot, -EINVAL);
295 :
296 0 : return free_and_strdup(&slot->description, description);
297 : }
298 :
299 0 : _public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) {
300 0 : assert_return(slot, -EINVAL);
301 0 : assert_return(description, -EINVAL);
302 :
303 0 : if (slot->description)
304 0 : *description = slot->description;
305 0 : else if (slot->type == BUS_MATCH_CALLBACK)
306 0 : *description = slot->match_callback.match_string;
307 : else
308 0 : return -ENXIO;
309 :
310 0 : return 0;
311 : }
|