blob: 194041e78435e95ec684dbcb2f375903558b8919 [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
Brad Bishop3d468792016-09-20 15:39:38 -040038static const int mapper_busy_retries = 5;
39static const uint64_t mapper_busy_delay_interval_usec = 1000000;
40
Brad Bishop2afe7182016-08-13 14:08:17 -040041struct mapper_async_wait
42{
43 char **objs;
44 void (*callback)(int, void *);
45 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040046 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040047 sd_bus *conn;
Brad Bishop829181d2017-02-24 09:49:14 -050048 sd_bus_slot *introspection_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -040049 sd_bus_slot *intf_slot;
50 int *status;
51 int count;
52 int finished;
53 int r;
54};
55
56struct async_wait_callback_data
57{
58 mapper_async_wait *wait;
59 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040060 sd_event_source *event_source;
61 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040062};
63
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050064struct mapper_async_subtree
65{
66};
67
Brad Bishop829181d2017-02-24 09:49:14 -050068static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040069 sd_bus_error *);
70static int async_wait_check_done(mapper_async_wait *);
71static void async_wait_done(int r, mapper_async_wait *);
72static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040073static int async_wait_getobject_callback(sd_bus_message *,
74 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040075
76static int sarraylen(char *array[])
77{
78 int count = 0;
79 char **p = array;
80
81 while(*p != NULL) {
82 ++count;
83 ++p;
84 }
85
86 return count;
87}
88
89static void sarrayfree(char *array[])
90{
91 char **p = array;
92 while(*p != NULL) {
93 free(*p);
94 ++p;
95 }
96 free(array);
97}
98
99static char **sarraydup(char *array[])
100{
101 int count = sarraylen(array);
102 int i;
103 char **ret = NULL;
104
105 ret = malloc(sizeof(*ret) * count);
106 if(!ret)
107 return NULL;
108
109 for(i=0; i<count; ++i) {
110 ret[i] = strdup(array[i]);
111 if(!ret[i])
112 goto error;
113 }
114
115 return ret;
116
117error:
118 sarrayfree(ret);
119 return NULL;
120}
121
Brad Bishop3d468792016-09-20 15:39:38 -0400122static int async_wait_timeout_callback(sd_event_source *s,
123 uint64_t usec, void *userdata)
124{
125 int r;
126 struct async_wait_callback_data *data = userdata;
127 mapper_async_wait *wait = data->wait;
128
129 sd_event_source_unref(data->event_source);
130 r = sd_bus_call_method_async(
131 wait->conn,
132 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400133 MAPPER_BUSNAME,
134 MAPPER_PATH,
135 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400136 "GetObject",
137 async_wait_getobject_callback,
138 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400139 "sas",
140 data->path,
141 0,
142 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400143 if(r < 0) {
144 async_wait_done(r, wait);
145 free(data);
146 }
147
148 return 0;
149}
150
Brad Bishop2afe7182016-08-13 14:08:17 -0400151static int async_wait_getobject_callback(sd_bus_message *m,
152 void *userdata,
153 sd_bus_error *e)
154{
Brad Bishop3d468792016-09-20 15:39:38 -0400155 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400156 struct async_wait_callback_data *data = userdata;
157 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400158 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400159
160 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400161 goto exit;
162
163 r = sd_bus_message_get_errno(m);
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500164 if(r == ENOENT)
165 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400166
Brad Bishop3d468792016-09-20 15:39:38 -0400167 if(r == EBUSY && data->retry < mapper_busy_retries) {
168 r = sd_event_now(wait->loop,
169 CLOCK_MONOTONIC,
170 &now);
171 if(r < 0) {
172 async_wait_done(r, wait);
173 goto exit;
174 }
175
176 ++data->retry;
177 r = sd_event_add_time(wait->loop,
178 &data->event_source,
179 CLOCK_MONOTONIC,
180 now + mapper_busy_delay_interval_usec,
181 0,
182 async_wait_timeout_callback,
183 data);
184 if(r < 0) {
185 async_wait_done(r, wait);
186 goto exit;
187 }
188
Brad Bishop2afe7182016-08-13 14:08:17 -0400189 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400190 }
191
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400192 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400193 async_wait_done(-r, wait);
194 goto exit;
195 }
196
Brad Bishop2afe7182016-08-13 14:08:17 -0400197 for(i=0; i<wait->count; ++i) {
198 if(!strcmp(data->path, wait->objs[i])) {
199 wait->status[i] = 1;
200 }
201 }
202
Brad Bishop2afe7182016-08-13 14:08:17 -0400203 if(async_wait_check_done(wait))
204 async_wait_done(0, wait);
205
Brad Bishop3d468792016-09-20 15:39:38 -0400206exit:
207 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400208 return 0;
209}
210
211static int async_wait_get_objects(mapper_async_wait *wait)
212{
213 int i, r;
214 struct async_wait_callback_data *data = NULL;
215
216 for(i=0; i<wait->count; ++i) {
217 if(wait->status[i])
218 continue;
219 data = malloc(sizeof(*data));
220 data->wait = wait;
221 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400222 data->retry = 0;
223 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400224 r = sd_bus_call_method_async(
225 wait->conn,
226 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400227 MAPPER_BUSNAME,
228 MAPPER_PATH,
229 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400230 "GetObject",
231 async_wait_getobject_callback,
232 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400233 "sas",
234 wait->objs[i],
235 0,
236 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400237 if(r < 0) {
238 free(data);
239 fprintf(stderr, "Error invoking method: %s\n",
240 strerror(-r));
241 return r;
242 }
243 }
244
245 return 0;
246}
247
Brad Bishop829181d2017-02-24 09:49:14 -0500248static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400249 sd_bus_error *e)
250{
Brad Bishopa6797f82016-08-30 13:02:46 -0400251 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400252
253 mapper_async_wait *wait = w;
254 if(wait->finished)
255 return 0;
256
257 r = async_wait_get_objects(wait);
258 if(r < 0)
259 async_wait_done(r, wait);
260
261 return 0;
262}
263
Brad Bishop2afe7182016-08-13 14:08:17 -0400264static void async_wait_done(int r, mapper_async_wait *w)
265{
266 if(w->finished)
267 return;
268
269 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500270 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400271 sd_bus_slot_unref(w->intf_slot);
272
273 if(w->callback)
274 w->callback(r, w->userdata);
275}
276
277static int async_wait_check_done(mapper_async_wait *w)
278{
279 int i;
280
281 if(w->finished)
282 return 1;
283
284 for(i=0; i<w->count; ++i)
285 if(!w->status[i])
286 return 0;
287
288 return 1;
289}
290
291void mapper_wait_async_free(mapper_async_wait *w)
292{
293 free(w->status);
294 sarrayfree(w->objs);
295 free(w);
296}
297
298int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400299 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400300 char *objs[],
301 void (*callback)(int, void *),
302 void *userdata,
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500303 mapper_async_wait **w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400304{
305 int r;
306 mapper_async_wait *wait = NULL;
307
308 wait = malloc(sizeof(*wait));
309 if(!wait)
310 return -ENOMEM;
311
312 memset(wait, 0, sizeof(*wait));
313 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400314 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400315 wait->callback = callback;
316 wait->userdata = userdata;
317 wait->count = sarraylen(objs);
318 if(!wait->count)
319 return 0;
320
321 wait->objs = sarraydup(objs);
322 if(!wait->objs) {
323 r = -ENOMEM;
324 goto free_wait;
325 }
326
327 wait->status = malloc(sizeof(*wait->status) * wait->count);
328 if(!wait->status) {
329 r = -ENOMEM;
330 goto free_objs;
331 }
332 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
333
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500334 r = sd_bus_add_match(conn,
335 &wait->introspection_slot,
336 async_wait_introspection_match,
337 async_wait_match_introspection_complete,
338 wait);
339 if(r < 0) {
340 fprintf(stderr, "Error adding match rule: %s\n",
341 strerror(-r));
342 goto free_status;
343 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400344
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500345 r = sd_bus_add_match(conn,
346 &wait->intf_slot,
347 async_wait_interfaces_added_match,
348 async_wait_match_introspection_complete,
349 wait);
350 if(r < 0) {
351 fprintf(stderr, "Error adding match rule: %s\n",
352 strerror(-r));
353 goto unref_name_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -0400354 }
355
356 r = async_wait_get_objects(wait);
357 if(r < 0) {
358 fprintf(stderr, "Error calling method: %s\n",
359 strerror(-r));
360 goto unref_intf_slot;
361 }
362
363 *w = wait;
364
365 return 0;
366
367unref_intf_slot:
368 sd_bus_slot_unref(wait->intf_slot);
369unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500370 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400371free_status:
372 free(wait->status);
373free_objs:
374 sarrayfree(wait->objs);
375free_wait:
376 free(wait);
377
378 return r;
379}
380
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500381int mapper_subtree_async(sd_bus *conn,
382 sd_event *loop,
383 char *namespace,
384 char *interface,
385 void (*callback)(int, void *),
386 void *userdata,
387 mapper_async_subtree **t,
388 int op)
389{
390 int r = 0;
391
392 return r;
393}
394
Brad Bishop3d468792016-09-20 15:39:38 -0400395int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400396{
397 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400398 sd_bus_message *request = NULL;
399 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400400
401 r = sd_bus_message_new_method_call(
402 conn,
403 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400404 MAPPER_BUSNAME,
405 MAPPER_PATH,
406 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400407 "GetObject");
408 if (r < 0)
409 goto exit;
410
411 r = sd_bus_message_append(request, "s", obj);
412 if (r < 0)
413 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400414 r = sd_bus_message_append(request, "as", 0, NULL);
415 if (r < 0)
416 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400417
Brad Bishop3d468792016-09-20 15:39:38 -0400418 while(retry < mapper_busy_retries) {
419 sd_bus_error_free(&error);
420 r = sd_bus_call(conn, request, 0, &error, reply);
421 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
422 ++retry;
423
424 if(retry != mapper_busy_retries)
425 usleep(mapper_busy_delay_interval_usec);
426 continue;
427 }
428 break;
429 }
430
431 if (r < 0)
432 goto exit;
433
434exit:
435 sd_bus_error_free(&error);
436 sd_bus_message_unref(request);
437
438 return r;
439}
440
441int mapper_get_service(sd_bus *conn, const char *obj, char **service)
442{
443 sd_bus_message *reply = NULL;
444 const char *tmp;
445 int r;
446
447 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400448 if (r < 0)
449 goto exit;
450
451 r = sd_bus_message_enter_container(reply, 0, NULL);
452 if (r < 0)
453 goto exit;
454
455 r = sd_bus_message_enter_container(reply, 0, NULL);
456 if (r < 0)
457 goto exit;
458
459 r = sd_bus_message_read(reply, "s", &tmp);
460 if (r < 0)
461 goto exit;
462
463 *service = strdup(tmp);
464
465exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400466 sd_bus_message_unref(reply);
467
468 return r;
469}