Add 'afb_daemon_queue_job' for bindings
[src/app-framework-binder.git] / src / afb-hook.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <unistd.h>
26
27 #include <json-c/json.h>
28
29 #include <afb/afb-req-itf.h>
30 #include <afb/afb-event-itf.h>
31
32 #include "afb-context.h"
33 #include "afb-hook.h"
34 #include "afb-session.h"
35 #include "afb-xreq.h"
36 #include "afb-ditf.h"
37 #include "verbose.h"
38
39 /**
40  * Definition of a hook for xreq
41  */
42 struct afb_hook_xreq {
43         struct afb_hook_xreq *next; /**< next hook */
44         unsigned refcount; /**< reference count */
45         char *api; /**< api hooked or NULL for any */
46         char *verb; /**< verb hooked or NULL for any */
47         struct afb_session *session; /**< session hooked or NULL if any */
48         unsigned flags; /**< hook flags */
49         struct afb_hook_xreq_itf *itf; /**< interface of hook */
50         void *closure; /**< closure for callbacks */
51 };
52
53 /**
54  * Definition of a hook for ditf
55  */
56 struct afb_hook_ditf {
57         struct afb_hook_ditf *next; /**< next hook */
58         unsigned refcount; /**< reference count */
59         char *api; /**< api hooked or NULL for any */
60         unsigned flags; /**< hook flags */
61         struct afb_hook_ditf_itf *itf; /**< interface of hook */
62         void *closure; /**< closure for callbacks */
63 };
64
65 /* synchronisation across threads */
66 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
67
68 /* list of hooks for xreq */
69 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
70
71 /* list of hooks for ditf */
72 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
73
74 /******************************************************************************
75  * section: default callbacks for tracing requests
76  *****************************************************************************/
77
78 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
79 {
80         int len;
81         char *buffer;
82         va_list ap;
83
84         va_start(ap, format);
85         len = vasprintf(&buffer, format, ap);
86         va_end(ap);
87
88         if (len < 0)
89                 NOTICE("hook xreq-%06d:%s/%s allocation error", xreq->hookindex, xreq->api, xreq->verb);
90         else {
91                 NOTICE("hook xreq-%06d:%s/%s %s", xreq->hookindex, xreq->api, xreq->verb, buffer);
92                 free(buffer);
93         }
94 }
95
96 static void hook_xreq_begin_default_cb(void * closure, const struct afb_xreq *xreq)
97 {
98         _hook_xreq_(xreq, "BEGIN");
99 }
100
101 static void hook_xreq_end_default_cb(void * closure, const struct afb_xreq *xreq)
102 {
103         _hook_xreq_(xreq, "END");
104 }
105
106 static void hook_xreq_json_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj)
107 {
108         _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
109 }
110
111 static void hook_xreq_get_default_cb(void * closure, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
112 {
113         _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
114 }
115
116 static void hook_xreq_success_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
117 {
118         _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
119 }
120
121 static void hook_xreq_fail_default_cb(void * closure, const struct afb_xreq *xreq, const char *status, const char *info)
122 {
123         _hook_xreq_(xreq, "fail(%s, %s)", status, info);
124 }
125
126 static void hook_xreq_raw_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
127 {
128         _hook_xreq_(xreq, "raw() -> %.*s", (int)size, buffer);
129 }
130
131 static void hook_xreq_send_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
132 {
133         _hook_xreq_(xreq, "send(%.*s)", (int)size, buffer);
134 }
135
136 static void hook_xreq_context_get_default_cb(void * closure, const struct afb_xreq *xreq, void *value)
137 {
138         _hook_xreq_(xreq, "context_get() -> %p", value);
139 }
140
141 static void hook_xreq_context_set_default_cb(void * closure, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
142 {
143         _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
144 }
145
146 static void hook_xreq_addref_default_cb(void * closure, const struct afb_xreq *xreq)
147 {
148         _hook_xreq_(xreq, "addref()");
149 }
150
151 static void hook_xreq_unref_default_cb(void * closure, const struct afb_xreq *xreq)
152 {
153         _hook_xreq_(xreq, "unref()");
154 }
155
156 static void hook_xreq_session_close_default_cb(void * closure, const struct afb_xreq *xreq)
157 {
158         _hook_xreq_(xreq, "session_close()");
159 }
160
161 static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct afb_xreq *xreq, unsigned level, int result)
162 {
163         _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
164 }
165
166 static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
167 {
168         _hook_xreq_(xreq, "subscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
169 }
170
171 static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
172 {
173         _hook_xreq_(xreq, "unsubscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
174 }
175
176 static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
177 {
178         _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
179 }
180
181 static void hook_xreq_subcall_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
182 {
183         _hook_xreq_(xreq, "    ...subcall... -> %d: %s", status, json_object_to_json_string(result));
184 }
185
186 static void hook_xreq_subcallsync_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
187 {
188         _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
189 }
190
191 static void hook_xreq_subcallsync_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
192 {
193         _hook_xreq_(xreq, "    ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
194 }
195
196 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
197         .hook_xreq_begin = hook_xreq_begin_default_cb,
198         .hook_xreq_end = hook_xreq_end_default_cb,
199         .hook_xreq_json = hook_xreq_json_default_cb,
200         .hook_xreq_get = hook_xreq_get_default_cb,
201         .hook_xreq_success = hook_xreq_success_default_cb,
202         .hook_xreq_fail = hook_xreq_fail_default_cb,
203         .hook_xreq_raw = hook_xreq_raw_default_cb,
204         .hook_xreq_send = hook_xreq_send_default_cb,
205         .hook_xreq_context_get = hook_xreq_context_get_default_cb,
206         .hook_xreq_context_set = hook_xreq_context_set_default_cb,
207         .hook_xreq_addref = hook_xreq_addref_default_cb,
208         .hook_xreq_unref = hook_xreq_unref_default_cb,
209         .hook_xreq_session_close = hook_xreq_session_close_default_cb,
210         .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
211         .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
212         .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
213         .hook_xreq_subcall = hook_xreq_subcall_default_cb,
214         .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
215         .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
216         .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
217 };
218
219 /******************************************************************************
220  * section: hooks for tracing requests
221  *****************************************************************************/
222
223 #define _HOOK_XREQ_(what,...)   \
224         struct afb_hook_xreq *hook; \
225         pthread_rwlock_rdlock(&rwlock); \
226         hook = list_of_xreq_hooks; \
227         while (hook) { \
228                 if (hook->itf->hook_xreq_##what \
229                  && (hook->flags & afb_hook_flag_req_##what) != 0 \
230                  && (!hook->session || hook->session == xreq->context.session) \
231                  && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
232                  && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
233                         hook->itf->hook_xreq_##what(hook->closure, __VA_ARGS__); \
234                 } \
235                 hook = hook->next; \
236         } \
237         pthread_rwlock_unlock(&rwlock);
238
239
240 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
241 {
242         _HOOK_XREQ_(begin, xreq);
243 }
244
245 void afb_hook_xreq_end(const struct afb_xreq *xreq)
246 {
247         _HOOK_XREQ_(end, xreq);
248 }
249
250 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
251 {
252         _HOOK_XREQ_(json, xreq, obj);
253         return obj;
254 }
255
256 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
257 {
258         _HOOK_XREQ_(get, xreq, name, arg);
259         return arg;
260 }
261
262 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
263 {
264         _HOOK_XREQ_(success, xreq, obj, info);
265 }
266
267 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
268 {
269         _HOOK_XREQ_(fail, xreq, status, info);
270 }
271
272 const char *afb_hook_xreq_raw(const struct afb_xreq *xreq, const char *buffer, size_t size)
273 {
274         _HOOK_XREQ_(raw, xreq, buffer, size);
275         return buffer;
276 }
277
278 void afb_hook_xreq_send(const struct afb_xreq *xreq, const char *buffer, size_t size)
279 {
280         _HOOK_XREQ_(send, xreq, buffer, size);
281 }
282
283 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
284 {
285         _HOOK_XREQ_(context_get, xreq, value);
286         return value;
287 }
288
289 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
290 {
291         _HOOK_XREQ_(context_set, xreq, value, free_value);
292 }
293
294 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
295 {
296         _HOOK_XREQ_(addref, xreq);
297 }
298
299 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
300 {
301         _HOOK_XREQ_(unref, xreq);
302 }
303
304 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
305 {
306         _HOOK_XREQ_(session_close, xreq);
307 }
308
309 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
310 {
311         _HOOK_XREQ_(session_set_LOA, xreq, level, result);
312         return result;
313 }
314
315 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
316 {
317         _HOOK_XREQ_(subscribe, xreq, event, result);
318         return result;
319 }
320
321 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
322 {
323         _HOOK_XREQ_(unsubscribe, xreq, event, result);
324         return result;
325 }
326
327 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
328 {
329         _HOOK_XREQ_(subcall, xreq, api, verb, args);
330 }
331
332 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
333 {
334         _HOOK_XREQ_(subcall_result, xreq, status, result);
335 }
336
337 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
338 {
339         _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
340 }
341
342 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
343 {
344         _HOOK_XREQ_(subcallsync_result, xreq, status, result);
345         return status;
346 }
347
348 /******************************************************************************
349  * section: 
350  *****************************************************************************/
351
352 void afb_hook_init_xreq(struct afb_xreq *xreq)
353 {
354         static int reqindex;
355
356         int f, flags;
357         int add;
358         struct afb_hook_xreq *hook;
359
360         /* scan hook list to get the expected flags */
361         flags = 0;
362         pthread_rwlock_rdlock(&rwlock);
363         hook = list_of_xreq_hooks;
364         while (hook) {
365                 f = hook->flags & afb_hook_flags_req_all;
366                 add = f != 0
367                    && (!hook->session || hook->session == xreq->context.session)
368                    && (!hook->api || !strcasecmp(hook->api, xreq->api))
369                    && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
370                 if (add)
371                         flags |= f;
372                 hook = hook->next;
373         }
374         pthread_rwlock_unlock(&rwlock);
375
376         /* store the hooking data */
377         xreq->hookflags = flags;
378         if (flags) {
379                 pthread_rwlock_wrlock(&rwlock);
380                 if (++reqindex < 0)
381                         reqindex = 1;
382                 xreq->hookindex = reqindex;
383                 pthread_rwlock_unlock(&rwlock);
384         }
385 }
386
387 struct afb_hook_xreq *afb_hook_create_xreq(const char *api, const char *verb, struct afb_session *session, int flags, struct afb_hook_xreq_itf *itf, void *closure)
388 {
389         struct afb_hook_xreq *hook;
390
391         /* alloc the result */
392         hook = calloc(1, sizeof *hook);
393         if (hook == NULL)
394                 return NULL;
395
396         /* get a copy of the names */
397         hook->api = api ? strdup(api) : NULL;
398         hook->verb = verb ? strdup(verb) : NULL;
399         if ((api && !hook->api) || (verb && !hook->verb)) {
400                 free(hook->api);
401                 free(hook->verb);
402                 free(hook);
403                 return NULL;
404         }
405
406         /* initialise the rest */
407         hook->session = session;
408         if (session)
409                 afb_session_addref(session);
410         hook->refcount = 1;
411         hook->flags = flags;
412         hook->itf = itf ? itf : &hook_xreq_default_itf;
413         hook->closure = closure;
414
415         /* record the hook */
416         pthread_rwlock_wrlock(&rwlock);
417         hook->next = list_of_xreq_hooks;
418         list_of_xreq_hooks = hook;
419         pthread_rwlock_unlock(&rwlock);
420
421         /* returns it */
422         return hook;
423 }
424
425 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
426 {
427         pthread_rwlock_wrlock(&rwlock);
428         hook->refcount++;
429         pthread_rwlock_unlock(&rwlock);
430         return hook;
431 }
432
433 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
434 {
435         struct afb_hook_xreq **prv;
436
437         if (hook) {
438                 pthread_rwlock_wrlock(&rwlock);
439                 if (--hook->refcount)
440                         hook = NULL;
441                 else {
442                         /* unlink */
443                         prv = &list_of_xreq_hooks;
444                         while (*prv && *prv != hook)
445                                 prv = &(*prv)->next;
446                         if(*prv)
447                                 *prv = hook->next;
448                 }
449                 pthread_rwlock_unlock(&rwlock);
450                 if (hook) {
451                         /* free */
452                         free(hook->api);
453                         free(hook->verb);
454                         if (hook->session)
455                                 afb_session_unref(hook->session);
456                         free(hook);
457                 }
458         }
459 }
460
461 /******************************************************************************
462  * section: default callbacks for tracing daemon interface
463  *****************************************************************************/
464
465 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
466 {
467         int len;
468         char *buffer;
469         va_list ap;
470
471         va_start(ap, format);
472         len = vasprintf(&buffer, format, ap);
473         va_end(ap);
474
475         if (len < 0)
476                 NOTICE("hook ditf-%s allocation error for %s", ditf->prefix, format);
477         else {
478                 NOTICE("hook ditf-%s %s", ditf->prefix, buffer);
479                 free(buffer);
480         }
481 }
482
483 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object)
484 {
485         _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
486 }
487
488 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
489 {
490         _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
491 }
492
493 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_ditf *ditf, struct sd_event *result)
494 {
495         _hook_ditf_(ditf, "get_event_loop() -> %p", result);
496 }
497
498 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
499 {
500         _hook_ditf_(ditf, "get_user_bus() -> %p", result);
501 }
502
503 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
504 {
505         _hook_ditf_(ditf, "get_system_bus() -> %p", result);
506 }
507
508 static void hook_ditf_vverbose_cb(void*closure, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
509 {
510         int len;
511         char *msg;
512         va_list ap;
513
514         va_copy(ap, args);
515         len = vasprintf(&msg, fmt, ap);
516         va_end(ap);
517
518         if (len < 0)
519                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
520         else {
521                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
522                 free(msg);
523         }
524 }
525
526 static void hook_ditf_event_make_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct afb_event result)
527 {
528         _hook_ditf_(ditf, "event_make(%s) -> %s:%p", name, afb_event_name(result), result.closure);
529 }
530
531 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_ditf *ditf, int result)
532 {
533         char path[PATH_MAX];
534         if (result < 0)
535                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
536         else {
537                 sprintf(path, "/proc/self/fd/%d", result);
538                 readlink(path, path, sizeof path);
539                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
540         }
541 }
542
543 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
544 {
545         char path[PATH_MAX];
546         if (!locale)
547                 locale = "(null)";
548         if (result < 0)
549                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
550         else {
551                 sprintf(path, "/proc/self/fd/%d", result);
552                 readlink(path, path, sizeof path);
553                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
554         }
555 }
556
557 static void hook_ditf_queue_job(void *closure, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
558 {
559         _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
560 }
561
562 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
563         .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
564         .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
565         .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
566         .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
567         .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
568         .hook_ditf_vverbose = hook_ditf_vverbose_cb,
569         .hook_ditf_event_make = hook_ditf_event_make_cb,
570         .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
571         .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
572         .hook_ditf_queue_job = hook_ditf_queue_job
573 };
574
575 /******************************************************************************
576  * section: hooks for tracing requests
577  *****************************************************************************/
578
579 #define _HOOK_DITF_(what,...)   \
580         struct afb_hook_ditf *hook; \
581         pthread_rwlock_rdlock(&rwlock); \
582         hook = list_of_ditf_hooks; \
583         while (hook) { \
584                 if (hook->itf->hook_ditf_##what \
585                  && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
586                  && (!hook->api || !strcasecmp(hook->api, ditf->prefix))) { \
587                         hook->itf->hook_ditf_##what(hook->closure, __VA_ARGS__); \
588                 } \
589                 hook = hook->next; \
590         } \
591         pthread_rwlock_unlock(&rwlock);
592
593 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
594 {
595         _HOOK_DITF_(event_broadcast_before, ditf, name, object);
596 }
597
598 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
599 {
600         _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
601         return result;
602 }
603
604 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
605 {
606         _HOOK_DITF_(get_event_loop, ditf, result);
607         return result;
608 }
609
610 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
611 {
612         _HOOK_DITF_(get_user_bus, ditf, result);
613         return result;
614 }
615
616 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
617 {
618         _HOOK_DITF_(get_system_bus, ditf, result);
619         return result;
620 }
621
622 void afb_hook_ditf_vverbose(const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
623 {
624         _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
625 }
626
627 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
628 {
629         _HOOK_DITF_(event_make, ditf, name, result);
630         return result;
631 }
632
633 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
634 {
635         _HOOK_DITF_(rootdir_get_fd, ditf, result);
636         return result;
637 }
638
639 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
640 {
641         _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
642         return result;
643 }
644
645 int afb_hook_ditf_queue_job(const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
646 {
647         _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
648         return result;
649 }
650
651 /******************************************************************************
652  * section: 
653  *****************************************************************************/
654
655 int afb_hook_flags_ditf(const char *api)
656 {
657         int flags;
658         struct afb_hook_ditf *hook;
659
660         pthread_rwlock_rdlock(&rwlock);
661         flags = 0;
662         hook = list_of_ditf_hooks;
663         while (hook) {
664                 if (!api || !hook->api || !strcasecmp(hook->api, api))
665                         flags |= hook->flags;
666                 hook = hook->next;
667         }
668         pthread_rwlock_unlock(&rwlock);
669         return flags;
670 }
671
672 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
673 {
674         struct afb_hook_ditf *hook;
675
676         /* alloc the result */
677         hook = calloc(1, sizeof *hook);
678         if (hook == NULL)
679                 return NULL;
680
681         /* get a copy of the names */
682         hook->api = api ? strdup(api) : NULL;
683         if (api && !hook->api) {
684                 free(hook);
685                 return NULL;
686         }
687
688         /* initialise the rest */
689         hook->refcount = 1;
690         hook->flags = flags;
691         hook->itf = itf ? itf : &hook_ditf_default_itf;
692         hook->closure = closure;
693
694         /* record the hook */
695         pthread_rwlock_wrlock(&rwlock);
696         hook->next = list_of_ditf_hooks;
697         list_of_ditf_hooks = hook;
698         pthread_rwlock_unlock(&rwlock);
699
700         /* returns it */
701         return hook;
702 }
703
704 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
705 {
706         pthread_rwlock_wrlock(&rwlock);
707         hook->refcount++;
708         pthread_rwlock_unlock(&rwlock);
709         return hook;
710 }
711
712 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
713 {
714         struct afb_hook_ditf **prv;
715
716         if (hook) {
717                 pthread_rwlock_wrlock(&rwlock);
718                 if (--hook->refcount)
719                         hook = NULL;
720                 else {
721                         /* unlink */
722                         prv = &list_of_ditf_hooks;
723                         while (*prv && *prv != hook)
724                                 prv = &(*prv)->next;
725                         if(*prv)
726                                 *prv = hook->next;
727                 }
728                 pthread_rwlock_unlock(&rwlock);
729                 if (hook) {
730                         /* free */
731                         free(hook->api);
732                         free(hook);
733                 }
734         }
735 }
736