d9fd1a37b7143c32f150588c160a35a232402e5e
[src/app-framework-binder.git] / src / afb-hook.c
1 /*
2  * Copyright (C) 2016, 2017, 2018 "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 #include <sys/uio.h>
27
28 #include <json-c/json.h>
29
30 #include <afb/afb-req-x1.h>
31 #include <afb/afb-event-x2.h>
32
33 #include "afb-context.h"
34 #include "afb-hook.h"
35 #include "afb-session.h"
36 #include "afb-cred.h"
37 #include "afb-xreq.h"
38 #include "afb-export.h"
39 #include "afb-evt.h"
40 #include "afb-api.h"
41 #include "afb-msg-json.h"
42 #include "verbose.h"
43
44 #include <fnmatch.h>
45 #define MATCH(pattern,string)   (\
46                 pattern \
47                         ? !fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH|FNM_PERIOD) \
48                         : (string)[0] != '.')
49
50 #define MATCH_API(pattern,string)       MATCH(pattern,string)
51 #define MATCH_VERB(pattern,string)      MATCH(pattern,string)
52 #define MATCH_EVENT(pattern,string)     MATCH(pattern,string)
53 #define MATCH_SESSION(pattern,string)   MATCH(pattern,string)
54
55 /**
56  * Definition of a hook for xreq
57  */
58 struct afb_hook_xreq {
59         struct afb_hook_xreq *next; /**< next hook */
60         unsigned refcount; /**< reference count */
61         unsigned flags; /**< hook flags */
62         char *api; /**< api hooked or NULL for any */
63         char *verb; /**< verb hooked or NULL for any */
64         struct afb_session *session; /**< session hooked or NULL if any */
65         struct afb_hook_xreq_itf *itf; /**< interface of hook */
66         void *closure; /**< closure for callbacks */
67 };
68
69 /**
70  * Definition of a hook for export
71  */
72 struct afb_hook_api {
73         struct afb_hook_api *next; /**< next hook */
74         unsigned refcount; /**< reference count */
75         unsigned flags; /**< hook flags */
76         char *api; /**< api hooked or NULL for any */
77         struct afb_hook_api_itf *itf; /**< interface of hook */
78         void *closure; /**< closure for callbacks */
79 };
80
81 /**
82  * Definition of a hook for evt
83  */
84 struct afb_hook_evt {
85         struct afb_hook_evt *next; /**< next hook */
86         unsigned refcount; /**< reference count */
87         unsigned flags; /**< hook flags */
88         char *pattern; /**< event pattern name hooked or NULL for any */
89         struct afb_hook_evt_itf *itf; /**< interface of hook */
90         void *closure; /**< closure for callbacks */
91 };
92
93 /**
94  * Definition of a hook for session
95  */
96 struct afb_hook_session {
97         struct afb_hook_session *next; /**< next hook */
98         unsigned refcount; /**< reference count */
99         unsigned flags; /**< hook flags */
100         char *pattern; /**< event pattern name hooked or NULL for any */
101         struct afb_hook_session_itf *itf; /**< interface of hook */
102         void *closure; /**< closure for callbacks */
103 };
104
105 /**
106  * Definition of a hook for global
107  */
108 struct afb_hook_global {
109         struct afb_hook_global *next; /**< next hook */
110         unsigned refcount; /**< reference count */
111         unsigned flags; /**< hook flags */
112         struct afb_hook_global_itf *itf; /**< interface of hook */
113         void *closure; /**< closure for callbacks */
114 };
115
116 /* synchronisation across threads */
117 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
118
119 /* list of hooks for xreq */
120 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
121
122 /* list of hooks for export */
123 static struct afb_hook_api *list_of_api_hooks = NULL;
124
125 /* list of hooks for evt */
126 static struct afb_hook_evt *list_of_evt_hooks = NULL;
127
128 /* list of hooks for session */
129 static struct afb_hook_session *list_of_session_hooks = NULL;
130
131 /* list of hooks for global */
132 static struct afb_hook_global *list_of_global_hooks = NULL;
133
134 /* hook id */
135 static unsigned next_hookid = 0;
136
137 /******************************************************************************
138  * section: hook id
139  *****************************************************************************/
140 static void init_hookid(struct afb_hookid *hookid)
141 {
142         hookid->id = __atomic_add_fetch(&next_hookid, 1, __ATOMIC_RELAXED);
143         clock_gettime(CLOCK_REALTIME, &hookid->time);
144 }
145
146 /******************************************************************************
147  * section: default callbacks for tracing requests
148  *****************************************************************************/
149
150 static char *_pbuf_(const char *fmt, va_list args, char **palloc, char *sbuf, size_t szsbuf, size_t *outlen)
151 {
152         int rc;
153         va_list cp;
154
155         *palloc = NULL;
156         va_copy(cp, args);
157         rc = vsnprintf(sbuf, szsbuf, fmt, args);
158         if ((size_t)rc >= szsbuf) {
159                 sbuf[szsbuf-1] = 0;
160                 sbuf[szsbuf-2] = sbuf[szsbuf-3] = sbuf[szsbuf-4] = '.';
161                 rc = vasprintf(palloc, fmt, cp);
162                 if (rc >= 0)
163                         sbuf = *palloc;
164         }
165         va_end(cp);
166         if (rc >= 0 && outlen)
167                 *outlen = (size_t)rc;
168         return sbuf;
169 }
170
171 #if 0 /* old behaviour: use NOTICE */
172 static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
173 {
174         char *tag, *data, *mem1, *mem2, buf1[256], buf2[2000];
175         va_list arg1;
176
177         data = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2, NULL);
178
179         va_start(arg1, arg2);
180         tag = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1, NULL);
181         va_end(arg1);
182
183         NOTICE("[HOOK %s] %s", tag, data);
184
185         free(mem1);
186         free(mem2);
187 }
188 #else /* new behaviour: emits directly to stderr */
189 static void _hook_(const char *fmt1, const char *fmt2, va_list arg2, ...)
190 {
191         static const char chars[] = "HOOK: [] \n";
192         char *mem1, *mem2, buf1[256], buf2[2000];
193         struct iovec iov[5];
194         va_list arg1;
195
196         iov[0].iov_base = (void*)&chars[0];
197         iov[0].iov_len = 7;
198
199         va_start(arg1, arg2);
200         iov[1].iov_base = _pbuf_(fmt1, arg1, &mem1, buf1, sizeof buf1, &iov[1].iov_len);
201         va_end(arg1);
202
203         iov[2].iov_base = (void*)&chars[7];
204         iov[2].iov_len = 2;
205
206         iov[3].iov_base = _pbuf_(fmt2, arg2, &mem2, buf2, sizeof buf2, &iov[3].iov_len);
207
208         iov[4].iov_base = (void*)&chars[9];
209         iov[4].iov_len = 1;
210
211         writev(2, iov, 5);
212
213         free(mem1);
214         free(mem2);
215 }
216 #endif
217
218 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
219 {
220         va_list ap;
221         va_start(ap, format);
222         _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.called_api, xreq->request.called_verb);
223         va_end(ap);
224 }
225
226 static void hook_xreq_begin_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
227 {
228         if (!xreq->cred)
229                 _hook_xreq_(xreq, "BEGIN");
230         else
231                 _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
232                         (int)xreq->cred->uid,
233                         xreq->cred->user,
234                         (int)xreq->cred->gid,
235                         (int)xreq->cred->pid,
236                         xreq->cred->label?:"(null)",
237                         xreq->cred->id?:"(null)"
238                 );
239 }
240
241 static void hook_xreq_end_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
242 {
243         _hook_xreq_(xreq, "END");
244 }
245
246 static void hook_xreq_json_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj)
247 {
248         _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
249 }
250
251 static void hook_xreq_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
252 {
253         _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
254 }
255
256 static void hook_xreq_reply_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
257 {
258         _hook_xreq_(xreq, "reply[%s](%s, %s)", error?:"success", json_object_to_json_string(obj), info);
259 }
260
261 static void hook_xreq_legacy_context_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value)
262 {
263         _hook_xreq_(xreq, "context_get() -> %p", value);
264 }
265
266 static void hook_xreq_legacy_context_set_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
267 {
268         _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
269 }
270
271 static void hook_xreq_addref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
272 {
273         _hook_xreq_(xreq, "addref()");
274 }
275
276 static void hook_xreq_unref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
277 {
278         _hook_xreq_(xreq, "unref()");
279 }
280
281 static void hook_xreq_session_close_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
282 {
283         _hook_xreq_(xreq, "session_close()");
284 }
285
286 static void hook_xreq_session_set_LOA_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result)
287 {
288         _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
289 }
290
291 static void hook_xreq_subscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
292 {
293         _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result);
294 }
295
296 static void hook_xreq_unsubscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
297 {
298         _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result);
299 }
300
301 static void hook_xreq_subcall_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
302 {
303         _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
304 }
305
306 static void hook_xreq_subcall_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
307 {
308         _hook_xreq_(xreq, "    ...subcall... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:"");
309 }
310
311 static void hook_xreq_subcallsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
312 {
313         _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
314 }
315
316 static void hook_xreq_subcallsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info)
317 {
318         _hook_xreq_(xreq, "    ...subcallsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:"");
319 }
320
321 static void hook_xreq_vverbose_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)
322 {
323         int len;
324         char *msg;
325         va_list ap;
326
327         va_copy(ap, args);
328         len = vasprintf(&msg, fmt, ap);
329         va_end(ap);
330
331         if (len < 0)
332                 _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt);
333         else {
334                 _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg);
335                 free(msg);
336         }
337 }
338
339 static void hook_xreq_legacy_store_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq)
340 {
341         _hook_xreq_(xreq, "store() -> %p", sreq);
342 }
343
344 static void hook_xreq_legacy_unstore_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq)
345 {
346         _hook_xreq_(xreq, "unstore()");
347 }
348
349 static void hook_xreq_has_permission_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result)
350 {
351         _hook_xreq_(xreq, "has_permission(%s) -> %d", permission, result);
352 }
353
354 static void hook_xreq_get_application_id_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result)
355 {
356         _hook_xreq_(xreq, "get_application_id() -> %s", result);
357 }
358
359 static void hook_xreq_context_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
360 {
361         _hook_xreq_(xreq, "context_make(replace=%s, %p, %p, %p) -> %p", replace?"yes":"no", create_value, free_value, create_closure, result);
362 }
363
364 static void hook_xreq_get_uid_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result)
365 {
366         _hook_xreq_(xreq, "get_uid() -> %d", result);
367 }
368
369 static void hook_xreq_get_client_info_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result)
370 {
371         _hook_xreq_(xreq, "get_client_info() -> %s", json_object_to_json_string(result));
372 }
373
374 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
375         .hook_xreq_begin = hook_xreq_begin_cb,
376         .hook_xreq_end = hook_xreq_end_cb,
377         .hook_xreq_json = hook_xreq_json_cb,
378         .hook_xreq_get = hook_xreq_get_cb,
379         .hook_xreq_reply = hook_xreq_reply_cb,
380         .hook_xreq_legacy_context_get = hook_xreq_legacy_context_get_cb,
381         .hook_xreq_legacy_context_set = hook_xreq_legacy_context_set_cb,
382         .hook_xreq_addref = hook_xreq_addref_cb,
383         .hook_xreq_unref = hook_xreq_unref_cb,
384         .hook_xreq_session_close = hook_xreq_session_close_cb,
385         .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_cb,
386         .hook_xreq_subscribe = hook_xreq_subscribe_cb,
387         .hook_xreq_unsubscribe = hook_xreq_unsubscribe_cb,
388         .hook_xreq_subcall = hook_xreq_subcall_cb,
389         .hook_xreq_subcall_result = hook_xreq_subcall_result_cb,
390         .hook_xreq_subcallsync = hook_xreq_subcallsync_cb,
391         .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_cb,
392         .hook_xreq_vverbose = hook_xreq_vverbose_cb,
393         .hook_xreq_legacy_store = hook_xreq_legacy_store_cb,
394         .hook_xreq_legacy_unstore = hook_xreq_legacy_unstore_cb,
395         .hook_xreq_has_permission = hook_xreq_has_permission_cb,
396         .hook_xreq_get_application_id = hook_xreq_get_application_id_cb,
397         .hook_xreq_context_make = hook_xreq_context_make_cb,
398         .hook_xreq_get_uid = hook_xreq_get_uid_cb,
399         .hook_xreq_get_client_info = hook_xreq_get_client_info_cb,
400 };
401
402 /******************************************************************************
403  * section: hooks for tracing requests
404  *****************************************************************************/
405
406 #define _HOOK_XREQ_2_(flag,func,...)   \
407         struct afb_hook_xreq *hook; \
408         struct afb_hookid hookid; \
409         pthread_rwlock_rdlock(&rwlock); \
410         init_hookid(&hookid); \
411         hook = list_of_xreq_hooks; \
412         while (hook) { \
413                 if (hook->itf->hook_xreq_##func \
414                  && (hook->flags & afb_hook_flag_req_##flag) != 0 \
415                  && (!hook->session || hook->session == xreq->context.session) \
416                  && MATCH_API(hook->api, xreq->request.called_api) \
417                  && MATCH_VERB(hook->verb, xreq->request.called_verb)) { \
418                         hook->itf->hook_xreq_##func(hook->closure, &hookid, __VA_ARGS__); \
419                 } \
420                 hook = hook->next; \
421         } \
422         pthread_rwlock_unlock(&rwlock);
423
424 #define _HOOK_XREQ_(what,...)   _HOOK_XREQ_2_(what,what,__VA_ARGS__)
425
426 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
427 {
428         _HOOK_XREQ_(begin, xreq);
429 }
430
431 void afb_hook_xreq_end(const struct afb_xreq *xreq)
432 {
433         _HOOK_XREQ_(end, xreq);
434 }
435
436 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
437 {
438         _HOOK_XREQ_(json, xreq, obj);
439         return obj;
440 }
441
442 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
443 {
444         _HOOK_XREQ_(get, xreq, name, arg);
445         return arg;
446 }
447
448 void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info)
449 {
450         _HOOK_XREQ_(reply, xreq, obj, error, info);
451 }
452
453 void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value)
454 {
455         _HOOK_XREQ_(legacy_context_get, xreq, value);
456         return value;
457 }
458
459 void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
460 {
461         _HOOK_XREQ_(legacy_context_set, xreq, value, free_value);
462 }
463
464 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
465 {
466         _HOOK_XREQ_(addref, xreq);
467 }
468
469 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
470 {
471         _HOOK_XREQ_(unref, xreq);
472 }
473
474 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
475 {
476         _HOOK_XREQ_(session_close, xreq);
477 }
478
479 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
480 {
481         _HOOK_XREQ_(session_set_LOA, xreq, level, result);
482         return result;
483 }
484
485 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
486 {
487         _HOOK_XREQ_(subscribe, xreq, event_x2, result);
488         return result;
489 }
490
491 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result)
492 {
493         _HOOK_XREQ_(unsubscribe, xreq, event_x2, result);
494         return result;
495 }
496
497 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags)
498 {
499         _HOOK_XREQ_(subcall, xreq, api, verb, args);
500 }
501
502 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
503 {
504         _HOOK_XREQ_(subcall_result, xreq, object, error, info);
505 }
506
507 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags)
508 {
509         _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
510 }
511
512 int  afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info)
513 {
514         _HOOK_XREQ_(subcallsync_result, xreq, status, object, error, info);
515         return status;
516 }
517
518 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)
519 {
520         _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
521 }
522
523 void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq)
524 {
525         _HOOK_XREQ_(legacy_store, xreq, sreq);
526 }
527
528 void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq)
529 {
530         _HOOK_XREQ_(legacy_unstore, xreq);
531 }
532
533 int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result)
534 {
535         _HOOK_XREQ_(has_permission, xreq, permission, result);
536         return result;
537 }
538
539 char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result)
540 {
541         _HOOK_XREQ_(get_application_id, xreq, result);
542         return result;
543 }
544
545 void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
546 {
547         _HOOK_XREQ_(context_make, xreq, replace, create_value, free_value, create_closure, result);
548         return result;
549 }
550
551 int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result)
552 {
553         _HOOK_XREQ_(get_uid, xreq, result);
554         return result;
555 }
556
557 struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result)
558 {
559         _HOOK_XREQ_(get_client_info, xreq, result);
560         return result;
561 }
562
563 /******************************************************************************
564  * section: hooking xreqs
565  *****************************************************************************/
566
567 void afb_hook_init_xreq(struct afb_xreq *xreq)
568 {
569         static int reqindex;
570
571         int f, flags;
572         int add;
573         struct afb_hook_xreq *hook;
574
575         /* scan hook list to get the expected flags */
576         flags = 0;
577         pthread_rwlock_rdlock(&rwlock);
578         hook = list_of_xreq_hooks;
579         while (hook) {
580                 f = hook->flags & afb_hook_flags_req_all;
581                 add = f != 0
582                    && (!hook->session || hook->session == xreq->context.session)
583                    && MATCH_API(hook->api, xreq->request.called_api)
584                    && MATCH_VERB(hook->verb, xreq->request.called_verb);
585                 if (add)
586                         flags |= f;
587                 hook = hook->next;
588         }
589         pthread_rwlock_unlock(&rwlock);
590
591         /* store the hooking data */
592         xreq->hookflags = flags;
593         if (flags) {
594                 pthread_rwlock_wrlock(&rwlock);
595                 if (++reqindex < 0)
596                         reqindex = 1;
597                 xreq->hookindex = reqindex;
598                 pthread_rwlock_unlock(&rwlock);
599         }
600 }
601
602 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)
603 {
604         struct afb_hook_xreq *hook;
605
606         /* alloc the result */
607         hook = calloc(1, sizeof *hook);
608         if (hook == NULL)
609                 return NULL;
610
611         /* get a copy of the names */
612         hook->api = api ? strdup(api) : NULL;
613         hook->verb = verb ? strdup(verb) : NULL;
614         if ((api && !hook->api) || (verb && !hook->verb)) {
615                 free(hook->api);
616                 free(hook->verb);
617                 free(hook);
618                 return NULL;
619         }
620
621         /* initialise the rest */
622         hook->session = session;
623         if (session)
624                 afb_session_addref(session);
625         hook->refcount = 1;
626         hook->flags = flags;
627         hook->itf = itf ? itf : &hook_xreq_default_itf;
628         hook->closure = closure;
629
630         /* record the hook */
631         pthread_rwlock_wrlock(&rwlock);
632         hook->next = list_of_xreq_hooks;
633         list_of_xreq_hooks = hook;
634         pthread_rwlock_unlock(&rwlock);
635
636         /* returns it */
637         return hook;
638 }
639
640 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
641 {
642         pthread_rwlock_wrlock(&rwlock);
643         hook->refcount++;
644         pthread_rwlock_unlock(&rwlock);
645         return hook;
646 }
647
648 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
649 {
650         struct afb_hook_xreq **prv;
651
652         if (hook) {
653                 pthread_rwlock_wrlock(&rwlock);
654                 if (--hook->refcount)
655                         hook = NULL;
656                 else {
657                         /* unlink */
658                         prv = &list_of_xreq_hooks;
659                         while (*prv && *prv != hook)
660                                 prv = &(*prv)->next;
661                         if(*prv)
662                                 *prv = hook->next;
663                 }
664                 pthread_rwlock_unlock(&rwlock);
665                 if (hook) {
666                         /* free */
667                         free(hook->api);
668                         free(hook->verb);
669                         if (hook->session)
670                                 afb_session_unref(hook->session);
671                         free(hook);
672                 }
673         }
674 }
675
676 /******************************************************************************
677  * section: default callbacks for tracing daemon interface
678  *****************************************************************************/
679
680 static void _hook_api_(const struct afb_export *export, const char *format, ...)
681 {
682         va_list ap;
683         va_start(ap, format);
684         _hook_("api-%s", format, ap, afb_export_apiname(export));
685         va_end(ap);
686 }
687
688 static void hook_api_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object)
689 {
690         _hook_api_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
691 }
692
693 static void hook_api_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result)
694 {
695         _hook_api_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
696 }
697
698 static void hook_api_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result)
699 {
700         _hook_api_(export, "get_event_loop() -> %p", result);
701 }
702
703 static void hook_api_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
704 {
705         _hook_api_(export, "get_user_bus() -> %p", result);
706 }
707
708 static void hook_api_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result)
709 {
710         _hook_api_(export, "get_system_bus() -> %p", result);
711 }
712
713 static void hook_api_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
714 {
715         int len;
716         char *msg;
717         va_list ap;
718
719         va_copy(ap, args);
720         len = vasprintf(&msg, fmt, ap);
721         va_end(ap);
722
723         if (len < 0)
724                 _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, function, fmt);
725         else {
726                 _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, function, msg);
727                 free(msg);
728         }
729 }
730
731 static void hook_api_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result)
732 {
733         _hook_api_(export, "event_make(%s) -> %s:%d", name, afb_evt_event_x2_fullname(result), afb_evt_event_x2_id(result));
734 }
735
736 static void hook_api_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
737 {
738         char path[PATH_MAX], proc[100];
739         if (result < 0)
740                 _hook_api_(export, "rootdir_get_fd() -> %d, %m", result);
741         else {
742                 snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
743                 readlink(proc, path, sizeof path);
744                 _hook_api_(export, "rootdir_get_fd() -> %d = %s", result, path);
745         }
746 }
747
748 static void hook_api_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
749 {
750         char path[PATH_MAX], proc[100];
751         if (!locale)
752                 locale = "(null)";
753         if (result < 0)
754                 _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
755         else {
756                 snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
757                 readlink(proc, path, sizeof path);
758                 _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
759         }
760 }
761
762 static void hook_api_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
763 {
764         _hook_api_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
765 }
766
767 static void hook_api_unstore_req_cb(void *closure, const struct afb_hookid *hookid,  const struct afb_export *export, struct afb_stored_req *sreq)
768 {
769         _hook_api_(export, "unstore_req(%p)", sreq);
770 }
771
772 static void hook_api_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
773 {
774         _hook_api_(export, "require_api(%s, %d)...", name, initialized);
775 }
776
777 static void hook_api_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result)
778 {
779         _hook_api_(export, "...require_api(%s, %d) -> %d", name, initialized, result);
780 }
781
782 static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result)
783 {
784         _hook_api_(export, "add_alias(%s -> %s) -> %d", api, alias?:"<null>", result);
785 }
786
787 static void hook_api_start_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
788 {
789         _hook_api_(export, "start.before");
790 }
791
792 static void hook_api_start_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
793 {
794         _hook_api_(export, "start.after -> %d", status);
795 }
796
797 static void hook_api_on_event_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
798 {
799         _hook_api_(export, "on_event.before(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
800 }
801
802 static void hook_api_on_event_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
803 {
804         _hook_api_(export, "on_event.after(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
805 }
806
807 static void hook_api_call_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
808 {
809         _hook_api_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
810 }
811
812 static void hook_api_call_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info)
813 {
814         _hook_api_(export, "    ...call... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:"");
815 }
816
817 static void hook_api_callsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
818 {
819         _hook_api_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
820 }
821
822 static void hook_api_callsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
823 {
824         _hook_api_(export, "    ...callsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:"");
825 }
826
827 static void hook_api_new_api_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency)
828 {
829         _hook_api_(export, "new_api.before %s (%s)%s ...", api, info?:"", noconcurrency?" no-concurrency" : "");
830 }
831
832 static void hook_api_new_api_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api)
833 {
834         _hook_api_(export, "... new_api.after %s -> %s (%d)", api, result >= 0 ? "OK" : "ERROR", result);
835 }
836
837 static void hook_api_api_set_verbs_v2_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
838 {
839         _hook_api_(export, "set_verbs_v2 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
840 }
841
842 static void hook_api_api_set_verbs_v3_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
843 {
844         _hook_api_(export, "set_verbs_v3 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
845 }
846
847 static void hook_api_api_add_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob)
848 {
849         _hook_api_(export, "add_verb(%s%s [%s]) -> %s (%d)", verb, glob?" (GLOB)":"", info?:"", result >= 0 ? "OK" : "ERROR", result);
850 }
851
852 static void hook_api_api_del_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb)
853 {
854         _hook_api_(export, "del_verb(%s) -> %s (%d)", verb, result >= 0 ? "OK" : "ERROR", result);
855 }
856
857 static void hook_api_api_set_on_event_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
858 {
859         _hook_api_(export, "set_on_event -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
860 }
861
862 static void hook_api_api_set_on_init_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
863 {
864         _hook_api_(export, "set_on_init -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
865 }
866
867 static void hook_api_api_seal_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
868 {
869         _hook_api_(export, "seal");
870 }
871
872 static void hook_api_event_handler_add_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
873 {
874         _hook_api_(export, "event_handler_add(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
875 }
876
877 static void hook_api_event_handler_del_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern)
878 {
879         _hook_api_(export, "event_handler_del(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
880 }
881
882 static void hook_api_class_provide_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
883 {
884         _hook_api_(export, "class_provide(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
885 }
886
887 static void hook_api_class_require_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
888 {
889         _hook_api_(export, "class_require(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
890 }
891
892 static void hook_api_delete_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
893 {
894         _hook_api_(export, "delete_api -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
895 }
896
897 static void hook_api_on_event_handler_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
898 {
899         _hook_api_(export, "on_event_handler[%s].before(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
900 }
901
902 static void hook_api_on_event_handler_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
903 {
904         _hook_api_(export, "on_event_handler[%s].after(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
905 }
906
907 static struct afb_hook_api_itf hook_api_default_itf = {
908         .hook_api_event_broadcast_before = hook_api_event_broadcast_before_cb,
909         .hook_api_event_broadcast_after = hook_api_event_broadcast_after_cb,
910         .hook_api_get_event_loop = hook_api_get_event_loop_cb,
911         .hook_api_get_user_bus = hook_api_get_user_bus_cb,
912         .hook_api_get_system_bus = hook_api_get_system_bus_cb,
913         .hook_api_vverbose = hook_api_vverbose_cb,
914         .hook_api_event_make = hook_api_event_make_cb,
915         .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd_cb,
916         .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale_cb,
917         .hook_api_queue_job = hook_api_queue_job_cb,
918         .hook_api_legacy_unstore_req = hook_api_unstore_req_cb,
919         .hook_api_require_api = hook_api_require_api_cb,
920         .hook_api_require_api_result = hook_api_require_api_result_cb,
921         .hook_api_add_alias = hook_api_add_alias_cb,
922         .hook_api_start_before = hook_api_start_before_cb,
923         .hook_api_start_after = hook_api_start_after_cb,
924         .hook_api_on_event_before = hook_api_on_event_before_cb,
925         .hook_api_on_event_after = hook_api_on_event_after_cb,
926         .hook_api_call = hook_api_call_cb,
927         .hook_api_call_result = hook_api_call_result_cb,
928         .hook_api_callsync = hook_api_callsync_cb,
929         .hook_api_callsync_result = hook_api_callsync_result_cb,
930         .hook_api_new_api_before = hook_api_new_api_before_cb,
931         .hook_api_new_api_after = hook_api_new_api_after_cb,
932         .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2_cb,
933         .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3_cb,
934         .hook_api_api_add_verb = hook_api_api_add_verb_cb,
935         .hook_api_api_del_verb = hook_api_api_del_verb_cb,
936         .hook_api_api_set_on_event = hook_api_api_set_on_event_cb,
937         .hook_api_api_set_on_init = hook_api_api_set_on_init_cb,
938         .hook_api_api_seal = hook_api_api_seal_cb,
939         .hook_api_event_handler_add = hook_api_event_handler_add_cb,
940         .hook_api_event_handler_del = hook_api_event_handler_del_cb,
941         .hook_api_class_provide = hook_api_class_provide_cb,
942         .hook_api_class_require = hook_api_class_require_cb,
943         .hook_api_delete_api = hook_api_delete_api_cb,
944         .hook_api_on_event_handler_before = hook_api_on_event_handler_before_cb,
945         .hook_api_on_event_handler_after = hook_api_on_event_handler_after_cb,
946 };
947
948 /******************************************************************************
949  * section: hooks for tracing daemon interface (export)
950  *****************************************************************************/
951
952 #define _HOOK_API_2_(flag,func,...)   \
953         struct afb_hook_api *hook; \
954         struct afb_hookid hookid; \
955         const char *apiname = afb_export_apiname(export); \
956         pthread_rwlock_rdlock(&rwlock); \
957         init_hookid(&hookid); \
958         hook = list_of_api_hooks; \
959         while (hook) { \
960                 if (hook->itf->hook_api_##func \
961                  && (hook->flags & afb_hook_flag_api_##flag) != 0 \
962                  && MATCH_API(hook->api, apiname)) { \
963                         hook->itf->hook_api_##func(hook->closure, &hookid, __VA_ARGS__); \
964                 } \
965                 hook = hook->next; \
966         } \
967         pthread_rwlock_unlock(&rwlock);
968
969 #define _HOOK_API_(what,...)   _HOOK_API_2_(what,what,__VA_ARGS__)
970
971 void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object)
972 {
973         _HOOK_API_2_(event_broadcast, event_broadcast_before, export, name, object);
974 }
975
976 int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result)
977 {
978         _HOOK_API_2_(event_broadcast, event_broadcast_after, export, name, object, result);
979         return result;
980 }
981
982 struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result)
983 {
984         _HOOK_API_(get_event_loop, export, result);
985         return result;
986 }
987
988 struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result)
989 {
990         _HOOK_API_(get_user_bus, export, result);
991         return result;
992 }
993
994 struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result)
995 {
996         _HOOK_API_(get_system_bus, export, result);
997         return result;
998 }
999
1000 void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
1001 {
1002         _HOOK_API_(vverbose, export, level, file, line, function, fmt, args);
1003 }
1004
1005 struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result)
1006 {
1007         _HOOK_API_(event_make, export, name, result);
1008         return result;
1009 }
1010
1011 int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result)
1012 {
1013         _HOOK_API_(rootdir_get_fd, export, result);
1014         return result;
1015 }
1016
1017 int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
1018 {
1019         _HOOK_API_(rootdir_open_locale, export, filename, flags, locale, result);
1020         return result;
1021 }
1022
1023 int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
1024 {
1025         _HOOK_API_(queue_job, export, callback, argument, group, timeout, result);
1026         return result;
1027 }
1028
1029 void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq)
1030 {
1031         _HOOK_API_(legacy_unstore_req, export, sreq);
1032 }
1033
1034 void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized)
1035 {
1036         _HOOK_API_(require_api, export, name, initialized);
1037 }
1038
1039 int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result)
1040 {
1041         _HOOK_API_2_(require_api, require_api_result, export, name, initialized, result);
1042         return result;
1043 }
1044
1045 int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result)
1046 {
1047         _HOOK_API_(add_alias, export, api, alias, result);
1048         return result;
1049 }
1050
1051 void afb_hook_api_start_before(const struct afb_export *export)
1052 {
1053         _HOOK_API_2_(start, start_before, export);
1054 }
1055
1056 int afb_hook_api_start_after(const struct afb_export *export, int status)
1057 {
1058         _HOOK_API_2_(start, start_after, export, status);
1059         return status;
1060 }
1061
1062 void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
1063 {
1064         _HOOK_API_2_(on_event, on_event_before, export, event, event_x2, object);
1065 }
1066
1067 void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
1068 {
1069         _HOOK_API_2_(on_event, on_event_after, export, event, event_x2, object);
1070 }
1071
1072 void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
1073 {
1074         _HOOK_API_(call, export, api, verb, args);
1075 }
1076
1077 void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char*error, const char *info)
1078 {
1079         _HOOK_API_2_(call, call_result, export, object, error, info);
1080
1081 }
1082
1083 void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
1084 {
1085         _HOOK_API_(callsync, export, api, verb, args);
1086 }
1087
1088 int afb_hook_api_callsync_result(const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
1089 {
1090         _HOOK_API_2_(callsync, callsync_result, export, status, object, error, info);
1091         return status;
1092 }
1093
1094 void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency)
1095 {
1096         _HOOK_API_2_(new_api, new_api_before, export, api, info, noconcurrency);
1097 }
1098
1099 int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api)
1100 {
1101         _HOOK_API_2_(new_api, new_api_after, export, result, api);
1102         return result;
1103 }
1104
1105 int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
1106 {
1107         _HOOK_API_2_(api_set_verbs, api_set_verbs_v2, export, result, verbs);
1108         return result;
1109 }
1110
1111 int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
1112 {
1113         _HOOK_API_2_(api_set_verbs, api_set_verbs_v3, export, result, verbs);
1114         return result;
1115 }
1116
1117 int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob)
1118 {
1119         _HOOK_API_(api_add_verb, export, result, verb, info, glob);
1120         return result;
1121 }
1122
1123 int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb)
1124 {
1125         _HOOK_API_(api_del_verb, export, result, verb);
1126         return result;
1127 }
1128
1129 int afb_hook_api_api_set_on_event(const struct afb_export *export, int result)
1130 {
1131         _HOOK_API_(api_set_on_event, export, result);
1132         return result;
1133 }
1134
1135 int afb_hook_api_api_set_on_init(const struct afb_export *export, int result)
1136 {
1137         _HOOK_API_(api_set_on_init, export, result);
1138         return result;
1139 }
1140
1141 void afb_hook_api_api_seal(const struct afb_export *export)
1142 {
1143         _HOOK_API_(api_seal, export);
1144 }
1145
1146 int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern)
1147 {
1148         _HOOK_API_(event_handler_add, export, result, pattern);
1149         return result;
1150 }
1151 int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern)
1152 {
1153         _HOOK_API_(event_handler_del, export, result, pattern);
1154         return result;
1155 }
1156 int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name)
1157 {
1158         _HOOK_API_(class_provide, export, result, name);
1159         return result;
1160 }
1161 int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name)
1162 {
1163         _HOOK_API_(class_require, export, result, name);
1164         return result;
1165 }
1166
1167 int afb_hook_api_delete_api(const struct afb_export *export, int result)
1168 {
1169         _HOOK_API_(delete_api, export, result);
1170         return result;
1171 }
1172
1173 void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
1174 {
1175         _HOOK_API_2_(on_event_handler, on_event_handler_before, export, event, event_x2, object, pattern);
1176 }
1177
1178 void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern)
1179 {
1180         _HOOK_API_2_(on_event_handler, on_event_handler_after, export, event, event_x2, object, pattern);
1181 }
1182
1183 /******************************************************************************
1184  * section: hooking export
1185  *****************************************************************************/
1186
1187 int afb_hook_flags_api(const char *api)
1188 {
1189         int flags;
1190         struct afb_hook_api *hook;
1191
1192         flags = 0;
1193         pthread_rwlock_rdlock(&rwlock);
1194         hook = list_of_api_hooks;
1195         while (hook) {
1196                 if (!api || MATCH_API(hook->api, api))
1197                         flags |= hook->flags;
1198                 hook = hook->next;
1199         }
1200         pthread_rwlock_unlock(&rwlock);
1201         return flags;
1202 }
1203
1204 struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure)
1205 {
1206         struct afb_hook_api *hook;
1207
1208         /* alloc the result */
1209         hook = calloc(1, sizeof *hook);
1210         if (hook == NULL)
1211                 return NULL;
1212
1213         /* get a copy of the names */
1214         hook->api = api ? strdup(api) : NULL;
1215         if (api && !hook->api) {
1216                 free(hook);
1217                 return NULL;
1218         }
1219
1220         /* initialise the rest */
1221         hook->refcount = 1;
1222         hook->flags = flags;
1223         hook->itf = itf ? itf : &hook_api_default_itf;
1224         hook->closure = closure;
1225
1226         /* record the hook */
1227         pthread_rwlock_wrlock(&rwlock);
1228         hook->next = list_of_api_hooks;
1229         list_of_api_hooks = hook;
1230         pthread_rwlock_unlock(&rwlock);
1231
1232         /* returns it */
1233         return hook;
1234 }
1235
1236 struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook)
1237 {
1238         pthread_rwlock_wrlock(&rwlock);
1239         hook->refcount++;
1240         pthread_rwlock_unlock(&rwlock);
1241         return hook;
1242 }
1243
1244 void afb_hook_unref_api(struct afb_hook_api *hook)
1245 {
1246         struct afb_hook_api **prv;
1247
1248         if (hook) {
1249                 pthread_rwlock_wrlock(&rwlock);
1250                 if (--hook->refcount)
1251                         hook = NULL;
1252                 else {
1253                         /* unlink */
1254                         prv = &list_of_api_hooks;
1255                         while (*prv && *prv != hook)
1256                                 prv = &(*prv)->next;
1257                         if(*prv)
1258                                 *prv = hook->next;
1259                 }
1260                 pthread_rwlock_unlock(&rwlock);
1261                 if (hook) {
1262                         /* free */
1263                         free(hook->api);
1264                         free(hook);
1265                 }
1266         }
1267 }
1268
1269 /******************************************************************************
1270  * section: default callbacks for tracing service interface (evt)
1271  *****************************************************************************/
1272
1273 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1274 {
1275         va_list ap;
1276         va_start(ap, format);
1277         _hook_("evt-%s:%d", format, ap, evt, id);
1278         va_end(ap);
1279 }
1280
1281 static void hook_evt_create_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1282 {
1283         _hook_evt_(evt, id, "create");
1284 }
1285
1286 static void hook_evt_push_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1287 {
1288         _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1289 }
1290
1291
1292 static void hook_evt_push_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1293 {
1294         _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1295 }
1296
1297 static void hook_evt_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1298 {
1299         _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1300 }
1301
1302 static void hook_evt_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result)
1303 {
1304         _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1305 }
1306
1307 static void hook_evt_name_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result)
1308 {
1309         _hook_evt_(evt, id, "name -> %s", result);
1310 }
1311
1312 static void hook_evt_addref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1313 {
1314         _hook_evt_(evt, id, "addref");
1315 }
1316
1317 static void hook_evt_unref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1318 {
1319         _hook_evt_(evt, id, "unref");
1320 }
1321
1322 static struct afb_hook_evt_itf hook_evt_default_itf = {
1323         .hook_evt_create = hook_evt_create_cb,
1324         .hook_evt_push_before = hook_evt_push_before_cb,
1325         .hook_evt_push_after = hook_evt_push_after_cb,
1326         .hook_evt_broadcast_before = hook_evt_broadcast_before_cb,
1327         .hook_evt_broadcast_after = hook_evt_broadcast_after_cb,
1328         .hook_evt_name = hook_evt_name_cb,
1329         .hook_evt_addref = hook_evt_addref_cb,
1330         .hook_evt_unref = hook_evt_unref_cb
1331 };
1332
1333 /******************************************************************************
1334  * section: hooks for tracing events interface (evt)
1335  *****************************************************************************/
1336
1337 #define _HOOK_EVT_(what,...)   \
1338         struct afb_hook_evt *hook; \
1339         struct afb_hookid hookid; \
1340         pthread_rwlock_rdlock(&rwlock); \
1341         init_hookid(&hookid); \
1342         hook = list_of_evt_hooks; \
1343         while (hook) { \
1344                 if (hook->itf->hook_evt_##what \
1345                  && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1346                  && MATCH_EVENT(hook->pattern, evt)) { \
1347                         hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \
1348                 } \
1349                 hook = hook->next; \
1350         } \
1351         pthread_rwlock_unlock(&rwlock);
1352
1353 void afb_hook_evt_create(const char *evt, int id)
1354 {
1355         _HOOK_EVT_(create, evt, id);
1356 }
1357
1358 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1359 {
1360         _HOOK_EVT_(push_before, evt, id, obj);
1361 }
1362
1363 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1364 {
1365         _HOOK_EVT_(push_after, evt, id, obj, result);
1366         return result;
1367 }
1368
1369 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1370 {
1371         _HOOK_EVT_(broadcast_before, evt, id, obj);
1372 }
1373
1374 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1375 {
1376         _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1377         return result;
1378 }
1379
1380 void afb_hook_evt_name(const char *evt, int id, const char *result)
1381 {
1382         _HOOK_EVT_(name, evt, id, result);
1383 }
1384
1385 void afb_hook_evt_addref(const char *evt, int id)
1386 {
1387         _HOOK_EVT_(addref, evt, id);
1388 }
1389
1390 void afb_hook_evt_unref(const char *evt, int id)
1391 {
1392         _HOOK_EVT_(unref, evt, id);
1393 }
1394
1395 /******************************************************************************
1396  * section: hooking services (evt)
1397  *****************************************************************************/
1398
1399 int afb_hook_flags_evt(const char *name)
1400 {
1401         int flags;
1402         struct afb_hook_evt *hook;
1403
1404         flags = 0;
1405         pthread_rwlock_rdlock(&rwlock);
1406         hook = list_of_evt_hooks;
1407         while (hook) {
1408                 if (!name || MATCH_EVENT(hook->pattern, name))
1409                         flags |= hook->flags;
1410                 hook = hook->next;
1411         }
1412         pthread_rwlock_unlock(&rwlock);
1413         return flags;
1414 }
1415
1416 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1417 {
1418         struct afb_hook_evt *hook;
1419
1420         /* alloc the result */
1421         hook = calloc(1, sizeof *hook);
1422         if (hook == NULL)
1423                 return NULL;
1424
1425         /* get a copy of the names */
1426         hook->pattern = pattern ? strdup(pattern) : NULL;
1427         if (pattern && !hook->pattern) {
1428                 free(hook);
1429                 return NULL;
1430         }
1431
1432         /* initialise the rest */
1433         hook->refcount = 1;
1434         hook->flags = flags;
1435         hook->itf = itf ? itf : &hook_evt_default_itf;
1436         hook->closure = closure;
1437
1438         /* record the hook */
1439         pthread_rwlock_wrlock(&rwlock);
1440         hook->next = list_of_evt_hooks;
1441         list_of_evt_hooks = hook;
1442         pthread_rwlock_unlock(&rwlock);
1443
1444         /* returns it */
1445         return hook;
1446 }
1447
1448 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1449 {
1450         pthread_rwlock_wrlock(&rwlock);
1451         hook->refcount++;
1452         pthread_rwlock_unlock(&rwlock);
1453         return hook;
1454 }
1455
1456 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1457 {
1458         struct afb_hook_evt **prv;
1459
1460         if (hook) {
1461                 pthread_rwlock_wrlock(&rwlock);
1462                 if (--hook->refcount)
1463                         hook = NULL;
1464                 else {
1465                         /* unlink */
1466                         prv = &list_of_evt_hooks;
1467                         while (*prv && *prv != hook)
1468                                 prv = &(*prv)->next;
1469                         if(*prv)
1470                                 *prv = hook->next;
1471                 }
1472                 pthread_rwlock_unlock(&rwlock);
1473                 if (hook) {
1474                         /* free */
1475                         free(hook->pattern);
1476                         free(hook);
1477                 }
1478         }
1479 }
1480
1481 /******************************************************************************
1482  * section: default callbacks for sessions (session)
1483  *****************************************************************************/
1484
1485 static void _hook_session_(struct afb_session *session, const char *format, ...)
1486 {
1487         va_list ap;
1488         va_start(ap, format);
1489         _hook_("session-%s", format, ap, afb_session_uuid(session));
1490         va_end(ap);
1491 }
1492
1493 static void hook_session_create_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1494 {
1495         _hook_session_(session, "create -> token=%s", afb_session_token(session));
1496 }
1497
1498 static void hook_session_close_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1499 {
1500         _hook_session_(session, "close");
1501 }
1502
1503 static void hook_session_destroy_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1504 {
1505         _hook_session_(session, "destroy");
1506 }
1507
1508 static void hook_session_renew_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1509 {
1510         _hook_session_(session, "renew -> token=%s", afb_session_token(session));
1511 }
1512
1513 static void hook_session_addref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1514 {
1515         _hook_session_(session, "addref");
1516 }
1517
1518 static void hook_session_unref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1519 {
1520         _hook_session_(session, "unref");
1521 }
1522
1523 static struct afb_hook_session_itf hook_session_default_itf = {
1524         .hook_session_create = hook_session_create_cb,
1525         .hook_session_close = hook_session_close_cb,
1526         .hook_session_destroy = hook_session_destroy_cb,
1527         .hook_session_renew = hook_session_renew_cb,
1528         .hook_session_addref = hook_session_addref_cb,
1529         .hook_session_unref = hook_session_unref_cb
1530 };
1531
1532 /******************************************************************************
1533  * section: hooks for tracing sessions (session)
1534  *****************************************************************************/
1535
1536 #define _HOOK_SESSION_(what,...)   \
1537         struct afb_hook_session *hook; \
1538         struct afb_hookid hookid; \
1539         const char *sessid = 0; \
1540         pthread_rwlock_rdlock(&rwlock); \
1541         init_hookid(&hookid); \
1542         hook = list_of_session_hooks; \
1543         while (hook) { \
1544                 if (hook->itf->hook_session_##what \
1545                  && (hook->flags & afb_hook_flag_session_##what) != 0 \
1546                  && MATCH_SESSION(hook->pattern, (sessid?:(sessid=afb_session_uuid(session))))) { \
1547                         hook->itf->hook_session_##what(hook->closure, &hookid, __VA_ARGS__); \
1548                 } \
1549                 hook = hook->next; \
1550         } \
1551         pthread_rwlock_unlock(&rwlock);
1552
1553 void afb_hook_session_create(struct afb_session *session)
1554 {
1555         _HOOK_SESSION_(create, session);
1556 }
1557
1558 void afb_hook_session_close(struct afb_session *session)
1559 {
1560         _HOOK_SESSION_(close, session);
1561 }
1562
1563 void afb_hook_session_destroy(struct afb_session *session)
1564 {
1565         _HOOK_SESSION_(destroy, session);
1566 }
1567
1568 void afb_hook_session_renew(struct afb_session *session)
1569 {
1570         _HOOK_SESSION_(renew, session);
1571 }
1572
1573 void afb_hook_session_addref(struct afb_session *session)
1574 {
1575         _HOOK_SESSION_(addref, session);
1576 }
1577
1578 void afb_hook_session_unref(struct afb_session *session)
1579 {
1580         _HOOK_SESSION_(unref, session);
1581 }
1582
1583
1584 /******************************************************************************
1585  * section: hooking sessions (session)
1586  *****************************************************************************/
1587
1588 struct afb_hook_session *afb_hook_create_session(const char *pattern, int flags, struct afb_hook_session_itf *itf, void *closure)
1589 {
1590         struct afb_hook_session *hook;
1591
1592         /* alloc the result */
1593         hook = calloc(1, sizeof *hook);
1594         if (hook == NULL)
1595                 return NULL;
1596
1597         /* get a copy of the names */
1598         hook->pattern = pattern ? strdup(pattern) : NULL;
1599         if (pattern && !hook->pattern) {
1600                 free(hook);
1601                 return NULL;
1602         }
1603
1604         /* initialise the rest */
1605         hook->refcount = 1;
1606         hook->flags = flags;
1607         hook->itf = itf ? itf : &hook_session_default_itf;
1608         hook->closure = closure;
1609
1610         /* record the hook */
1611         pthread_rwlock_wrlock(&rwlock);
1612         hook->next = list_of_session_hooks;
1613         list_of_session_hooks = hook;
1614         pthread_rwlock_unlock(&rwlock);
1615
1616         /* returns it */
1617         return hook;
1618 }
1619
1620 struct afb_hook_session *afb_hook_addref_session(struct afb_hook_session *hook)
1621 {
1622         pthread_rwlock_wrlock(&rwlock);
1623         hook->refcount++;
1624         pthread_rwlock_unlock(&rwlock);
1625         return hook;
1626 }
1627
1628 void afb_hook_unref_session(struct afb_hook_session *hook)
1629 {
1630         struct afb_hook_session **prv;
1631
1632         if (hook) {
1633                 pthread_rwlock_wrlock(&rwlock);
1634                 if (--hook->refcount)
1635                         hook = NULL;
1636                 else {
1637                         /* unlink */
1638                         prv = &list_of_session_hooks;
1639                         while (*prv && *prv != hook)
1640                                 prv = &(*prv)->next;
1641                         if(*prv)
1642                                 *prv = hook->next;
1643                 }
1644                 pthread_rwlock_unlock(&rwlock);
1645                 if (hook) {
1646                         /* free */
1647                         free(hook->pattern);
1648                         free(hook);
1649                 }
1650         }
1651 }
1652
1653 /******************************************************************************
1654  * section: default callbacks for globals (global)
1655  *****************************************************************************/
1656
1657 static void _hook_global_(const char *format, ...)
1658 {
1659         va_list ap;
1660         va_start(ap, format);
1661         _hook_("global", format, ap);
1662         va_end(ap);
1663 }
1664
1665 static void hook_global_vverbose_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
1666 {
1667         int len;
1668         char *msg;
1669         va_list ap;
1670
1671         va_copy(ap, args);
1672         len = vasprintf(&msg, fmt, ap);
1673         va_end(ap);
1674
1675         if (len < 0)
1676                 _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt);
1677         else {
1678                 _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg);
1679                 free(msg);
1680         }
1681 }
1682
1683 static struct afb_hook_global_itf hook_global_default_itf = {
1684         .hook_global_vverbose = hook_global_vverbose_cb
1685 };
1686
1687 /******************************************************************************
1688  * section: hooks for tracing globals (global)
1689  *****************************************************************************/
1690
1691 #define _HOOK_GLOBAL_(what,...)   \
1692         struct afb_hook_global *hook; \
1693         struct afb_hookid hookid; \
1694         pthread_rwlock_rdlock(&rwlock); \
1695         init_hookid(&hookid); \
1696         hook = list_of_global_hooks; \
1697         while (hook) { \
1698                 if (hook->itf->hook_global_##what \
1699                  && (hook->flags & afb_hook_flag_global_##what) != 0) { \
1700                         hook->itf->hook_global_##what(hook->closure, &hookid, __VA_ARGS__); \
1701                 } \
1702                 hook = hook->next; \
1703         } \
1704         pthread_rwlock_unlock(&rwlock);
1705
1706 static void afb_hook_global_vverbose(int level, const char *file, int line, const char *func, const char *fmt, va_list args)
1707 {
1708         _HOOK_GLOBAL_(vverbose, level, file ?: "?", line, func ?: "?", fmt ?: "", args);
1709 }
1710
1711 /******************************************************************************
1712  * section: hooking globals (global)
1713  *****************************************************************************/
1714
1715 static void update_global()
1716 {
1717         struct afb_hook_global *hook;
1718         int flags = 0;
1719
1720         pthread_rwlock_rdlock(&rwlock);
1721         hook = list_of_global_hooks;
1722         while (hook) {
1723                 flags = hook->flags;
1724                 hook = hook->next;
1725         }
1726         verbose_observer = (flags & afb_hook_flag_global_vverbose) ? afb_hook_global_vverbose : NULL;
1727         pthread_rwlock_unlock(&rwlock);
1728 }
1729
1730 struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook_global_itf *itf, void *closure)
1731 {
1732         struct afb_hook_global *hook;
1733
1734         /* alloc the result */
1735         hook = calloc(1, sizeof *hook);
1736         if (hook == NULL)
1737                 return NULL;
1738
1739         /* initialise the rest */
1740         hook->refcount = 1;
1741         hook->flags = flags;
1742         hook->itf = itf ? itf : &hook_global_default_itf;
1743         hook->closure = closure;
1744
1745         /* record the hook */
1746         pthread_rwlock_wrlock(&rwlock);
1747         hook->next = list_of_global_hooks;
1748         list_of_global_hooks = hook;
1749         pthread_rwlock_unlock(&rwlock);
1750
1751         /* update hooking */
1752         update_global();
1753
1754         /* returns it */
1755         return hook;
1756 }
1757
1758 struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook)
1759 {
1760         pthread_rwlock_wrlock(&rwlock);
1761         hook->refcount++;
1762         pthread_rwlock_unlock(&rwlock);
1763         return hook;
1764 }
1765
1766 void afb_hook_unref_global(struct afb_hook_global *hook)
1767 {
1768         struct afb_hook_global **prv;
1769
1770         if (hook) {
1771                 pthread_rwlock_wrlock(&rwlock);
1772                 if (--hook->refcount)
1773                         hook = NULL;
1774                 else {
1775                         /* unlink */
1776                         prv = &list_of_global_hooks;
1777                         while (*prv && *prv != hook)
1778                                 prv = &(*prv)->next;
1779                         if(*prv)
1780                                 *prv = hook->next;
1781                 }
1782                 pthread_rwlock_unlock(&rwlock);
1783                 if (hook) {
1784                         /* free */
1785                         free(hook);
1786
1787                         /* update hooking */
1788                         update_global();
1789                 }
1790         }
1791 }
1792