blob: ad64d4a63303a0e4bef351c41a516cbe3e742054 [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 Bishop829181d2017-02-24 09:49:14 -050027static const char *async_wait_introspection_match =
Brad Bishop2afe7182016-08-13 14:08:17 -040028 "type='signal',"
Brad Bishop829181d2017-02-24 09:49:14 -050029 "sender='xyz.openbmc_project.ObjectMapper',"
30 "interface='xyz.openbmc_project.ObjectMapper.Private',"
31 "member='IntrospectionComplete'";
Brad Bishop2afe7182016-08-13 14:08:17 -040032
33static const char *async_wait_interfaces_added_match =
34 "type='signal',"
35 "interface='org.freedesktop.DBus.ObjectManager',"
36 "member='InterfacesAdded'";
37
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -050038static const char *async_wait_interfaces_removed_match =
39 "type='signal',"
40 "interface='org.freedesktop.DBus.ObjectManager',"
41 "member='InterfacesRemoved'";
42
Brad Bishop3d468792016-09-20 15:39:38 -040043static const int mapper_busy_retries = 5;
44static const uint64_t mapper_busy_delay_interval_usec = 1000000;
45
Brad Bishop2afe7182016-08-13 14:08:17 -040046struct mapper_async_wait
47{
48 char **objs;
49 void (*callback)(int, void *);
50 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040051 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040052 sd_bus *conn;
Brad Bishop829181d2017-02-24 09:49:14 -050053 sd_bus_slot *introspection_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -040054 sd_bus_slot *intf_slot;
55 int *status;
56 int count;
57 int finished;
58 int r;
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -050059 bool added;
Brad Bishop2afe7182016-08-13 14:08:17 -040060};
61
62struct async_wait_callback_data
63{
64 mapper_async_wait *wait;
65 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040066 sd_event_source *event_source;
67 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040068};
69
Brad Bishop829181d2017-02-24 09:49:14 -050070static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040071 sd_bus_error *);
72static int async_wait_check_done(mapper_async_wait *);
73static void async_wait_done(int r, mapper_async_wait *);
74static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040075static int async_wait_getobject_callback(sd_bus_message *,
76 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040077
78static int sarraylen(char *array[])
79{
80 int count = 0;
81 char **p = array;
82
83 while(*p != NULL) {
84 ++count;
85 ++p;
86 }
87
88 return count;
89}
90
91static void sarrayfree(char *array[])
92{
93 char **p = array;
94 while(*p != NULL) {
95 free(*p);
96 ++p;
97 }
98 free(array);
99}
100
101static char **sarraydup(char *array[])
102{
103 int count = sarraylen(array);
104 int i;
105 char **ret = NULL;
106
107 ret = malloc(sizeof(*ret) * count);
108 if(!ret)
109 return NULL;
110
111 for(i=0; i<count; ++i) {
112 ret[i] = strdup(array[i]);
113 if(!ret[i])
114 goto error;
115 }
116
117 return ret;
118
119error:
120 sarrayfree(ret);
121 return NULL;
122}
123
Brad Bishop3d468792016-09-20 15:39:38 -0400124static int async_wait_timeout_callback(sd_event_source *s,
125 uint64_t usec, void *userdata)
126{
127 int r;
128 struct async_wait_callback_data *data = userdata;
129 mapper_async_wait *wait = data->wait;
130
131 sd_event_source_unref(data->event_source);
132 r = sd_bus_call_method_async(
133 wait->conn,
134 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400135 MAPPER_BUSNAME,
136 MAPPER_PATH,
137 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400138 "GetObject",
139 async_wait_getobject_callback,
140 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400141 "sas",
142 data->path,
143 0,
144 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400145 if(r < 0) {
146 async_wait_done(r, wait);
147 free(data);
148 }
149
150 return 0;
151}
152
Brad Bishop2afe7182016-08-13 14:08:17 -0400153static int async_wait_getobject_callback(sd_bus_message *m,
154 void *userdata,
155 sd_bus_error *e)
156{
Brad Bishop3d468792016-09-20 15:39:38 -0400157 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400158 struct async_wait_callback_data *data = userdata;
159 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400160 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400161
162 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400163 goto exit;
164
165 r = sd_bus_message_get_errno(m);
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500166 if(r == ENOENT) {
167 if (wait->added)
168 goto exit;
169 else
170 r = 0;
171 }
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400172
Brad Bishop3d468792016-09-20 15:39:38 -0400173 if(r == EBUSY && data->retry < mapper_busy_retries) {
174 r = sd_event_now(wait->loop,
175 CLOCK_MONOTONIC,
176 &now);
177 if(r < 0) {
178 async_wait_done(r, wait);
179 goto exit;
180 }
181
182 ++data->retry;
183 r = sd_event_add_time(wait->loop,
184 &data->event_source,
185 CLOCK_MONOTONIC,
186 now + mapper_busy_delay_interval_usec,
187 0,
188 async_wait_timeout_callback,
189 data);
190 if(r < 0) {
191 async_wait_done(r, wait);
192 goto exit;
193 }
194
Brad Bishop2afe7182016-08-13 14:08:17 -0400195 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400196 }
197
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400198 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400199 async_wait_done(-r, wait);
200 goto exit;
201 }
202
Brad Bishop2afe7182016-08-13 14:08:17 -0400203 for(i=0; i<wait->count; ++i) {
204 if(!strcmp(data->path, wait->objs[i])) {
205 wait->status[i] = 1;
206 }
207 }
208
Brad Bishop2afe7182016-08-13 14:08:17 -0400209 if(async_wait_check_done(wait))
210 async_wait_done(0, wait);
211
Brad Bishop3d468792016-09-20 15:39:38 -0400212exit:
213 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400214 return 0;
215}
216
217static int async_wait_get_objects(mapper_async_wait *wait)
218{
219 int i, r;
220 struct async_wait_callback_data *data = NULL;
221
222 for(i=0; i<wait->count; ++i) {
223 if(wait->status[i])
224 continue;
225 data = malloc(sizeof(*data));
226 data->wait = wait;
227 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400228 data->retry = 0;
229 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400230 r = sd_bus_call_method_async(
231 wait->conn,
232 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400233 MAPPER_BUSNAME,
234 MAPPER_PATH,
235 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400236 "GetObject",
237 async_wait_getobject_callback,
238 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400239 "sas",
240 wait->objs[i],
241 0,
242 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400243 if(r < 0) {
244 free(data);
245 fprintf(stderr, "Error invoking method: %s\n",
246 strerror(-r));
247 return r;
248 }
249 }
250
251 return 0;
252}
253
Brad Bishop829181d2017-02-24 09:49:14 -0500254static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400255 sd_bus_error *e)
256{
Brad Bishopa6797f82016-08-30 13:02:46 -0400257 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400258
259 mapper_async_wait *wait = w;
260 if(wait->finished)
261 return 0;
262
263 r = async_wait_get_objects(wait);
264 if(r < 0)
265 async_wait_done(r, wait);
266
267 return 0;
268}
269
Brad Bishop2afe7182016-08-13 14:08:17 -0400270static void async_wait_done(int r, mapper_async_wait *w)
271{
272 if(w->finished)
273 return;
274
275 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500276 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400277 sd_bus_slot_unref(w->intf_slot);
278
279 if(w->callback)
280 w->callback(r, w->userdata);
281}
282
283static int async_wait_check_done(mapper_async_wait *w)
284{
285 int i;
286
287 if(w->finished)
288 return 1;
289
290 for(i=0; i<w->count; ++i)
291 if(!w->status[i])
292 return 0;
293
294 return 1;
295}
296
297void mapper_wait_async_free(mapper_async_wait *w)
298{
299 free(w->status);
300 sarrayfree(w->objs);
301 free(w);
302}
303
304int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400305 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400306 char *objs[],
307 void (*callback)(int, void *),
308 void *userdata,
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500309 mapper_async_wait **w,
310 bool added)
Brad Bishop2afe7182016-08-13 14:08:17 -0400311{
312 int r;
313 mapper_async_wait *wait = NULL;
314
315 wait = malloc(sizeof(*wait));
316 if(!wait)
317 return -ENOMEM;
318
319 memset(wait, 0, sizeof(*wait));
320 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400321 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400322 wait->callback = callback;
323 wait->userdata = userdata;
324 wait->count = sarraylen(objs);
325 if(!wait->count)
326 return 0;
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500327 wait->added = added;
Brad Bishop2afe7182016-08-13 14:08:17 -0400328
329 wait->objs = sarraydup(objs);
330 if(!wait->objs) {
331 r = -ENOMEM;
332 goto free_wait;
333 }
334
335 wait->status = malloc(sizeof(*wait->status) * wait->count);
336 if(!wait->status) {
337 r = -ENOMEM;
338 goto free_objs;
339 }
340 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
341
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500342 if (wait->added) {
343 r = sd_bus_add_match(conn,
344 &wait->introspection_slot,
345 async_wait_introspection_match,
346 async_wait_match_introspection_complete,
347 wait);
348 if(r < 0) {
349 fprintf(stderr, "Error adding match rule: %s\n",
350 strerror(-r));
351 goto free_status;
352 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400353
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500354 r = sd_bus_add_match(conn,
355 &wait->intf_slot,
356 async_wait_interfaces_added_match,
357 async_wait_match_introspection_complete,
358 wait);
359 if(r < 0) {
360 fprintf(stderr, "Error adding match rule: %s\n",
361 strerror(-r));
362 goto unref_name_slot;
363 }
364 } else {
365 r = sd_bus_add_match(conn,
366 &wait->intf_slot,
367 async_wait_interfaces_removed_match,
368 async_wait_match_introspection_complete,
369 wait);
370 if(r < 0) {
371 fprintf(stderr, "Error adding match rule: %s\n",
372 strerror(-r));
373 goto unref_name_slot;
374 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400375 }
376
377 r = async_wait_get_objects(wait);
378 if(r < 0) {
379 fprintf(stderr, "Error calling method: %s\n",
380 strerror(-r));
381 goto unref_intf_slot;
382 }
383
384 *w = wait;
385
386 return 0;
387
388unref_intf_slot:
389 sd_bus_slot_unref(wait->intf_slot);
390unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500391 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400392free_status:
393 free(wait->status);
394free_objs:
395 sarrayfree(wait->objs);
396free_wait:
397 free(wait);
398
399 return r;
400}
401
Brad Bishop3d468792016-09-20 15:39:38 -0400402int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400403{
404 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400405 sd_bus_message *request = NULL;
406 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400407
408 r = sd_bus_message_new_method_call(
409 conn,
410 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400411 MAPPER_BUSNAME,
412 MAPPER_PATH,
413 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400414 "GetObject");
415 if (r < 0)
416 goto exit;
417
418 r = sd_bus_message_append(request, "s", obj);
419 if (r < 0)
420 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400421 r = sd_bus_message_append(request, "as", 0, NULL);
422 if (r < 0)
423 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400424
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}