Add hooking for events
[src/app-framework-binder.git] / src / afb-hook.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <fnmatch.h>
27
28 #include <json-c/json.h>
29
30 #include <afb/afb-req-itf.h>
31 #include <afb/afb-event-itf.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-ditf.h"
39 #include "afb-svc.h"
40 #include "afb-evt.h"
41 #include "verbose.h"
42
43 /**
44  * Definition of a hook for xreq
45  */
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 */
55 };
56
57 /**
58  * Definition of a hook for ditf
59  */
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 */
67 };
68
69 /**
70  * Definition of a hook for svc
71  */
72 struct afb_hook_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 */
79 };
80
81 /* synchronisation across threads */
82 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
83
84 /* list of hooks for xreq */
85 static struct afb_hook_xreq *list_of_xreq_hooks = NULL;
86
87 /* list of hooks for ditf */
88 static struct afb_hook_ditf *list_of_ditf_hooks = NULL;
89
90 /* list of hooks for svc */
91 static struct afb_hook_svc *list_of_svc_hooks = NULL;
92
93 /******************************************************************************
94  * section: default callbacks for tracing requests
95  *****************************************************************************/
96
97 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
98 {
99         int len;
100         char *buffer;
101         va_list ap;
102
103         va_start(ap, format);
104         len = vasprintf(&buffer, format, ap);
105         va_end(ap);
106
107         if (len < 0)
108                 NOTICE("hook xreq-%06d:%s/%s allocation error", xreq->hookindex, xreq->api, xreq->verb);
109         else {
110                 NOTICE("hook xreq-%06d:%s/%s %s", xreq->hookindex, xreq->api, xreq->verb, buffer);
111                 free(buffer);
112         }
113 }
114
115 static void hook_xreq_begin_default_cb(void * closure, const struct afb_xreq *xreq)
116 {
117         if (!xreq->cred)
118                 _hook_xreq_(xreq, "BEGIN");
119         else
120                 _hook_xreq_(xreq, "BEGIN uid=%d=%s gid=%d pid=%d label=%s id=%s",
121                         (int)xreq->cred->uid,
122                         xreq->cred->user,
123                         (int)xreq->cred->gid,
124                         (int)xreq->cred->pid,
125                         xreq->cred->label?:"(null)",
126                         xreq->cred->id?:"(null)"
127                 );
128 }
129
130 static void hook_xreq_end_default_cb(void * closure, const struct afb_xreq *xreq)
131 {
132         _hook_xreq_(xreq, "END");
133 }
134
135 static void hook_xreq_json_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj)
136 {
137         _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
138 }
139
140 static void hook_xreq_get_default_cb(void * closure, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
141 {
142         _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
143 }
144
145 static void hook_xreq_success_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
146 {
147         _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
148 }
149
150 static void hook_xreq_fail_default_cb(void * closure, const struct afb_xreq *xreq, const char *status, const char *info)
151 {
152         _hook_xreq_(xreq, "fail(%s, %s)", status, info);
153 }
154
155 static void hook_xreq_context_get_default_cb(void * closure, const struct afb_xreq *xreq, void *value)
156 {
157         _hook_xreq_(xreq, "context_get() -> %p", value);
158 }
159
160 static void hook_xreq_context_set_default_cb(void * closure, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
161 {
162         _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
163 }
164
165 static void hook_xreq_addref_default_cb(void * closure, const struct afb_xreq *xreq)
166 {
167         _hook_xreq_(xreq, "addref()");
168 }
169
170 static void hook_xreq_unref_default_cb(void * closure, const struct afb_xreq *xreq)
171 {
172         _hook_xreq_(xreq, "unref()");
173 }
174
175 static void hook_xreq_session_close_default_cb(void * closure, const struct afb_xreq *xreq)
176 {
177         _hook_xreq_(xreq, "session_close()");
178 }
179
180 static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct afb_xreq *xreq, unsigned level, int result)
181 {
182         _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
183 }
184
185 static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
186 {
187         _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
188 }
189
190 static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
191 {
192         _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_name(event), afb_evt_event_id(event), result);
193 }
194
195 static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
196 {
197         _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
198 }
199
200 static void hook_xreq_subcall_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
201 {
202         _hook_xreq_(xreq, "    ...subcall... -> %d: %s", status, json_object_to_json_string(result));
203 }
204
205 static void hook_xreq_subcallsync_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
206 {
207         _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
208 }
209
210 static void hook_xreq_subcallsync_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
211 {
212         _hook_xreq_(xreq, "    ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
213 }
214
215 static void hook_xreq_vverbose_default_cb(void * closure, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args)
216 {
217         int len;
218         char *msg;
219         va_list ap;
220
221         va_copy(ap, args);
222         len = vasprintf(&msg, fmt, ap);
223         va_end(ap);
224
225         if (len < 0)
226                 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt);
227         else {
228                 _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg);
229                 free(msg);
230         }
231 }
232
233 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
234         .hook_xreq_begin = hook_xreq_begin_default_cb,
235         .hook_xreq_end = hook_xreq_end_default_cb,
236         .hook_xreq_json = hook_xreq_json_default_cb,
237         .hook_xreq_get = hook_xreq_get_default_cb,
238         .hook_xreq_success = hook_xreq_success_default_cb,
239         .hook_xreq_fail = hook_xreq_fail_default_cb,
240         .hook_xreq_context_get = hook_xreq_context_get_default_cb,
241         .hook_xreq_context_set = hook_xreq_context_set_default_cb,
242         .hook_xreq_addref = hook_xreq_addref_default_cb,
243         .hook_xreq_unref = hook_xreq_unref_default_cb,
244         .hook_xreq_session_close = hook_xreq_session_close_default_cb,
245         .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
246         .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
247         .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
248         .hook_xreq_subcall = hook_xreq_subcall_default_cb,
249         .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
250         .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
251         .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
252         .hook_xreq_vverbose = hook_xreq_vverbose_default_cb
253 };
254
255 /******************************************************************************
256  * section: hooks for tracing requests
257  *****************************************************************************/
258
259 #define _HOOK_XREQ_(what,...)   \
260         struct afb_hook_xreq *hook; \
261         pthread_rwlock_rdlock(&rwlock); \
262         hook = list_of_xreq_hooks; \
263         while (hook) { \
264                 if (hook->itf->hook_xreq_##what \
265                  && (hook->flags & afb_hook_flag_req_##what) != 0 \
266                  && (!hook->session || hook->session == xreq->context.session) \
267                  && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
268                  && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
269                         hook->itf->hook_xreq_##what(hook->closure, __VA_ARGS__); \
270                 } \
271                 hook = hook->next; \
272         } \
273         pthread_rwlock_unlock(&rwlock);
274
275
276 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
277 {
278         _HOOK_XREQ_(begin, xreq);
279 }
280
281 void afb_hook_xreq_end(const struct afb_xreq *xreq)
282 {
283         _HOOK_XREQ_(end, xreq);
284 }
285
286 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
287 {
288         _HOOK_XREQ_(json, xreq, obj);
289         return obj;
290 }
291
292 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
293 {
294         _HOOK_XREQ_(get, xreq, name, arg);
295         return arg;
296 }
297
298 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
299 {
300         _HOOK_XREQ_(success, xreq, obj, info);
301 }
302
303 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
304 {
305         _HOOK_XREQ_(fail, xreq, status, info);
306 }
307
308 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
309 {
310         _HOOK_XREQ_(context_get, xreq, value);
311         return value;
312 }
313
314 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
315 {
316         _HOOK_XREQ_(context_set, xreq, value, free_value);
317 }
318
319 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
320 {
321         _HOOK_XREQ_(addref, xreq);
322 }
323
324 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
325 {
326         _HOOK_XREQ_(unref, xreq);
327 }
328
329 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
330 {
331         _HOOK_XREQ_(session_close, xreq);
332 }
333
334 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
335 {
336         _HOOK_XREQ_(session_set_LOA, xreq, level, result);
337         return result;
338 }
339
340 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
341 {
342         _HOOK_XREQ_(subscribe, xreq, event, result);
343         return result;
344 }
345
346 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
347 {
348         _HOOK_XREQ_(unsubscribe, xreq, event, result);
349         return result;
350 }
351
352 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
353 {
354         _HOOK_XREQ_(subcall, xreq, api, verb, args);
355 }
356
357 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
358 {
359         _HOOK_XREQ_(subcall_result, xreq, status, result);
360 }
361
362 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
363 {
364         _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
365 }
366
367 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
368 {
369         _HOOK_XREQ_(subcallsync_result, xreq, status, result);
370         return status;
371 }
372
373 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)
374 {
375         _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args);
376 }
377
378 /******************************************************************************
379  * section: hooking xreqs
380  *****************************************************************************/
381
382 void afb_hook_init_xreq(struct afb_xreq *xreq)
383 {
384         static int reqindex;
385
386         int f, flags;
387         int add;
388         struct afb_hook_xreq *hook;
389
390         /* scan hook list to get the expected flags */
391         flags = 0;
392         pthread_rwlock_rdlock(&rwlock);
393         hook = list_of_xreq_hooks;
394         while (hook) {
395                 f = hook->flags & afb_hook_flags_req_all;
396                 add = f != 0
397                    && (!hook->session || hook->session == xreq->context.session)
398                    && (!hook->api || !strcasecmp(hook->api, xreq->api))
399                    && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
400                 if (add)
401                         flags |= f;
402                 hook = hook->next;
403         }
404         pthread_rwlock_unlock(&rwlock);
405
406         /* store the hooking data */
407         xreq->hookflags = flags;
408         if (flags) {
409                 pthread_rwlock_wrlock(&rwlock);
410                 if (++reqindex < 0)
411                         reqindex = 1;
412                 xreq->hookindex = reqindex;
413                 pthread_rwlock_unlock(&rwlock);
414         }
415 }
416
417 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)
418 {
419         struct afb_hook_xreq *hook;
420
421         /* alloc the result */
422         hook = calloc(1, sizeof *hook);
423         if (hook == NULL)
424                 return NULL;
425
426         /* get a copy of the names */
427         hook->api = api ? strdup(api) : NULL;
428         hook->verb = verb ? strdup(verb) : NULL;
429         if ((api && !hook->api) || (verb && !hook->verb)) {
430                 free(hook->api);
431                 free(hook->verb);
432                 free(hook);
433                 return NULL;
434         }
435
436         /* initialise the rest */
437         hook->session = session;
438         if (session)
439                 afb_session_addref(session);
440         hook->refcount = 1;
441         hook->flags = flags;
442         hook->itf = itf ? itf : &hook_xreq_default_itf;
443         hook->closure = closure;
444
445         /* record the hook */
446         pthread_rwlock_wrlock(&rwlock);
447         hook->next = list_of_xreq_hooks;
448         list_of_xreq_hooks = hook;
449         pthread_rwlock_unlock(&rwlock);
450
451         /* returns it */
452         return hook;
453 }
454
455 struct afb_hook_xreq *afb_hook_addref_xreq(struct afb_hook_xreq *hook)
456 {
457         pthread_rwlock_wrlock(&rwlock);
458         hook->refcount++;
459         pthread_rwlock_unlock(&rwlock);
460         return hook;
461 }
462
463 void afb_hook_unref_xreq(struct afb_hook_xreq *hook)
464 {
465         struct afb_hook_xreq **prv;
466
467         if (hook) {
468                 pthread_rwlock_wrlock(&rwlock);
469                 if (--hook->refcount)
470                         hook = NULL;
471                 else {
472                         /* unlink */
473                         prv = &list_of_xreq_hooks;
474                         while (*prv && *prv != hook)
475                                 prv = &(*prv)->next;
476                         if(*prv)
477                                 *prv = hook->next;
478                 }
479                 pthread_rwlock_unlock(&rwlock);
480                 if (hook) {
481                         /* free */
482                         free(hook->api);
483                         free(hook->verb);
484                         if (hook->session)
485                                 afb_session_unref(hook->session);
486                         free(hook);
487                 }
488         }
489 }
490
491 /******************************************************************************
492  * section: default callbacks for tracing daemon interface
493  *****************************************************************************/
494
495 static void _hook_ditf_(const struct afb_ditf *ditf, const char *format, ...)
496 {
497         int len;
498         char *buffer;
499         va_list ap;
500
501         va_start(ap, format);
502         len = vasprintf(&buffer, format, ap);
503         va_end(ap);
504
505         if (len < 0)
506                 NOTICE("hook ditf-%s allocation error for %s", ditf->prefix, format);
507         else {
508                 NOTICE("hook ditf-%s %s", ditf->prefix, buffer);
509                 free(buffer);
510         }
511 }
512
513 static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object)
514 {
515         _hook_ditf_(ditf, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object));
516 }
517
518 static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
519 {
520         _hook_ditf_(ditf, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result);
521 }
522
523 static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_ditf *ditf, struct sd_event *result)
524 {
525         _hook_ditf_(ditf, "get_event_loop() -> %p", result);
526 }
527
528 static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
529 {
530         _hook_ditf_(ditf, "get_user_bus() -> %p", result);
531 }
532
533 static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_ditf *ditf, struct sd_bus *result)
534 {
535         _hook_ditf_(ditf, "get_system_bus() -> %p", result);
536 }
537
538 static void hook_ditf_vverbose_cb(void*closure, const struct afb_ditf *ditf, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
539 {
540         int len;
541         char *msg;
542         va_list ap;
543
544         va_copy(ap, args);
545         len = vasprintf(&msg, fmt, ap);
546         va_end(ap);
547
548         if (len < 0)
549                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt);
550         else {
551                 _hook_ditf_(ditf, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg);
552                 free(msg);
553         }
554 }
555
556 static void hook_ditf_event_make_cb(void *closure, const struct afb_ditf *ditf, const char *name, struct afb_event result)
557 {
558         _hook_ditf_(ditf, "event_make(%s) -> %s:%d", name, afb_evt_event_name(result), afb_evt_event_id(result));
559 }
560
561 static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_ditf *ditf, int result)
562 {
563         char path[PATH_MAX];
564         if (result < 0)
565                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d, %m", result);
566         else {
567                 sprintf(path, "/proc/self/fd/%d", result);
568                 readlink(path, path, sizeof path);
569                 _hook_ditf_(ditf, "rootdir_get_fd() -> %d = %s", result, path);
570         }
571 }
572
573 static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
574 {
575         char path[PATH_MAX];
576         if (!locale)
577                 locale = "(null)";
578         if (result < 0)
579                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
580         else {
581                 sprintf(path, "/proc/self/fd/%d", result);
582                 readlink(path, path, sizeof path);
583                 _hook_ditf_(ditf, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
584         }
585 }
586
587 static void hook_ditf_queue_job(void *closure, const struct afb_ditf *ditf, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result)
588 {
589         _hook_ditf_(ditf, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
590 }
591
592 static struct afb_hook_ditf_itf hook_ditf_default_itf = {
593         .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb,
594         .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb,
595         .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb,
596         .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb,
597         .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb,
598         .hook_ditf_vverbose = hook_ditf_vverbose_cb,
599         .hook_ditf_event_make = hook_ditf_event_make_cb,
600         .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb,
601         .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb,
602         .hook_ditf_queue_job = hook_ditf_queue_job
603 };
604
605 /******************************************************************************
606  * section: hooks for tracing daemon interface (ditf)
607  *****************************************************************************/
608
609 #define _HOOK_DITF_(what,...)   \
610         struct afb_hook_ditf *hook; \
611         pthread_rwlock_rdlock(&rwlock); \
612         hook = list_of_ditf_hooks; \
613         while (hook) { \
614                 if (hook->itf->hook_ditf_##what \
615                  && (hook->flags & afb_hook_flag_ditf_##what) != 0 \
616                  && (!hook->api || !strcasecmp(hook->api, ditf->prefix))) { \
617                         hook->itf->hook_ditf_##what(hook->closure, __VA_ARGS__); \
618                 } \
619                 hook = hook->next; \
620         } \
621         pthread_rwlock_unlock(&rwlock);
622
623 void afb_hook_ditf_event_broadcast_before(const struct afb_ditf *ditf, const char *name, struct json_object *object)
624 {
625         _HOOK_DITF_(event_broadcast_before, ditf, name, object);
626 }
627
628 int afb_hook_ditf_event_broadcast_after(const struct afb_ditf *ditf, const char *name, struct json_object *object, int result)
629 {
630         _HOOK_DITF_(event_broadcast_after, ditf, name, object, result);
631         return result;
632 }
633
634 struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_ditf *ditf, struct sd_event *result)
635 {
636         _HOOK_DITF_(get_event_loop, ditf, result);
637         return result;
638 }
639
640 struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_ditf *ditf, struct sd_bus *result)
641 {
642         _HOOK_DITF_(get_user_bus, ditf, result);
643         return result;
644 }
645
646 struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_ditf *ditf, struct sd_bus *result)
647 {
648         _HOOK_DITF_(get_system_bus, ditf, result);
649         return result;
650 }
651
652 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)
653 {
654         _HOOK_DITF_(vverbose, ditf, level, file, line, function, fmt, args);
655 }
656
657 struct afb_event afb_hook_ditf_event_make(const struct afb_ditf *ditf, const char *name, struct afb_event result)
658 {
659         _HOOK_DITF_(event_make, ditf, name, result);
660         return result;
661 }
662
663 int afb_hook_ditf_rootdir_get_fd(const struct afb_ditf *ditf, int result)
664 {
665         _HOOK_DITF_(rootdir_get_fd, ditf, result);
666         return result;
667 }
668
669 int afb_hook_ditf_rootdir_open_locale(const struct afb_ditf *ditf, const char *filename, int flags, const char *locale, int result)
670 {
671         _HOOK_DITF_(rootdir_open_locale, ditf, filename, flags, locale, result);
672         return result;
673 }
674
675 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)
676 {
677         _HOOK_DITF_(queue_job, ditf, callback, argument, group, timeout, result);
678         return result;
679 }
680
681 /******************************************************************************
682  * section: hooking ditf
683  *****************************************************************************/
684
685 int afb_hook_flags_ditf(const char *api)
686 {
687         int flags;
688         struct afb_hook_ditf *hook;
689
690         pthread_rwlock_rdlock(&rwlock);
691         flags = 0;
692         hook = list_of_ditf_hooks;
693         while (hook) {
694                 if (!api || !hook->api || !strcasecmp(hook->api, api))
695                         flags |= hook->flags;
696                 hook = hook->next;
697         }
698         pthread_rwlock_unlock(&rwlock);
699         return flags;
700 }
701
702 struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure)
703 {
704         struct afb_hook_ditf *hook;
705
706         /* alloc the result */
707         hook = calloc(1, sizeof *hook);
708         if (hook == NULL)
709                 return NULL;
710
711         /* get a copy of the names */
712         hook->api = api ? strdup(api) : NULL;
713         if (api && !hook->api) {
714                 free(hook);
715                 return NULL;
716         }
717
718         /* initialise the rest */
719         hook->refcount = 1;
720         hook->flags = flags;
721         hook->itf = itf ? itf : &hook_ditf_default_itf;
722         hook->closure = closure;
723
724         /* record the hook */
725         pthread_rwlock_wrlock(&rwlock);
726         hook->next = list_of_ditf_hooks;
727         list_of_ditf_hooks = hook;
728         pthread_rwlock_unlock(&rwlock);
729
730         /* returns it */
731         return hook;
732 }
733
734 struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook)
735 {
736         pthread_rwlock_wrlock(&rwlock);
737         hook->refcount++;
738         pthread_rwlock_unlock(&rwlock);
739         return hook;
740 }
741
742 void afb_hook_unref_ditf(struct afb_hook_ditf *hook)
743 {
744         struct afb_hook_ditf **prv;
745
746         if (hook) {
747                 pthread_rwlock_wrlock(&rwlock);
748                 if (--hook->refcount)
749                         hook = NULL;
750                 else {
751                         /* unlink */
752                         prv = &list_of_ditf_hooks;
753                         while (*prv && *prv != hook)
754                                 prv = &(*prv)->next;
755                         if(*prv)
756                                 *prv = hook->next;
757                 }
758                 pthread_rwlock_unlock(&rwlock);
759                 if (hook) {
760                         /* free */
761                         free(hook->api);
762                         free(hook);
763                 }
764         }
765 }
766
767 /******************************************************************************
768  * section: default callbacks for tracing service interface (svc)
769  *****************************************************************************/
770
771 static void _hook_svc_(const struct afb_svc *svc, const char *format, ...)
772 {
773         int len;
774         char *buffer;
775         va_list ap;
776
777         va_start(ap, format);
778         len = vasprintf(&buffer, format, ap);
779         va_end(ap);
780
781         if (len < 0)
782                 NOTICE("hook svc-%s allocation error for %s", svc->api, format);
783         else {
784                 NOTICE("hook svc-%s %s", svc->api, buffer);
785                 free(buffer);
786         }
787 }
788
789 static void hook_svc_start_before_default_cb(void *closure, const struct afb_svc *svc)
790 {
791         _hook_svc_(svc, "start.before");
792 }
793
794 static void hook_svc_start_after_default_cb(void *closure, const struct afb_svc *svc, int status)
795 {
796         _hook_svc_(svc, "start.after -> %d", status);
797 }
798
799 static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
800 {
801         _hook_svc_(svc, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
802 }
803
804 static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
805 {
806         _hook_svc_(svc, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object));
807 }
808
809 static void hook_svc_call_default_cb(void *closure, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
810 {
811         _hook_svc_(svc, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
812 }
813
814 static void hook_svc_call_result_default_cb(void *closure, const struct afb_svc *svc, int status, struct json_object *result)
815 {
816         _hook_svc_(svc, "    ...call... -> %d: %s", status, json_object_to_json_string(result));
817 }
818
819 static void hook_svc_callsync_default_cb(void *closure, const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
820 {
821         _hook_svc_(svc, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
822 }
823
824 static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_svc *svc, int status, struct json_object *result)
825 {
826         _hook_svc_(svc, "    ...callsync... -> %d: %s", status, json_object_to_json_string(result));
827 }
828
829 static struct afb_hook_svc_itf hook_svc_default_itf = {
830         .hook_svc_start_before = hook_svc_start_before_default_cb,
831         .hook_svc_start_after = hook_svc_start_after_default_cb,
832         .hook_svc_on_event_before = hook_svc_on_event_before_default_cb,
833         .hook_svc_on_event_after = hook_svc_on_event_after_default_cb,
834         .hook_svc_call = hook_svc_call_default_cb,
835         .hook_svc_call_result = hook_svc_call_result_default_cb,
836         .hook_svc_callsync = hook_svc_callsync_default_cb,
837         .hook_svc_callsync_result = hook_svc_callsync_result_default_cb
838 };
839
840 /******************************************************************************
841  * section: hooks for tracing service interface (svc)
842  *****************************************************************************/
843
844 #define _HOOK_SVC_(what,...)   \
845         struct afb_hook_svc *hook; \
846         pthread_rwlock_rdlock(&rwlock); \
847         hook = list_of_svc_hooks; \
848         while (hook) { \
849                 if (hook->itf->hook_svc_##what \
850                  && (hook->flags & afb_hook_flag_svc_##what) != 0 \
851                  && (!hook->api || !strcasecmp(hook->api, svc->api))) { \
852                         hook->itf->hook_svc_##what(hook->closure, __VA_ARGS__); \
853                 } \
854                 hook = hook->next; \
855         } \
856         pthread_rwlock_unlock(&rwlock);
857
858 void afb_hook_svc_start_before(const struct afb_svc *svc)
859 {
860         _HOOK_SVC_(start_before, svc);
861 }
862
863 int afb_hook_svc_start_after(const struct afb_svc *svc, int status)
864 {
865         _HOOK_SVC_(start_after, svc, status);
866         return status;
867 }
868
869 void afb_hook_svc_on_event_before(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
870 {
871         _HOOK_SVC_(on_event_before, svc, event, eventid, object);
872 }
873
874 void afb_hook_svc_on_event_after(const struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
875 {
876         _HOOK_SVC_(on_event_after, svc, event, eventid, object);
877 }
878
879 void afb_hook_svc_call(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
880 {
881         _HOOK_SVC_(call, svc, api, verb, args);
882 }
883
884 void afb_hook_svc_call_result(const struct afb_svc *svc, int status, struct json_object *result)
885 {
886         _HOOK_SVC_(call_result, svc, status, result);
887 }
888
889 void afb_hook_svc_callsync(const struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
890 {
891         _HOOK_SVC_(callsync, svc, api, verb, args);
892 }
893
894 int afb_hook_svc_callsync_result(const struct afb_svc *svc, int status, struct json_object *result)
895 {
896         _HOOK_SVC_(callsync_result, svc, status, result);
897         return status;
898 }
899
900 /******************************************************************************
901  * section: hooking services (svc)
902  *****************************************************************************/
903
904 int afb_hook_flags_svc(const char *api)
905 {
906         int flags;
907         struct afb_hook_svc *hook;
908
909         pthread_rwlock_rdlock(&rwlock);
910         flags = 0;
911         hook = list_of_svc_hooks;
912         while (hook) {
913                 if (!api || !hook->api || !strcasecmp(hook->api, api))
914                         flags |= hook->flags;
915                 hook = hook->next;
916         }
917         pthread_rwlock_unlock(&rwlock);
918         return flags;
919 }
920
921 struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure)
922 {
923         struct afb_hook_svc *hook;
924
925         /* alloc the result */
926         hook = calloc(1, sizeof *hook);
927         if (hook == NULL)
928                 return NULL;
929
930         /* get a copy of the names */
931         hook->api = api ? strdup(api) : NULL;
932         if (api && !hook->api) {
933                 free(hook);
934                 return NULL;
935         }
936
937         /* initialise the rest */
938         hook->refcount = 1;
939         hook->flags = flags;
940         hook->itf = itf ? itf : &hook_svc_default_itf;
941         hook->closure = closure;
942
943         /* record the hook */
944         pthread_rwlock_wrlock(&rwlock);
945         hook->next = list_of_svc_hooks;
946         list_of_svc_hooks = hook;
947         pthread_rwlock_unlock(&rwlock);
948
949         /* returns it */
950         return hook;
951 }
952
953 struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook)
954 {
955         pthread_rwlock_wrlock(&rwlock);
956         hook->refcount++;
957         pthread_rwlock_unlock(&rwlock);
958         return hook;
959 }
960
961 void afb_hook_unref_svc(struct afb_hook_svc *hook)
962 {
963         struct afb_hook_svc **prv;
964
965         if (hook) {
966                 pthread_rwlock_wrlock(&rwlock);
967                 if (--hook->refcount)
968                         hook = NULL;
969                 else {
970                         /* unlink */
971                         prv = &list_of_svc_hooks;
972                         while (*prv && *prv != hook)
973                                 prv = &(*prv)->next;
974                         if(*prv)
975                                 *prv = hook->next;
976                 }
977                 pthread_rwlock_unlock(&rwlock);
978                 if (hook) {
979                         /* free */
980                         free(hook->api);
981                         free(hook);
982                 }
983         }
984 }
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 /*********************************************************
1027 * section hooking evt (event interface)
1028 *********************************************************/
1029
1030 /**
1031  * Definition of a hook for evt
1032  */
1033 struct afb_hook_evt {
1034         struct afb_hook_evt *next; /**< next hook */
1035         unsigned refcount; /**< reference count */
1036         char *pattern; /**< event pattern name hooked or NULL for any */
1037         unsigned flags; /**< hook flags */
1038         struct afb_hook_evt_itf *itf; /**< interface of hook */
1039         void *closure; /**< closure for callbacks */
1040 };
1041
1042 /* list of hooks for evt */
1043 static struct afb_hook_evt *list_of_evt_hooks = NULL;
1044
1045
1046 /******************************************************************************
1047  * section: default callbacks for tracing service interface (evt)
1048  *****************************************************************************/
1049
1050 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1051 {
1052         int len;
1053         char *buffer;
1054         va_list ap;
1055
1056         va_start(ap, format);
1057         len = vasprintf(&buffer, format, ap);
1058         va_end(ap);
1059
1060         if (len < 0)
1061                 NOTICE("hook evt-%s:%d allocation error for %s", evt, id, format);
1062         else {
1063                 NOTICE("hook evt-%s:%d %s", evt, id, buffer);
1064                 free(buffer);
1065         }
1066 }
1067
1068 static void hook_evt_create_default_cb(void *closure, const char *evt, int id)
1069 {
1070         _hook_evt_(evt, id, "create");
1071 }
1072
1073 static void hook_evt_push_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj)
1074 {
1075         _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1076 }
1077
1078
1079 static void hook_evt_push_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result)
1080 {
1081         _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1082 }
1083
1084 static void hook_evt_broadcast_before_default_cb(void *closure, const char *evt, int id, struct json_object *obj)
1085 {
1086         _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1087 }
1088
1089 static void hook_evt_broadcast_after_default_cb(void *closure, const char *evt, int id, struct json_object *obj, int result)
1090 {
1091         _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1092 }
1093
1094 static void hook_evt_name_default_cb(void *closure, const char *evt, int id)
1095 {
1096         _hook_evt_(evt, id, "name");
1097 }
1098
1099 static void hook_evt_drop_default_cb(void *closure, const char *evt, int id)
1100 {
1101         _hook_evt_(evt, id, "drop");
1102 }
1103
1104 static struct afb_hook_evt_itf hook_evt_default_itf = {
1105         .hook_evt_create = hook_evt_create_default_cb,
1106         .hook_evt_push_before = hook_evt_push_before_default_cb,
1107         .hook_evt_push_after = hook_evt_push_after_default_cb,
1108         .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb,
1109         .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb,
1110         .hook_evt_name = hook_evt_name_default_cb,
1111         .hook_evt_drop = hook_evt_drop_default_cb
1112 };
1113
1114 /******************************************************************************
1115  * section: hooks for tracing service interface (evt)
1116  *****************************************************************************/
1117
1118 #define _HOOK_EVT_(what,...)   \
1119         struct afb_hook_evt *hook; \
1120         pthread_rwlock_rdlock(&rwlock); \
1121         hook = list_of_evt_hooks; \
1122         while (hook) { \
1123                 if (hook->itf->hook_evt_##what \
1124                  && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1125                  && (!hook->pattern || !fnmatch(hook->pattern, evt, FNM_CASEFOLD))) { \
1126                         hook->itf->hook_evt_##what(hook->closure, __VA_ARGS__); \
1127                 } \
1128                 hook = hook->next; \
1129         } \
1130         pthread_rwlock_unlock(&rwlock);
1131
1132 void afb_hook_evt_create(const char *evt, int id)
1133 {
1134         _HOOK_EVT_(create, evt, id);
1135 }
1136
1137 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1138 {
1139         _HOOK_EVT_(push_before, evt, id, obj);
1140 }
1141
1142 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1143 {
1144         _HOOK_EVT_(push_after, evt, id, obj, result);
1145         return result;
1146 }
1147
1148 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1149 {
1150         _HOOK_EVT_(broadcast_before, evt, id, obj);
1151 }
1152
1153 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1154 {
1155         _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1156         return result;
1157 }
1158
1159 void afb_hook_evt_name(const char *evt, int id)
1160 {
1161         _HOOK_EVT_(name, evt, id);
1162 }
1163
1164 void afb_hook_evt_drop(const char *evt, int id)
1165 {
1166         _HOOK_EVT_(drop, evt, id);
1167 }
1168
1169 /******************************************************************************
1170  * section: hooking services (evt)
1171  *****************************************************************************/
1172
1173 int afb_hook_flags_evt(const char *name)
1174 {
1175         int flags;
1176         struct afb_hook_evt *hook;
1177
1178         pthread_rwlock_rdlock(&rwlock);
1179         flags = 0;
1180         hook = list_of_evt_hooks;
1181         while (hook) {
1182                 if (!name || !hook->pattern || !fnmatch(hook->pattern, name, FNM_CASEFOLD))
1183                         flags |= hook->flags;
1184                 hook = hook->next;
1185         }
1186         pthread_rwlock_unlock(&rwlock);
1187         return flags;
1188 }
1189
1190 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1191 {
1192         struct afb_hook_evt *hook;
1193
1194         /* alloc the result */
1195         hook = calloc(1, sizeof *hook);
1196         if (hook == NULL)
1197                 return NULL;
1198
1199         /* get a copy of the names */
1200         hook->pattern = pattern ? strdup(pattern) : NULL;
1201         if (pattern && !hook->pattern) {
1202                 free(hook);
1203                 return NULL;
1204         }
1205
1206         /* initialise the rest */
1207         hook->refcount = 1;
1208         hook->flags = flags;
1209         hook->itf = itf ? itf : &hook_evt_default_itf;
1210         hook->closure = closure;
1211
1212         /* record the hook */
1213         pthread_rwlock_wrlock(&rwlock);
1214         hook->next = list_of_evt_hooks;
1215         list_of_evt_hooks = hook;
1216         pthread_rwlock_unlock(&rwlock);
1217
1218         /* returns it */
1219         return hook;
1220 }
1221
1222 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1223 {
1224         pthread_rwlock_wrlock(&rwlock);
1225         hook->refcount++;
1226         pthread_rwlock_unlock(&rwlock);
1227         return hook;
1228 }
1229
1230 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1231 {
1232         struct afb_hook_evt **prv;
1233
1234         if (hook) {
1235                 pthread_rwlock_wrlock(&rwlock);
1236                 if (--hook->refcount)
1237                         hook = NULL;
1238                 else {
1239                         /* unlink */
1240                         prv = &list_of_evt_hooks;
1241                         while (*prv && *prv != hook)
1242                                 prv = &(*prv)->next;
1243                         if(*prv)
1244                                 *prv = hook->next;
1245                 }
1246                 pthread_rwlock_unlock(&rwlock);
1247                 if (hook) {
1248                         /* free */
1249                         free(hook->pattern);
1250                         free(hook);
1251                 }
1252         }
1253 }
1254
1255 #if 0
1256 #define afb_hook_flag_evt_create                        0x000001
1257 #define afb_hook_flag_evt_push_before                   0x000002
1258 #define afb_hook_flag_evt_push_after                    0x000004
1259 #define afb_hook_flag_evt_broadcast_before              0x000008
1260 #define afb_hook_flag_evt_broadcast_after               0x000010
1261 #define afb_hook_flag_evt_drop                          0x000020
1262 #define afb_hook_flag_evt_name                          0x000040
1263
1264 struct afb_hook_evt_itf {
1265         void (*hook_evt_create)(void *closure, const char *evt);
1266         void (*hook_evt_push_before)(void *closure, const char *evt);
1267         void (*hook_evt_push_after)(void *closure, const char *evt, int result);
1268         void (*hook_evt_broadcast_before)(void *closure, const char *evt);
1269         void (*hook_evt_broadcast_after)(void *closure, const char *evt, int result);
1270         void (*hook_evt_drop)(void *closure, const char *evt);
1271         void (*hook_evt_name)(void *closure, const char *evt);
1272 };
1273
1274 extern void afb_hook_evt_create(const char *evt);
1275 extern void afb_hook_evt_push_before(const char *evt);
1276 extern int afb_hook_evt_push_after(const char *evt, int result);
1277 extern void afb_hook_evt_broadcast_before(const char *evt);
1278 extern int afb_hook_evt_broadcast_after(const char *evt, int result);
1279 extern void afb_hook_evt_drop(const char *evt);
1280 extern void afb_hook_evt_name(const char *evt);
1281
1282 extern int afb_hook_flags_evt(const char *name);
1283 extern struct afb_hook_evt *afb_hook_create_evt(const char *name, int flags, struct afb_hook_evt_itf *itf, void *closure);
1284 extern struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook);
1285 extern void afb_hook_unref_evt(struct afb_hook_evt *hook);
1286 #endif