blob: 81df03dd0f4c348cb551ea305e76584bd377c15c [file] [log] [blame]
Brad Bishop62ece2b2016-07-25 09:00:51 -04001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brad Bishop36eb1e52016-11-01 15:18:36 -040016#include "config.h"
Brad Bishop2afe7182016-08-13 14:08:17 -040017#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040018#include <string.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040019#include <stdio.h>
20#include <errno.h>
Brad Bishop3d468792016-09-20 15:39:38 -040021#include <unistd.h>
22#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040023#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040024#include <systemd/sd-event.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040025#include "mapper.h"
26
Brad Bishop2afe7182016-08-13 14:08:17 -040027static const char *async_wait_name_owner_match =
28 "type='signal',"
29 "sender='org.freedesktop.DBus',"
30 "interface='org.freedesktop.DBus',"
31 "member='NameOwnerChanged',"
32 "path='/org/freedesktop/DBus'";
33
34static const char *async_wait_interfaces_added_match =
35 "type='signal',"
36 "interface='org.freedesktop.DBus.ObjectManager',"
37 "member='InterfacesAdded'";
38
Brad Bishop3d468792016-09-20 15:39:38 -040039static const int mapper_busy_retries = 5;
40static const uint64_t mapper_busy_delay_interval_usec = 1000000;
41
Brad Bishop2afe7182016-08-13 14:08:17 -040042struct mapper_async_wait
43{
44 char **objs;
45 void (*callback)(int, void *);
46 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040047 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040048 sd_bus *conn;
49 sd_bus_slot *name_owner_slot;
50 sd_bus_slot *intf_slot;
51 int *status;
52 int count;
53 int finished;
54 int r;
55};
56
57struct async_wait_callback_data
58{
59 mapper_async_wait *wait;
60 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040061 sd_event_source *event_source;
62 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040063};
64
65static int async_wait_match_name_owner_changed(sd_bus_message *, void *,
66 sd_bus_error *);
67static int async_wait_match_interfaces_added(sd_bus_message *, void *,
68 sd_bus_error *);
69static int async_wait_check_done(mapper_async_wait *);
70static void async_wait_done(int r, mapper_async_wait *);
71static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040072static int async_wait_getobject_callback(sd_bus_message *,
73 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040074
75static int sarraylen(char *array[])
76{
77 int count = 0;
78 char **p = array;
79
80 while(*p != NULL) {
81 ++count;
82 ++p;
83 }
84
85 return count;
86}
87
88static void sarrayfree(char *array[])
89{
90 char **p = array;
91 while(*p != NULL) {
92 free(*p);
93 ++p;
94 }
95 free(array);
96}
97
98static char **sarraydup(char *array[])
99{
100 int count = sarraylen(array);
101 int i;
102 char **ret = NULL;
103
104 ret = malloc(sizeof(*ret) * count);
105 if(!ret)
106 return NULL;
107
108 for(i=0; i<count; ++i) {
109 ret[i] = strdup(array[i]);
110 if(!ret[i])
111 goto error;
112 }
113
114 return ret;
115
116error:
117 sarrayfree(ret);
118 return NULL;
119}
120
Brad Bishop3d468792016-09-20 15:39:38 -0400121static int async_wait_timeout_callback(sd_event_source *s,
122 uint64_t usec, void *userdata)
123{
124 int r;
125 struct async_wait_callback_data *data = userdata;
126 mapper_async_wait *wait = data->wait;
127
128 sd_event_source_unref(data->event_source);
129 r = sd_bus_call_method_async(
130 wait->conn,
131 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400132 MAPPER_BUSNAME,
133 MAPPER_PATH,
134 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400135 "GetObject",
136 async_wait_getobject_callback,
137 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400138 "sas",
139 data->path,
140 0,
141 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400142 if(r < 0) {
143 async_wait_done(r, wait);
144 free(data);
145 }
146
147 return 0;
148}
149
Brad Bishop2afe7182016-08-13 14:08:17 -0400150static int async_wait_getobject_callback(sd_bus_message *m,
151 void *userdata,
152 sd_bus_error *e)
153{
Brad Bishop3d468792016-09-20 15:39:38 -0400154 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400155 struct async_wait_callback_data *data = userdata;
156 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400157 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400158
159 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400160 goto exit;
161
162 r = sd_bus_message_get_errno(m);
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400163 if(r == ENOENT)
164 goto exit;
165
Brad Bishop3d468792016-09-20 15:39:38 -0400166 if(r == EBUSY && data->retry < mapper_busy_retries) {
167 r = sd_event_now(wait->loop,
168 CLOCK_MONOTONIC,
169 &now);
170 if(r < 0) {
171 async_wait_done(r, wait);
172 goto exit;
173 }
174
175 ++data->retry;
176 r = sd_event_add_time(wait->loop,
177 &data->event_source,
178 CLOCK_MONOTONIC,
179 now + mapper_busy_delay_interval_usec,
180 0,
181 async_wait_timeout_callback,
182 data);
183 if(r < 0) {
184 async_wait_done(r, wait);
185 goto exit;
186 }
187
Brad Bishop2afe7182016-08-13 14:08:17 -0400188 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400189 }
190
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400191 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400192 async_wait_done(-r, wait);
193 goto exit;
194 }
195
Brad Bishop2afe7182016-08-13 14:08:17 -0400196 for(i=0; i<wait->count; ++i) {
197 if(!strcmp(data->path, wait->objs[i])) {
198 wait->status[i] = 1;
199 }
200 }
201
Brad Bishop2afe7182016-08-13 14:08:17 -0400202 if(async_wait_check_done(wait))
203 async_wait_done(0, wait);
204
Brad Bishop3d468792016-09-20 15:39:38 -0400205exit:
206 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400207 return 0;
208}
209
210static int async_wait_get_objects(mapper_async_wait *wait)
211{
212 int i, r;
213 struct async_wait_callback_data *data = NULL;
214
215 for(i=0; i<wait->count; ++i) {
216 if(wait->status[i])
217 continue;
218 data = malloc(sizeof(*data));
219 data->wait = wait;
220 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400221 data->retry = 0;
222 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400223 r = sd_bus_call_method_async(
224 wait->conn,
225 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400226 MAPPER_BUSNAME,
227 MAPPER_PATH,
228 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400229 "GetObject",
230 async_wait_getobject_callback,
231 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400232 "sas",
233 wait->objs[i],
234 0,
235 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400236 if(r < 0) {
237 free(data);
238 fprintf(stderr, "Error invoking method: %s\n",
239 strerror(-r));
240 return r;
241 }
242 }
243
244 return 0;
245}
246
247static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w,
248 sd_bus_error *e)
249{
Brad Bishopa6797f82016-08-30 13:02:46 -0400250 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400251
252 mapper_async_wait *wait = w;
253 if(wait->finished)
254 return 0;
255
256 r = async_wait_get_objects(wait);
257 if(r < 0)
258 async_wait_done(r, wait);
259
260 return 0;
261}
262
263static int async_wait_match_interfaces_added(sd_bus_message *m, void *w,
264 sd_bus_error *e)
265{
266 int i, r;
267 mapper_async_wait *wait = w;
268 const char *path;
269
270 if(wait->finished)
271 return 0;
272
273 r = sd_bus_message_read(m, "o", &path);
274 if (r < 0) {
275 fprintf(stderr, "Error reading message: %s\n",
276 strerror(-r));
277 goto finished;
278 }
279
280 for(i=0; i<wait->count; ++i) {
281 if(!strcmp(path, wait->objs[i]))
282 wait->status[i] = 1;
283 }
284
285finished:
286 if(r < 0 || async_wait_check_done(wait))
287 async_wait_done(r < 0 ? r : 0, wait);
288
289 return 0;
290}
291
292static void async_wait_done(int r, mapper_async_wait *w)
293{
294 if(w->finished)
295 return;
296
297 w->finished = 1;
298 sd_bus_slot_unref(w->name_owner_slot);
299 sd_bus_slot_unref(w->intf_slot);
300
301 if(w->callback)
302 w->callback(r, w->userdata);
303}
304
305static int async_wait_check_done(mapper_async_wait *w)
306{
307 int i;
308
309 if(w->finished)
310 return 1;
311
312 for(i=0; i<w->count; ++i)
313 if(!w->status[i])
314 return 0;
315
316 return 1;
317}
318
319void mapper_wait_async_free(mapper_async_wait *w)
320{
321 free(w->status);
322 sarrayfree(w->objs);
323 free(w);
324}
325
326int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400327 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400328 char *objs[],
329 void (*callback)(int, void *),
330 void *userdata,
331 mapper_async_wait **w)
332{
333 int r;
334 mapper_async_wait *wait = NULL;
335
336 wait = malloc(sizeof(*wait));
337 if(!wait)
338 return -ENOMEM;
339
340 memset(wait, 0, sizeof(*wait));
341 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400342 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400343 wait->callback = callback;
344 wait->userdata = userdata;
345 wait->count = sarraylen(objs);
346 if(!wait->count)
347 return 0;
348
349 wait->objs = sarraydup(objs);
350 if(!wait->objs) {
351 r = -ENOMEM;
352 goto free_wait;
353 }
354
355 wait->status = malloc(sizeof(*wait->status) * wait->count);
356 if(!wait->status) {
357 r = -ENOMEM;
358 goto free_objs;
359 }
360 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
361
362 r = sd_bus_add_match(conn,
363 &wait->name_owner_slot,
364 async_wait_name_owner_match,
365 async_wait_match_name_owner_changed,
366 wait);
367 if(r < 0) {
368 fprintf(stderr, "Error adding match rule: %s\n",
369 strerror(-r));
370 goto free_status;
371 }
372
373 r = sd_bus_add_match(conn,
374 &wait->intf_slot,
375 async_wait_interfaces_added_match,
376 async_wait_match_interfaces_added,
377 wait);
378 if(r < 0) {
379 fprintf(stderr, "Error adding match rule: %s\n",
380 strerror(-r));
381 goto unref_name_slot;
382 }
383
384 r = async_wait_get_objects(wait);
385 if(r < 0) {
386 fprintf(stderr, "Error calling method: %s\n",
387 strerror(-r));
388 goto unref_intf_slot;
389 }
390
391 *w = wait;
392
393 return 0;
394
395unref_intf_slot:
396 sd_bus_slot_unref(wait->intf_slot);
397unref_name_slot:
398 sd_bus_slot_unref(wait->name_owner_slot);
399free_status:
400 free(wait->status);
401free_objs:
402 sarrayfree(wait->objs);
403free_wait:
404 free(wait);
405
406 return r;
407}
408
Brad Bishop3d468792016-09-20 15:39:38 -0400409int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400410{
411 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400412 sd_bus_message *request = NULL;
413 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400414
415 r = sd_bus_message_new_method_call(
416 conn,
417 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400418 MAPPER_BUSNAME,
419 MAPPER_PATH,
420 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400421 "GetObject");
422 if (r < 0)
423 goto exit;
424
425 r = sd_bus_message_append(request, "s", obj);
426 if (r < 0)
427 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400428 r = sd_bus_message_append(request, "as", 0, NULL);
429 if (r < 0)
430 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400431
Brad Bishop3d468792016-09-20 15:39:38 -0400432 while(retry < mapper_busy_retries) {
433 sd_bus_error_free(&error);
434 r = sd_bus_call(conn, request, 0, &error, reply);
435 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
436 ++retry;
437
438 if(retry != mapper_busy_retries)
439 usleep(mapper_busy_delay_interval_usec);
440 continue;
441 }
442 break;
443 }
444
445 if (r < 0)
446 goto exit;
447
448exit:
449 sd_bus_error_free(&error);
450 sd_bus_message_unref(request);
451
452 return r;
453}
454
455int mapper_get_service(sd_bus *conn, const char *obj, char **service)
456{
457 sd_bus_message *reply = NULL;
458 const char *tmp;
459 int r;
460
461 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400462 if (r < 0)
463 goto exit;
464
465 r = sd_bus_message_enter_container(reply, 0, NULL);
466 if (r < 0)
467 goto exit;
468
469 r = sd_bus_message_enter_container(reply, 0, NULL);
470 if (r < 0)
471 goto exit;
472
473 r = sd_bus_message_read(reply, "s", &tmp);
474 if (r < 0)
475 goto exit;
476
477 *service = strdup(tmp);
478
479exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400480 sd_bus_message_unref(reply);
481
482 return r;
483}