2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
28 #include <json-c/json.h>
30 #include <afb/afb-req-common.h>
31 #include <afb/afb-event-itf.h>
33 #include "afb-context.h"
35 #include "afb-session.h"
44 * Definition of a hook for xreq
46 struct afb_hook_xreq {
47 struct afb_hook_xreq *next; /**< next hook */
48 unsigned refcount; /**< reference count */
49 char *api; /**< api hooked or NULL for any */
50 char *verb; /**< verb hooked or NULL for any */
51 struct afb_session *session; /**< session hooked or NULL if any */
52 unsigned flags; /**< hook flags */
53 struct afb_hook_xreq_itf *itf; /**< interface of hook */
54 void *closure; /**< closure for callbacks */
58 * Definition of a hook for ditf
60 struct afb_hook_ditf {
61 struct afb_hook_ditf *next; /**< next hook */
62 unsigned refcount; /**< reference count */
63 char *api; /**< api hooked or NULL for any */
64 unsigned flags; /**< hook flags */
65 struct afb_hook_ditf_itf *itf; /**< interface of hook */
66 void *closure; /**< closure for callbacks */
70 * Definition of a hook for svc
73 struct afb_hook_svc *next; /**< next hook */
74 unsigned refcount; /**< reference count */
75 char *api; /**< api hooked or NULL for any */
76 unsigned flags; /**< hook flags */
77 struct afb_hook_svc_itf *itf; /**< interface of hook */
78 void *closure; /**< closure for callbacks */
82 * Definition of a hook for evt
85 struct afb_hook_evt *next; /**< next hook */
86 unsigned refcount; /**< reference count */
87 char *pattern; /**< event pattern name hooked or NULL for any */
88 unsigned flags; /**< hook flags */
89 struct afb_hook_evt_itf *itf; /**< interface of hook */
90 void *closure; /**< closure for callbacks */
93 /* synchronisation across threads */
94 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
96 /* list of hooks for xreq */
97 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
99 /* list of hooks for ditf */
100 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
102 /* list of hooks for svc */
103 static struct afb_hook_svc *list_of_svc_hooks = NULL;
105 /* list of hooks for evt */
106 static struct afb_hook_evt *list_of_evt_hooks = NULL;
109 static unsigned next_hookid = 0;
111 /******************************************************************************
113 *****************************************************************************/
114 static void init_hookid(struct afb_hookid *hookid)
116 hookid->id = __atomic_add_fetch(&next_hookid, 1, __ATOMIC_RELAXED);
117 clock_gettime(CLOCK_MONOTONIC, &hookid->time);
120 /******************************************************************************
121 * section: default callbacks for tracing requests
122 *****************************************************************************/
124 static char *_pbuf_(const char *fmt, va_list args, char **palloc, char *sbuf, size_t szsbuf)
131 rc = vsnprintf(sbuf, szsbuf, fmt, args);
132 if ((size_t)rc >= szsbuf) {
134 sbuf[szsbuf-2] = sbuf[szsbuf-3] = sbuf[szsbuf-4] = '.';
135 rc = vasprintf(palloc, fmt, cp);
143 static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
145 char *tag, *data, *mem1, *mem2, buf1[256], buf2[2000];
148 data = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2);
150 va_start(arg1, arg2);
151 tag = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1);
154 NOTICE("[HOOK %s] %s", tag, data);
160 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
163 va_start(ap, format);
164 _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->api, xreq->verb);
168 static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
171 _hook_xreq_(xreq, "BEGIN");
173 _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
174 (int)xreq->cred->uid,
176 (int)xreq->cred->gid,
177 (int)xreq->cred->pid,
178 xreq->cred->label?:"(null)",
179 xreq->cred->id?:"(null)"
183 static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
185 _hook_xreq_(xreq, "END");
188 static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
190 _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
193 static void hook_xreq_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
195 _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
198 static void hook_xreq_success_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
200 _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
203 static void hook_xreq_fail_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info)
205 _hook_xreq_(xreq, "fail(%s, %s)", status, info);
208 static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
210 _hook_xreq_(xreq, "context_get() -> %p", value);
213 static void hook_xreq_context_set_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
215 _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
218 static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
220 _hook_xreq_(xreq, "addref()");
223 static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
225 _hook_xreq_(xreq, "unref()");
228 static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
230 _hook_xreq_(xreq, "session_close()");
233 static void hook_xreq_session_set_LOA_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
235 _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
238 static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
240 _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
243 static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event event, int result)
245 _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
248 static void hook_xreq_subcall_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
250 _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
253 static void hook_xreq_subcall_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
255 _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
258 static void hook_xreq_subcallsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
260 _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
263 static void hook_xreq_subcallsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
265 _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
268 static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
275 len = vasprintf(&msg, fmt, ap);
279 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
281 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
286 static void hook_xreq_store_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
288 _hook_xreq_(xreq, "store() -> %p", sreq);
291 static void hook_xreq_unstore_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
293 _hook_xreq_(xreq, "unstore()");
296 static void hook_xreq_subcall_req_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
298 _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
301 static void hook_xreq_subcall_req_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result)
303 _hook_xreq_(xreq, " ...subcall_req... -> %d: %s", status, json_object_to_json_string(result));
306 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
307 .hook_xreq_begin = hook_xreq_begin_default_cb,
308 .hook_xreq_end = hook_xreq_end_default_cb,
309 .hook_xreq_json = hook_xreq_json_default_cb,
310 .hook_xreq_get = hook_xreq_get_default_cb,
311 .hook_xreq_success = hook_xreq_success_default_cb,
312 .hook_xreq_fail = hook_xreq_fail_default_cb,
313 .hook_xreq_context_get = hook_xreq_context_get_default_cb,
314 .hook_xreq_context_set = hook_xreq_context_set_default_cb,
315 .hook_xreq_addref = hook_xreq_addref_default_cb,
316 .hook_xreq_unref = hook_xreq_unref_default_cb,
317 .hook_xreq_session_close = hook_xreq_session_close_default_cb,
318 .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
319 .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
320 .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
321 .hook_xreq_subcall = hook_xreq_subcall_default_cb,
322 .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
323 .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
324 .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
325 .hook_xreq_vverbose = hook_xreq_vverbose_default_cb,
326 .hook_xreq_store = hook_xreq_store_default_cb,
327 .hook_xreq_unstore = hook_xreq_unstore_default_cb,
328 .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb,
329 .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb
332 /******************************************************************************
333 * section: hooks for tracing requests
334 *****************************************************************************/
336 #define _HOOK_XREQ_(what,...) \
337 struct afb_hook_xreq *hook; \
338 struct afb_hookid hookid; \
339 pthread_rwlock_rdlock(&rwlock); \
340 init_hookid(&hookid); \
341 hook = list_of_xreq_hooks; \
343 if (hook->itf->hook_xreq_##what \
344 && (hook->flags & afb_hook_flag_req_##what) != 0 \
345 && (!hook->session || hook->session == xreq->context.session) \
346 && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
347 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
348 hook->itf->hook_xreq_##what(hook->closure, &hookid, __VA_ARGS__); \
352 pthread_rwlock_unlock(&rwlock);
355 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
357 _HOOK_XREQ_(begin, xreq);
360 void afb_hook_xreq_end(const struct afb_xreq *xreq)
362 _HOOK_XREQ_(end, xreq);
365 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
367 _HOOK_XREQ_(json, xreq, obj);
371 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
373 _HOOK_XREQ_(get, xreq, name, arg);
377 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
379 _HOOK_XREQ_(success, xreq, obj, info);
382 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
384 _HOOK_XREQ_(fail, xreq, status, info);
387 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
389 _HOOK_XREQ_(context_get, xreq, value);
393 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
395 _HOOK_XREQ_(context_set, xreq, value, free_value);
398 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
400 _HOOK_XREQ_(addref, xreq);
403 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
405 _HOOK_XREQ_(unref, xreq);
408 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
410 _HOOK_XREQ_(session_close, xreq);
413 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
415 _HOOK_XREQ_(session_set_LOA, xreq, level, result);
419 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
421 _HOOK_XREQ_(subscribe, xreq, event, result);
425 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
427 _HOOK_XREQ_(unsubscribe, xreq, event, result);
431 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
433 _HOOK_XREQ_(subcall, xreq, api, verb, args);
436 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
438 _HOOK_XREQ_(subcall_result, xreq, status, result);
441 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
443 _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
446 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
448 _HOOK_XREQ_(subcallsync_result, xreq, status, result);
452 void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
454 _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
457 void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq)
459 _HOOK_XREQ_(store, xreq, sreq);
462 void afb_hook_xreq_unstore(const struct afb_xreq *xreq)
464 _HOOK_XREQ_(unstore, xreq);
467 void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
469 _HOOK_XREQ_(subcall_req, xreq, api, verb, args);
472 void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result)
474 _HOOK_XREQ_(subcall_req_result, xreq, status, result);
477 /******************************************************************************
478 * section: hooking xreqs
479 *****************************************************************************/
481 void afb_hook_init_xreq(struct afb_xreq *xreq)
487 struct afb_hook_xreq *hook;
489 /* scan hook list to get the expected flags */
491 pthread_rwlock_rdlock(&rwlock);
492 hook = list_of_xreq_hooks;
494 f = hook->flags & afb_hook_flags_req_all;
496 && (!hook->session || hook->session == xreq->context.session)
497 && (!hook->api || !strcasecmp(hook->api, xreq->api))
498 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
503 pthread_rwlock_unlock(&rwlock);
505 /* store the hooking data */
506 xreq->hookflags = flags;
508 pthread_rwlock_wrlock(&rwlock);
511 xreq->hookindex = reqindex;
512 pthread_rwlock_unlock(&rwlock);
516 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)
518 struct afb_hook_xreq *hook;
520 /* alloc the result */
521 hook = calloc(1, sizeof *hook);
525 /* get a copy of the names */
526 hook->api = api ? strdup(api) : NULL;
527 hook->verb = verb ? strdup(verb) : NULL;
528 if ((api && !hook->api) || (verb && !hook->verb)) {
535 /* initialise the rest */
536 hook->session = session;
538 afb_session_addref(session);
541 hook->itf = itf ? itf : &hook_xreq_default_itf;
542 hook->closure = closure;
544 /* record the hook */
545 pthread_rwlock_wrlock(&rwlock);
546 hook->next = list_of_xreq_hooks;
547 list_of_xreq_hooks = hook;
548 pthread_rwlock_unlock(&rwlock);
554 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
556 pthread_rwlock_wrlock(&rwlock);
558 pthread_rwlock_unlock(&rwlock);
562 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
564 struct afb_hook_xreq **prv;
567 pthread_rwlock_wrlock(&rwlock);
568 if (--hook->refcount)
572 prv = &list_of_xreq_hooks;
573 while (*prv && *prv != hook)
578 pthread_rwlock_unlock(&rwlock);
584 afb_session_unref(hook->session);
590 /******************************************************************************
591 * section: default callbacks for tracing daemon interface
592 *****************************************************************************/
594 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
597 va_start(ap, format);
598 _hook_("ditf-%s", format, ap, ditf->api);
602 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object)
604 _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
607 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
609 _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
612 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_event *result)
614 _hook_ditf_(ditf, "get_event_loop() -> %p", result);
617 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_bus *result)
619 _hook_ditf_(ditf, "get_user_bus() -> %p", result);
622 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct sd_bus *result)
624 _hook_ditf_(ditf, "get_system_bus() -> %p", result);
627 static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
634 len = vasprintf(&msg, fmt, ap);
638 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
640 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
645 static void hook_ditf_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, struct afb_event result)
647 _hook_ditf_(ditf, "event_make(%s) -> %s:%d", name, afb_evt_event_name(result), afb_evt_event_id(result));
650 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, int result)
654 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
656 sprintf(path, "/proc/self/fd/%d", result);
657 readlink(path, path, sizeof path);
658 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
662 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
668 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
670 sprintf(path, "/proc/self/fd/%d", result);
671 readlink(path, path, sizeof path);
672 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
676 static void hook_ditf_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
678 _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
681 static void hook_ditf_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, struct afb_stored_req *sreq)
683 _hook_ditf_(ditf, "unstore_req(%p)", sreq);
686 static void hook_ditf_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, int initialized)
688 _hook_ditf_(ditf, "require_api(%s, %d)...", name, initialized);
691 static void hook_ditf_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_ditf *ditf, const char *name, int initialized, int result)
693 _hook_ditf_(ditf, "...require_api(%s, %d) -> %d", name, initialized, result);
696 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
697 .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
698 .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
699 .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
700 .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
701 .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
702 .hook_ditf_vverbose = hook_ditf_vverbose_cb,
703 .hook_ditf_event_make = hook_ditf_event_make_cb,
704 .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
705 .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
706 .hook_ditf_queue_job = hook_ditf_queue_job_cb,
707 .hook_ditf_unstore_req = hook_ditf_unstore_req_cb,
708 .hook_ditf_require_api = hook_ditf_require_api_cb,
709 .hook_ditf_require_api_result = hook_ditf_require_api_result_cb
712 /******************************************************************************
713 * section: hooks for tracing daemon interface (ditf)
714 *****************************************************************************/
716 #define _HOOK_DITF_(what,...) \
717 struct afb_hook_ditf *hook; \
718 struct afb_hookid hookid; \
719 pthread_rwlock_rdlock(&rwlock); \
720 init_hookid(&hookid); \
721 hook = list_of_ditf_hooks; \
723 if (hook->itf->hook_ditf_##what \
724 && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
725 && (!hook->api || !strcasecmp(hook->api, ditf->api))) { \
726 hook->itf->hook_ditf_##what(hook->closure, &hookid, __VA_ARGS__); \
730 pthread_rwlock_unlock(&rwlock);
732 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
734 _HOOK_DITF_(event_broadcast_before, ditf, name, object);
737 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
739 _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
743 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
745 _HOOK_DITF_(get_event_loop, ditf, result);
749 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
751 _HOOK_DITF_(get_user_bus, ditf, result);
755 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
757 _HOOK_DITF_(get_system_bus, ditf, result);
761 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)
763 _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
766 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
768 _HOOK_DITF_(event_make, ditf, name, result);
772 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
774 _HOOK_DITF_(rootdir_get_fd, ditf, result);
778 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
780 _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
784 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)
786 _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
790 void afb_hook_ditf_unstore_req(const struct afb_ditf *ditf, struct afb_stored_req *sreq)
792 _HOOK_DITF_(unstore_req, ditf, sreq);
795 void afb_hook_ditf_require_api(const struct afb_ditf *ditf, const char *name, int initialized)
797 _HOOK_DITF_(require_api, ditf, name, initialized);
800 int afb_hook_ditf_require_api_result(const struct afb_ditf *ditf, const char *name, int initialized, int result)
802 _HOOK_DITF_(require_api_result, ditf, name, initialized, result);
806 /******************************************************************************
807 * section: hooking ditf
808 *****************************************************************************/
810 int afb_hook_flags_ditf(const char *api)
813 struct afb_hook_ditf *hook;
815 pthread_rwlock_rdlock(&rwlock);
817 hook = list_of_ditf_hooks;
819 if (!api || !hook->api || !strcasecmp(hook->api, api))
820 flags |= hook->flags;
823 pthread_rwlock_unlock(&rwlock);
827 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
829 struct afb_hook_ditf *hook;
831 /* alloc the result */
832 hook = calloc(1, sizeof *hook);
836 /* get a copy of the names */
837 hook->api = api ? strdup(api) : NULL;
838 if (api && !hook->api) {
843 /* initialise the rest */
846 hook->itf = itf ? itf : &hook_ditf_default_itf;
847 hook->closure = closure;
849 /* record the hook */
850 pthread_rwlock_wrlock(&rwlock);
851 hook->next = list_of_ditf_hooks;
852 list_of_ditf_hooks = hook;
853 pthread_rwlock_unlock(&rwlock);
859 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
861 pthread_rwlock_wrlock(&rwlock);
863 pthread_rwlock_unlock(&rwlock);
867 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
869 struct afb_hook_ditf **prv;
872 pthread_rwlock_wrlock(&rwlock);
873 if (--hook->refcount)
877 prv = &list_of_ditf_hooks;
878 while (*prv && *prv != hook)
883 pthread_rwlock_unlock(&rwlock);
892 /******************************************************************************
893 * section: default callbacks for tracing service interface (svc)
894 *****************************************************************************/
896 static void _hook_svc_(const struct afb_svc *svc, const char *format, ...)
899 va_start(ap, format);
900 _hook_("svc-%s", format, ap, svc->api);
904 static void hook_svc_start_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc)
906 _hook_svc_(svc, "start.before");
909 static void hook_svc_start_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status)
911 _hook_svc_(svc, "start.after -> %d", status);
914 static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
916 _hook_svc_(svc, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
919 static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
921 _hook_svc_(svc, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
924 static void hook_svc_call_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
926 _hook_svc_(svc, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
929 static void hook_svc_call_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status, struct json_object *result)
931 _hook_svc_(svc, " ...call... -> %d: %s", status, json_object_to_json_string(result));
934 static void hook_svc_callsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
936 _hook_svc_(svc, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
939 static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_svc *svc, int status, struct json_object *result)
941 _hook_svc_(svc, " ...callsync... -> %d: %s", status, json_object_to_json_string(result));
944 static struct afb_hook_svc_itf hook_svc_default_itf = {
945 .hook_svc_start_before = hook_svc_start_before_default_cb,
946 .hook_svc_start_after = hook_svc_start_after_default_cb,
947 .hook_svc_on_event_before = hook_svc_on_event_before_default_cb,
948 .hook_svc_on_event_after = hook_svc_on_event_after_default_cb,
949 .hook_svc_call = hook_svc_call_default_cb,
950 .hook_svc_call_result = hook_svc_call_result_default_cb,
951 .hook_svc_callsync = hook_svc_callsync_default_cb,
952 .hook_svc_callsync_result = hook_svc_callsync_result_default_cb
955 /******************************************************************************
956 * section: hooks for tracing service interface (svc)
957 *****************************************************************************/
959 #define _HOOK_SVC_(what,...) \
960 struct afb_hook_svc *hook; \
961 struct afb_hookid hookid; \
962 pthread_rwlock_rdlock(&rwlock); \
963 init_hookid(&hookid); \
964 hook = list_of_svc_hooks; \
966 if (hook->itf->hook_svc_##what \
967 && (hook->flags & afb_hook_flag_svc_##what) != 0 \
968 && (!hook->api || !strcasecmp(hook->api, svc->api))) { \
969 hook->itf->hook_svc_##what(hook->closure, &hookid, __VA_ARGS__); \
973 pthread_rwlock_unlock(&rwlock);
975 void afb_hook_svc_start_before(const struct afb_svc *svc)
977 _HOOK_SVC_(start_before, svc);
980 int afb_hook_svc_start_after(const struct afb_svc *svc, int status)
982 _HOOK_SVC_(start_after, svc, status);
986 void afb_hook_svc_on_event_before(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
988 _HOOK_SVC_(on_event_before, svc, event, eventid, object);
991 void afb_hook_svc_on_event_after(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
993 _HOOK_SVC_(on_event_after, svc, event, eventid, object);
996 void afb_hook_svc_call(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
998 _HOOK_SVC_(call, svc, api, verb, args);
1001 void afb_hook_svc_call_result(const struct afb_svc *svc, int status, struct json_object *result)
1003 _HOOK_SVC_(call_result, svc, status, result);
1006 void afb_hook_svc_callsync(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
1008 _HOOK_SVC_(callsync, svc, api, verb, args);
1011 int afb_hook_svc_callsync_result(const struct afb_svc *svc, int status, struct json_object *result)
1013 _HOOK_SVC_(callsync_result, svc, status, result);
1017 /******************************************************************************
1018 * section: hooking services (svc)
1019 *****************************************************************************/
1021 int afb_hook_flags_svc(const char *api)
1024 struct afb_hook_svc *hook;
1026 pthread_rwlock_rdlock(&rwlock);
1028 hook = list_of_svc_hooks;
1030 if (!api || !hook->api || !strcasecmp(hook->api, api))
1031 flags |= hook->flags;
1034 pthread_rwlock_unlock(&rwlock);
1038 struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure)
1040 struct afb_hook_svc *hook;
1042 /* alloc the result */
1043 hook = calloc(1, sizeof *hook);
1047 /* get a copy of the names */
1048 hook->api = api ? strdup(api) : NULL;
1049 if (api && !hook->api) {
1054 /* initialise the rest */
1056 hook->flags = flags;
1057 hook->itf = itf ? itf : &hook_svc_default_itf;
1058 hook->closure = closure;
1060 /* record the hook */
1061 pthread_rwlock_wrlock(&rwlock);
1062 hook->next = list_of_svc_hooks;
1063 list_of_svc_hooks = hook;
1064 pthread_rwlock_unlock(&rwlock);
1070 struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
1072 pthread_rwlock_wrlock(&rwlock);
1074 pthread_rwlock_unlock(&rwlock);
1078 void afb_hook_unref_svc(struct afb_hook_svc *hook)
1080 struct afb_hook_svc **prv;
1083 pthread_rwlock_wrlock(&rwlock);
1084 if (--hook->refcount)
1088 prv = &list_of_svc_hooks;
1089 while (*prv && *prv != hook)
1090 prv = &(*prv)->next;
1094 pthread_rwlock_unlock(&rwlock);
1103 /******************************************************************************
1104 * section: default callbacks for tracing service interface (evt)
1105 *****************************************************************************/
1107 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1110 va_start(ap, format);
1111 _hook_("evt-%s:%d", format, ap, evt, id);
1115 static void hook_evt_create_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1117 _hook_evt_(evt, id, "create");
1120 static void hook_evt_push_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1122 _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1126 static void hook_evt_push_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1128 _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1131 static void hook_evt_broadcast_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1133 _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1136 static void hook_evt_broadcast_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1138 _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1141 static void hook_evt_name_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1143 _hook_evt_(evt, id, "name");
1146 static void hook_evt_drop_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1148 _hook_evt_(evt, id, "drop");
1151 static struct afb_hook_evt_itf hook_evt_default_itf = {
1152 .hook_evt_create = hook_evt_create_default_cb,
1153 .hook_evt_push_before = hook_evt_push_before_default_cb,
1154 .hook_evt_push_after = hook_evt_push_after_default_cb,
1155 .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb,
1156 .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb,
1157 .hook_evt_name = hook_evt_name_default_cb,
1158 .hook_evt_drop = hook_evt_drop_default_cb
1161 /******************************************************************************
1162 * section: hooks for tracing service interface (evt)
1163 *****************************************************************************/
1165 #define _HOOK_EVT_(what,...) \
1166 struct afb_hook_evt *hook; \
1167 struct afb_hookid hookid; \
1168 pthread_rwlock_rdlock(&rwlock); \
1169 init_hookid(&hookid); \
1170 hook = list_of_evt_hooks; \
1172 if (hook->itf->hook_evt_##what \
1173 && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1174 && (!hook->pattern || !fnmatch(hook->pattern, evt, FNM_CASEFOLD))) { \
1175 hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \
1177 hook = hook->next; \
1179 pthread_rwlock_unlock(&rwlock);
1181 void afb_hook_evt_create(const char *evt, int id)
1183 _HOOK_EVT_(create, evt, id);
1186 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1188 _HOOK_EVT_(push_before, evt, id, obj);
1191 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1193 _HOOK_EVT_(push_after, evt, id, obj, result);
1197 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1199 _HOOK_EVT_(broadcast_before, evt, id, obj);
1202 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1204 _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1208 void afb_hook_evt_name(const char *evt, int id)
1210 _HOOK_EVT_(name, evt, id);
1213 void afb_hook_evt_drop(const char *evt, int id)
1215 _HOOK_EVT_(drop, evt, id);
1218 /******************************************************************************
1219 * section: hooking services (evt)
1220 *****************************************************************************/
1222 int afb_hook_flags_evt(const char *name)
1225 struct afb_hook_evt *hook;
1227 pthread_rwlock_rdlock(&rwlock);
1229 hook = list_of_evt_hooks;
1231 if (!name || !hook->pattern || !fnmatch(hook->pattern, name, FNM_CASEFOLD))
1232 flags |= hook->flags;
1235 pthread_rwlock_unlock(&rwlock);
1239 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1241 struct afb_hook_evt *hook;
1243 /* alloc the result */
1244 hook = calloc(1, sizeof *hook);
1248 /* get a copy of the names */
1249 hook->pattern = pattern ? strdup(pattern) : NULL;
1250 if (pattern && !hook->pattern) {
1255 /* initialise the rest */
1257 hook->flags = flags;
1258 hook->itf = itf ? itf : &hook_evt_default_itf;
1259 hook->closure = closure;
1261 /* record the hook */
1262 pthread_rwlock_wrlock(&rwlock);
1263 hook->next = list_of_evt_hooks;
1264 list_of_evt_hooks = hook;
1265 pthread_rwlock_unlock(&rwlock);
1271 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1273 pthread_rwlock_wrlock(&rwlock);
1275 pthread_rwlock_unlock(&rwlock);
1279 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1281 struct afb_hook_evt **prv;
1284 pthread_rwlock_wrlock(&rwlock);
1285 if (--hook->refcount)
1289 prv = &list_of_evt_hooks;
1290 while (*prv && *prv != hook)
1291 prv = &(*prv)->next;
1295 pthread_rwlock_unlock(&rwlock);
1298 free(hook->pattern);