blob: 74326eaf368bdf7662fb2abf93e823481c17fd64 [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,
138 "s",
139 data->path);
140 if(r < 0) {
141 async_wait_done(r, wait);
142 free(data);
143 }
144
145 return 0;
146}
147
Brad Bishop2afe7182016-08-13 14:08:17 -0400148static int async_wait_getobject_callback(sd_bus_message *m,
149 void *userdata,
150 sd_bus_error *e)
151{
Brad Bishop3d468792016-09-20 15:39:38 -0400152 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400153 struct async_wait_callback_data *data = userdata;
154 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400155 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400156
157 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400158 goto exit;
159
160 r = sd_bus_message_get_errno(m);
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400161 if(r == ENOENT)
162 goto exit;
163
Brad Bishop3d468792016-09-20 15:39:38 -0400164 if(r == EBUSY && data->retry < mapper_busy_retries) {
165 r = sd_event_now(wait->loop,
166 CLOCK_MONOTONIC,
167 &now);
168 if(r < 0) {
169 async_wait_done(r, wait);
170 goto exit;
171 }
172
173 ++data->retry;
174 r = sd_event_add_time(wait->loop,
175 &data->event_source,
176 CLOCK_MONOTONIC,
177 now + mapper_busy_delay_interval_usec,
178 0,
179 async_wait_timeout_callback,
180 data);
181 if(r < 0) {
182 async_wait_done(r, wait);
183 goto exit;
184 }
185
Brad Bishop2afe7182016-08-13 14:08:17 -0400186 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400187 }
188
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400189 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400190 async_wait_done(-r, wait);
191 goto exit;
192 }
193
Brad Bishop2afe7182016-08-13 14:08:17 -0400194 for(i=0; i<wait->count; ++i) {
195 if(!strcmp(data->path, wait->objs[i])) {
196 wait->status[i] = 1;
197 }
198 }
199
Brad Bishop2afe7182016-08-13 14:08:17 -0400200 if(async_wait_check_done(wait))
201 async_wait_done(0, wait);
202
Brad Bishop3d468792016-09-20 15:39:38 -0400203exit:
204 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400205 return 0;
206}
207
208static int async_wait_get_objects(mapper_async_wait *wait)
209{
210 int i, r;
211 struct async_wait_callback_data *data = NULL;
212
213 for(i=0; i<wait->count; ++i) {
214 if(wait->status[i])
215 continue;
216 data = malloc(sizeof(*data));
217 data->wait = wait;
218 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400219 data->retry = 0;
220 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400221 r = sd_bus_call_method_async(
222 wait->conn,
223 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400224 MAPPER_BUSNAME,
225 MAPPER_PATH,
226 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400227 "GetObject",
228 async_wait_getobject_callback,
229 data,
230 "s",
231 wait->objs[i]);
232 if(r < 0) {
233 free(data);
234 fprintf(stderr, "Error invoking method: %s\n",
235 strerror(-r));
236 return r;
237 }
238 }
239
240 return 0;
241}
242
243static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w,
244 sd_bus_error *e)
245{
Brad Bishopa6797f82016-08-30 13:02:46 -0400246 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400247
248 mapper_async_wait *wait = w;
249 if(wait->finished)
250 return 0;
251
252 r = async_wait_get_objects(wait);
253 if(r < 0)
254 async_wait_done(r, wait);
255
256 return 0;
257}
258
259static int async_wait_match_interfaces_added(sd_bus_message *m, void *w,
260 sd_bus_error *e)
261{
262 int i, r;
263 mapper_async_wait *wait = w;
264 const char *path;
265
266 if(wait->finished)
267 return 0;
268
269 r = sd_bus_message_read(m, "o", &path);
270 if (r < 0) {
271 fprintf(stderr, "Error reading message: %s\n",
272 strerror(-r));
273 goto finished;
274 }
275
276 for(i=0; i<wait->count; ++i) {
277 if(!strcmp(path, wait->objs[i]))
278 wait->status[i] = 1;
279 }
280
281finished:
282 if(r < 0 || async_wait_check_done(wait))
283 async_wait_done(r < 0 ? r : 0, wait);
284
285 return 0;
286}
287
288static void async_wait_done(int r, mapper_async_wait *w)
289{
290 if(w->finished)
291 return;
292
293 w->finished = 1;
294 sd_bus_slot_unref(w->name_owner_slot);
295 sd_bus_slot_unref(w->intf_slot);
296
297 if(w->callback)
298 w->callback(r, w->userdata);
299}
300
301static int async_wait_check_done(mapper_async_wait *w)
302{
303 int i;
304
305 if(w->finished)
306 return 1;
307
308 for(i=0; i<w->count; ++i)
309 if(!w->status[i])
310 return 0;
311
312 return 1;
313}
314
315void mapper_wait_async_free(mapper_async_wait *w)
316{
317 free(w->status);
318 sarrayfree(w->objs);
319 free(w);
320}
321
322int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400323 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400324 char *objs[],
325 void (*callback)(int, void *),
326 void *userdata,
327 mapper_async_wait **w)
328{
329 int r;
330 mapper_async_wait *wait = NULL;
331
332 wait = malloc(sizeof(*wait));
333 if(!wait)
334 return -ENOMEM;
335
336 memset(wait, 0, sizeof(*wait));
337 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400338 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400339 wait->callback = callback;
340 wait->userdata = userdata;
341 wait->count = sarraylen(objs);
342 if(!wait->count)
343 return 0;
344
345 wait->objs = sarraydup(objs);
346 if(!wait->objs) {
347 r = -ENOMEM;
348 goto free_wait;
349 }
350
351 wait->status = malloc(sizeof(*wait->status) * wait->count);
352 if(!wait->status) {
353 r = -ENOMEM;
354 goto free_objs;
355 }
356 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
357
358 r = sd_bus_add_match(conn,
359 &wait->name_owner_slot,
360 async_wait_name_owner_match,
361 async_wait_match_name_owner_changed,
362 wait);
363 if(r < 0) {
364 fprintf(stderr, "Error adding match rule: %s\n",
365 strerror(-r));
366 goto free_status;
367 }
368
369 r = sd_bus_add_match(conn,
370 &wait->intf_slot,
371 async_wait_interfaces_added_match,
372 async_wait_match_interfaces_added,
373 wait);
374 if(r < 0) {
375 fprintf(stderr, "Error adding match rule: %s\n",
376 strerror(-r));
377 goto unref_name_slot;
378 }
379
380 r = async_wait_get_objects(wait);
381 if(r < 0) {
382 fprintf(stderr, "Error calling method: %s\n",
383 strerror(-r));
384 goto unref_intf_slot;
385 }
386
387 *w = wait;
388
389 return 0;
390
391unref_intf_slot:
392 sd_bus_slot_unref(wait->intf_slot);
393unref_name_slot:
394 sd_bus_slot_unref(wait->name_owner_slot);
395free_status:
396 free(wait->status);
397free_objs:
398 sarrayfree(wait->objs);
399free_wait:
400 free(wait);
401
402 return r;
403}
404
Brad Bishop3d468792016-09-20 15:39:38 -0400405int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400406{
407 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400408 sd_bus_message *request = NULL;
409 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400410
411 r = sd_bus_message_new_method_call(
412 conn,
413 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400414 MAPPER_BUSNAME,
415 MAPPER_PATH,
416 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400417 "GetObject");
418 if (r < 0)
419 goto exit;
420
421 r = sd_bus_message_append(request, "s", obj);
422 if (r < 0)
423 goto exit;
424
Brad Bishop3d468792016-09-20 15:39:38 -0400425 while(retry < mapper_busy_retries) {
426 sd_bus_error_free(&error);
427 r = sd_bus_call(conn, request, 0, &error, reply);
428 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
429 ++retry;
430
431 if(retry != mapper_busy_retries)
432 usleep(mapper_busy_delay_interval_usec);
433 continue;
434 }
435 break;
436 }
437
438 if (r < 0)
439 goto exit;
440
441exit:
442 sd_bus_error_free(&error);
443 sd_bus_message_unref(request);
444
445 return r;
446}
447
448int mapper_get_service(sd_bus *conn, const char *obj, char **service)
449{
450 sd_bus_message *reply = NULL;
451 const char *tmp;
452 int r;
453
454 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400455 if (r < 0)
456 goto exit;
457
458 r = sd_bus_message_enter_container(reply, 0, NULL);
459 if (r < 0)
460 goto exit;
461
462 r = sd_bus_message_enter_container(reply, 0, NULL);
463 if (r < 0)
464 goto exit;
465
466 r = sd_bus_message_read(reply, "s", &tmp);
467 if (r < 0)
468 goto exit;
469
470 *service = strdup(tmp);
471
472exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400473 sd_bus_message_unref(reply);
474
475 return r;
476}