48eb582a7b02a5571e5418877648fa86a70dd953
[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         ssize_t s;
740
741         if (result < 0)
742                 _hook_api_(export, "rootdir_get_fd() -> %d, %m", result);
743         else {
744                 snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
745                 s = readlink(proc, path, sizeof path);
746                 path[s < 0 ? 0 : s >= sizeof path ? sizeof path - 1 : s] = 0;
747                 _hook_api_(export, "rootdir_get_fd() -> %d = %s", result, path);
748         }
749 }
750
751 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)
752 {
753         char path[PATH_MAX], proc[100];
754         ssize_t s;
755
756         if (!locale)
757                 locale = "(null)";
758         if (result < 0)
759                 _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result);
760         else {
761                 snprintf(proc, sizeof proc, "/proc/self/fd/%d", result);
762                 s = readlink(proc, path, sizeof path);
763                 path[s < 0 ? 0 : s >= sizeof path ? sizeof path - 1 : s] = 0;
764                 _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path);
765         }
766 }
767
768 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)
769 {
770         _hook_api_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result);
771 }
772
773 static void hook_api_unstore_req_cb(void *closure, const struct afb_hookid *hookid,  const struct afb_export *export, struct afb_stored_req *sreq)
774 {
775         _hook_api_(export, "unstore_req(%p)", sreq);
776 }
777
778 static void hook_api_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized)
779 {
780         _hook_api_(export, "require_api(%s, %d)...", name, initialized);
781 }
782
783 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)
784 {
785         _hook_api_(export, "...require_api(%s, %d) -> %d", name, initialized, result);
786 }
787
788 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)
789 {
790         _hook_api_(export, "add_alias(%s -> %s) -> %d", api, alias?:"<null>", result);
791 }
792
793 static void hook_api_start_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
794 {
795         _hook_api_(export, "start.before");
796 }
797
798 static void hook_api_start_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status)
799 {
800         _hook_api_(export, "start.after -> %d", status);
801 }
802
803 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)
804 {
805         _hook_api_(export, "on_event.before(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
806 }
807
808 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)
809 {
810         _hook_api_(export, "on_event.after(%s, %d, %s)", event, event_x2, json_object_to_json_string(object));
811 }
812
813 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)
814 {
815         _hook_api_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
816 }
817
818 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)
819 {
820         _hook_api_(export, "    ...call... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:"");
821 }
822
823 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)
824 {
825         _hook_api_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
826 }
827
828 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)
829 {
830         _hook_api_(export, "    ...callsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:"");
831 }
832
833 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)
834 {
835         _hook_api_(export, "new_api.before %s (%s)%s ...", api, info?:"", noconcurrency?" no-concurrency" : "");
836 }
837
838 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)
839 {
840         _hook_api_(export, "... new_api.after %s -> %s (%d)", api, result >= 0 ? "OK" : "ERROR", result);
841 }
842
843 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)
844 {
845         _hook_api_(export, "set_verbs_v2 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
846 }
847
848 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)
849 {
850         _hook_api_(export, "set_verbs_v3 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
851 }
852
853 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)
854 {
855         _hook_api_(export, "add_verb(%s%s [%s]) -> %s (%d)", verb, glob?" (GLOB)":"", info?:"", result >= 0 ? "OK" : "ERROR", result);
856 }
857
858 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)
859 {
860         _hook_api_(export, "del_verb(%s) -> %s (%d)", verb, result >= 0 ? "OK" : "ERROR", result);
861 }
862
863 static void hook_api_api_set_on_event_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
864 {
865         _hook_api_(export, "set_on_event -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
866 }
867
868 static void hook_api_api_set_on_init_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
869 {
870         _hook_api_(export, "set_on_init -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
871 }
872
873 static void hook_api_api_seal_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export)
874 {
875         _hook_api_(export, "seal");
876 }
877
878 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)
879 {
880         _hook_api_(export, "event_handler_add(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
881 }
882
883 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)
884 {
885         _hook_api_(export, "event_handler_del(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result);
886 }
887
888 static void hook_api_class_provide_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
889 {
890         _hook_api_(export, "class_provide(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
891 }
892
893 static void hook_api_class_require_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name)
894 {
895         _hook_api_(export, "class_require(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result);
896 }
897
898 static void hook_api_delete_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result)
899 {
900         _hook_api_(export, "delete_api -> %s (%d)", result >= 0 ? "OK" : "ERROR", result);
901 }
902
903 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)
904 {
905         _hook_api_(export, "on_event_handler[%s].before(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
906 }
907
908 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)
909 {
910         _hook_api_(export, "on_event_handler[%s].after(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object));
911 }
912
913 static struct afb_hook_api_itf hook_api_default_itf = {
914         .hook_api_event_broadcast_before = hook_api_event_broadcast_before_cb,
915         .hook_api_event_broadcast_after = hook_api_event_broadcast_after_cb,
916         .hook_api_get_event_loop = hook_api_get_event_loop_cb,
917         .hook_api_get_user_bus = hook_api_get_user_bus_cb,
918         .hook_api_get_system_bus = hook_api_get_system_bus_cb,
919         .hook_api_vverbose = hook_api_vverbose_cb,
920         .hook_api_event_make = hook_api_event_make_cb,
921         .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd_cb,
922         .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale_cb,
923         .hook_api_queue_job = hook_api_queue_job_cb,
924         .hook_api_legacy_unstore_req = hook_api_unstore_req_cb,
925         .hook_api_require_api = hook_api_require_api_cb,
926         .hook_api_require_api_result = hook_api_require_api_result_cb,
927         .hook_api_add_alias = hook_api_add_alias_cb,
928         .hook_api_start_before = hook_api_start_before_cb,
929         .hook_api_start_after = hook_api_start_after_cb,
930         .hook_api_on_event_before = hook_api_on_event_before_cb,
931         .hook_api_on_event_after = hook_api_on_event_after_cb,
932         .hook_api_call = hook_api_call_cb,
933         .hook_api_call_result = hook_api_call_result_cb,
934         .hook_api_callsync = hook_api_callsync_cb,
935         .hook_api_callsync_result = hook_api_callsync_result_cb,
936         .hook_api_new_api_before = hook_api_new_api_before_cb,
937         .hook_api_new_api_after = hook_api_new_api_after_cb,
938         .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2_cb,
939         .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3_cb,
940         .hook_api_api_add_verb = hook_api_api_add_verb_cb,
941         .hook_api_api_del_verb = hook_api_api_del_verb_cb,
942         .hook_api_api_set_on_event = hook_api_api_set_on_event_cb,
943         .hook_api_api_set_on_init = hook_api_api_set_on_init_cb,
944         .hook_api_api_seal = hook_api_api_seal_cb,
945         .hook_api_event_handler_add = hook_api_event_handler_add_cb,
946         .hook_api_event_handler_del = hook_api_event_handler_del_cb,
947         .hook_api_class_provide = hook_api_class_provide_cb,
948         .hook_api_class_require = hook_api_class_require_cb,
949         .hook_api_delete_api = hook_api_delete_api_cb,
950         .hook_api_on_event_handler_before = hook_api_on_event_handler_before_cb,
951         .hook_api_on_event_handler_after = hook_api_on_event_handler_after_cb,
952 };
953
954 /******************************************************************************
955  * section: hooks for tracing daemon interface (export)
956  *****************************************************************************/
957
958 #define _HOOK_API_2_(flag,func,...)   \
959         struct afb_hook_api *hook; \
960         struct afb_hookid hookid; \
961         const char *apiname = afb_export_apiname(export); \
962         pthread_rwlock_rdlock(&rwlock); \
963         init_hookid(&hookid); \
964         hook = list_of_api_hooks; \
965         while (hook) { \
966                 if (hook->itf->hook_api_##func \
967                  && (hook->flags & afb_hook_flag_api_##flag) != 0 \
968                  && MATCH_API(hook->api, apiname)) { \
969                         hook->itf->hook_api_##func(hook->closure, &hookid, __VA_ARGS__); \
970                 } \
971                 hook = hook->next; \
972         } \
973         pthread_rwlock_unlock(&rwlock);
974
975 #define _HOOK_API_(what,...)   _HOOK_API_2_(what,what,__VA_ARGS__)
976
977 void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object)
978 {
979         _HOOK_API_2_(event_broadcast, event_broadcast_before, export, name, object);
980 }
981
982 int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result)
983 {
984         _HOOK_API_2_(event_broadcast, event_broadcast_after, export, name, object, result);
985         return result;
986 }
987
988 struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result)
989 {
990         _HOOK_API_(get_event_loop, export, result);
991         return result;
992 }
993
994 struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result)
995 {
996         _HOOK_API_(get_user_bus, export, result);
997         return result;
998 }
999
1000 struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result)
1001 {
1002         _HOOK_API_(get_system_bus, export, result);
1003         return result;
1004 }
1005
1006 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)
1007 {
1008         _HOOK_API_(vverbose, export, level, file, line, function, fmt, args);
1009 }
1010
1011 struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result)
1012 {
1013         _HOOK_API_(event_make, export, name, result);
1014         return result;
1015 }
1016
1017 int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result)
1018 {
1019         _HOOK_API_(rootdir_get_fd, export, result);
1020         return result;
1021 }
1022
1023 int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result)
1024 {
1025         _HOOK_API_(rootdir_open_locale, export, filename, flags, locale, result);
1026         return result;
1027 }
1028
1029 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)
1030 {
1031         _HOOK_API_(queue_job, export, callback, argument, group, timeout, result);
1032         return result;
1033 }
1034
1035 void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq)
1036 {
1037         _HOOK_API_(legacy_unstore_req, export, sreq);
1038 }
1039
1040 void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized)
1041 {
1042         _HOOK_API_(require_api, export, name, initialized);
1043 }
1044
1045 int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result)
1046 {
1047         _HOOK_API_2_(require_api, require_api_result, export, name, initialized, result);
1048         return result;
1049 }
1050
1051 int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result)
1052 {
1053         _HOOK_API_(add_alias, export, api, alias, result);
1054         return result;
1055 }
1056
1057 void afb_hook_api_start_before(const struct afb_export *export)
1058 {
1059         _HOOK_API_2_(start, start_before, export);
1060 }
1061
1062 int afb_hook_api_start_after(const struct afb_export *export, int status)
1063 {
1064         _HOOK_API_2_(start, start_after, export, status);
1065         return status;
1066 }
1067
1068 void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
1069 {
1070         _HOOK_API_2_(on_event, on_event_before, export, event, event_x2, object);
1071 }
1072
1073 void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object)
1074 {
1075         _HOOK_API_2_(on_event, on_event_after, export, event, event_x2, object);
1076 }
1077
1078 void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
1079 {
1080         _HOOK_API_(call, export, api, verb, args);
1081 }
1082
1083 void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char*error, const char *info)
1084 {
1085         _HOOK_API_2_(call, call_result, export, object, error, info);
1086
1087 }
1088
1089 void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args)
1090 {
1091         _HOOK_API_(callsync, export, api, verb, args);
1092 }
1093
1094 int afb_hook_api_callsync_result(const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info)
1095 {
1096         _HOOK_API_2_(callsync, callsync_result, export, status, object, error, info);
1097         return status;
1098 }
1099
1100 void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency)
1101 {
1102         _HOOK_API_2_(new_api, new_api_before, export, api, info, noconcurrency);
1103 }
1104
1105 int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api)
1106 {
1107         _HOOK_API_2_(new_api, new_api_after, export, result, api);
1108         return result;
1109 }
1110
1111 int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs)
1112 {
1113         _HOOK_API_2_(api_set_verbs, api_set_verbs_v2, export, result, verbs);
1114         return result;
1115 }
1116
1117 int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs)
1118 {
1119         _HOOK_API_2_(api_set_verbs, api_set_verbs_v3, export, result, verbs);
1120         return result;
1121 }
1122
1123 int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob)
1124 {
1125         _HOOK_API_(api_add_verb, export, result, verb, info, glob);
1126         return result;
1127 }
1128
1129 int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb)
1130 {
1131         _HOOK_API_(api_del_verb, export, result, verb);
1132         return result;
1133 }
1134
1135 int afb_hook_api_api_set_on_event(const struct afb_export *export, int result)
1136 {
1137         _HOOK_API_(api_set_on_event, export, result);
1138         return result;
1139 }
1140
1141 int afb_hook_api_api_set_on_init(const struct afb_export *export, int result)
1142 {
1143         _HOOK_API_(api_set_on_init, export, result);
1144         return result;
1145 }
1146
1147 void afb_hook_api_api_seal(const struct afb_export *export)
1148 {
1149         _HOOK_API_(api_seal, export);
1150 }
1151
1152 int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern)
1153 {
1154         _HOOK_API_(event_handler_add, export, result, pattern);
1155         return result;
1156 }
1157 int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern)
1158 {
1159         _HOOK_API_(event_handler_del, export, result, pattern);
1160         return result;
1161 }
1162 int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name)
1163 {
1164         _HOOK_API_(class_provide, export, result, name);
1165         return result;
1166 }
1167 int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name)
1168 {
1169         _HOOK_API_(class_require, export, result, name);
1170         return result;
1171 }
1172
1173 int afb_hook_api_delete_api(const struct afb_export *export, int result)
1174 {
1175         _HOOK_API_(delete_api, export, result);
1176         return result;
1177 }
1178
1179 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)
1180 {
1181         _HOOK_API_2_(on_event_handler, on_event_handler_before, export, event, event_x2, object, pattern);
1182 }
1183
1184 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)
1185 {
1186         _HOOK_API_2_(on_event_handler, on_event_handler_after, export, event, event_x2, object, pattern);
1187 }
1188
1189 /******************************************************************************
1190  * section: hooking export
1191  *****************************************************************************/
1192
1193 int afb_hook_flags_api(const char *api)
1194 {
1195         int flags;
1196         struct afb_hook_api *hook;
1197
1198         flags = 0;
1199         pthread_rwlock_rdlock(&rwlock);
1200         hook = list_of_api_hooks;
1201         while (hook) {
1202                 if (!api || MATCH_API(hook->api, api))
1203                         flags |= hook->flags;
1204                 hook = hook->next;
1205         }
1206         pthread_rwlock_unlock(&rwlock);
1207         return flags;
1208 }
1209
1210 struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure)
1211 {
1212         struct afb_hook_api *hook;
1213
1214         /* alloc the result */
1215         hook = calloc(1, sizeof *hook);
1216         if (hook == NULL)
1217                 return NULL;
1218
1219         /* get a copy of the names */
1220         hook->api = api ? strdup(api) : NULL;
1221         if (api && !hook->api) {
1222                 free(hook);
1223                 return NULL;
1224         }
1225
1226         /* initialise the rest */
1227         hook->refcount = 1;
1228         hook->flags = flags;
1229         hook->itf = itf ? itf : &hook_api_default_itf;
1230         hook->closure = closure;
1231
1232         /* record the hook */
1233         pthread_rwlock_wrlock(&rwlock);
1234         hook->next = list_of_api_hooks;
1235         list_of_api_hooks = hook;
1236         pthread_rwlock_unlock(&rwlock);
1237
1238         /* returns it */
1239         return hook;
1240 }
1241
1242 struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook)
1243 {
1244         pthread_rwlock_wrlock(&rwlock);
1245         hook->refcount++;
1246         pthread_rwlock_unlock(&rwlock);
1247         return hook;
1248 }
1249
1250 void afb_hook_unref_api(struct afb_hook_api *hook)
1251 {
1252         struct afb_hook_api **prv;
1253
1254         if (hook) {
1255                 pthread_rwlock_wrlock(&rwlock);
1256                 if (--hook->refcount)
1257                         hook = NULL;
1258                 else {
1259                         /* unlink */
1260                         prv = &list_of_api_hooks;
1261                         while (*prv && *prv != hook)
1262                                 prv = &(*prv)->next;
1263                         if(*prv)
1264                                 *prv = hook->next;
1265                 }
1266                 pthread_rwlock_unlock(&rwlock);
1267                 if (hook) {
1268                         /* free */
1269                         free(hook->api);
1270                         free(hook);
1271                 }
1272         }
1273 }
1274
1275 /******************************************************************************
1276  * section: default callbacks for tracing service interface (evt)
1277  *****************************************************************************/
1278
1279 static void _hook_evt_(const char *evt, int id, const char *format, ...)
1280 {
1281         va_list ap;
1282         va_start(ap, format);
1283         _hook_("evt-%s:%d", format, ap, evt, id);
1284         va_end(ap);
1285 }
1286
1287 static void hook_evt_create_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1288 {
1289         _hook_evt_(evt, id, "create");
1290 }
1291
1292 static void hook_evt_push_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1293 {
1294         _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj));
1295 }
1296
1297
1298 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)
1299 {
1300         _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result);
1301 }
1302
1303 static void hook_evt_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj)
1304 {
1305         _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj));
1306 }
1307
1308 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)
1309 {
1310         _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result);
1311 }
1312
1313 static void hook_evt_name_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result)
1314 {
1315         _hook_evt_(evt, id, "name -> %s", result);
1316 }
1317
1318 static void hook_evt_addref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1319 {
1320         _hook_evt_(evt, id, "addref");
1321 }
1322
1323 static void hook_evt_unref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id)
1324 {
1325         _hook_evt_(evt, id, "unref");
1326 }
1327
1328 static struct afb_hook_evt_itf hook_evt_default_itf = {
1329         .hook_evt_create = hook_evt_create_cb,
1330         .hook_evt_push_before = hook_evt_push_before_cb,
1331         .hook_evt_push_after = hook_evt_push_after_cb,
1332         .hook_evt_broadcast_before = hook_evt_broadcast_before_cb,
1333         .hook_evt_broadcast_after = hook_evt_broadcast_after_cb,
1334         .hook_evt_name = hook_evt_name_cb,
1335         .hook_evt_addref = hook_evt_addref_cb,
1336         .hook_evt_unref = hook_evt_unref_cb
1337 };
1338
1339 /******************************************************************************
1340  * section: hooks for tracing events interface (evt)
1341  *****************************************************************************/
1342
1343 #define _HOOK_EVT_(what,...)   \
1344         struct afb_hook_evt *hook; \
1345         struct afb_hookid hookid; \
1346         pthread_rwlock_rdlock(&rwlock); \
1347         init_hookid(&hookid); \
1348         hook = list_of_evt_hooks; \
1349         while (hook) { \
1350                 if (hook->itf->hook_evt_##what \
1351                  && (hook->flags & afb_hook_flag_evt_##what) != 0 \
1352                  && MATCH_EVENT(hook->pattern, evt)) { \
1353                         hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \
1354                 } \
1355                 hook = hook->next; \
1356         } \
1357         pthread_rwlock_unlock(&rwlock);
1358
1359 void afb_hook_evt_create(const char *evt, int id)
1360 {
1361         _HOOK_EVT_(create, evt, id);
1362 }
1363
1364 void afb_hook_evt_push_before(const char *evt, int id, struct json_object *obj)
1365 {
1366         _HOOK_EVT_(push_before, evt, id, obj);
1367 }
1368
1369 int afb_hook_evt_push_after(const char *evt, int id, struct json_object *obj, int result)
1370 {
1371         _HOOK_EVT_(push_after, evt, id, obj, result);
1372         return result;
1373 }
1374
1375 void afb_hook_evt_broadcast_before(const char *evt, int id, struct json_object *obj)
1376 {
1377         _HOOK_EVT_(broadcast_before, evt, id, obj);
1378 }
1379
1380 int afb_hook_evt_broadcast_after(const char *evt, int id, struct json_object *obj, int result)
1381 {
1382         _HOOK_EVT_(broadcast_after, evt, id, obj, result);
1383         return result;
1384 }
1385
1386 void afb_hook_evt_name(const char *evt, int id, const char *result)
1387 {
1388         _HOOK_EVT_(name, evt, id, result);
1389 }
1390
1391 void afb_hook_evt_addref(const char *evt, int id)
1392 {
1393         _HOOK_EVT_(addref, evt, id);
1394 }
1395
1396 void afb_hook_evt_unref(const char *evt, int id)
1397 {
1398         _HOOK_EVT_(unref, evt, id);
1399 }
1400
1401 /******************************************************************************
1402  * section: hooking services (evt)
1403  *****************************************************************************/
1404
1405 int afb_hook_flags_evt(const char *name)
1406 {
1407         int flags;
1408         struct afb_hook_evt *hook;
1409
1410         flags = 0;
1411         pthread_rwlock_rdlock(&rwlock);
1412         hook = list_of_evt_hooks;
1413         while (hook) {
1414                 if (!name || MATCH_EVENT(hook->pattern, name))
1415                         flags |= hook->flags;
1416                 hook = hook->next;
1417         }
1418         pthread_rwlock_unlock(&rwlock);
1419         return flags;
1420 }
1421
1422 struct afb_hook_evt *afb_hook_create_evt(const char *pattern, int flags, struct afb_hook_evt_itf *itf, void *closure)
1423 {
1424         struct afb_hook_evt *hook;
1425
1426         /* alloc the result */
1427         hook = calloc(1, sizeof *hook);
1428         if (hook == NULL)
1429                 return NULL;
1430
1431         /* get a copy of the names */
1432         hook->pattern = pattern ? strdup(pattern) : NULL;
1433         if (pattern && !hook->pattern) {
1434                 free(hook);
1435                 return NULL;
1436         }
1437
1438         /* initialise the rest */
1439         hook->refcount = 1;
1440         hook->flags = flags;
1441         hook->itf = itf ? itf : &hook_evt_default_itf;
1442         hook->closure = closure;
1443
1444         /* record the hook */
1445         pthread_rwlock_wrlock(&rwlock);
1446         hook->next = list_of_evt_hooks;
1447         list_of_evt_hooks = hook;
1448         pthread_rwlock_unlock(&rwlock);
1449
1450         /* returns it */
1451         return hook;
1452 }
1453
1454 struct afb_hook_evt *afb_hook_addref_evt(struct afb_hook_evt *hook)
1455 {
1456         pthread_rwlock_wrlock(&rwlock);
1457         hook->refcount++;
1458         pthread_rwlock_unlock(&rwlock);
1459         return hook;
1460 }
1461
1462 void afb_hook_unref_evt(struct afb_hook_evt *hook)
1463 {
1464         struct afb_hook_evt **prv;
1465
1466         if (hook) {
1467                 pthread_rwlock_wrlock(&rwlock);
1468                 if (--hook->refcount)
1469                         hook = NULL;
1470                 else {
1471                         /* unlink */
1472                         prv = &list_of_evt_hooks;
1473                         while (*prv && *prv != hook)
1474                                 prv = &(*prv)->next;
1475                         if(*prv)
1476                                 *prv = hook->next;
1477                 }
1478                 pthread_rwlock_unlock(&rwlock);
1479                 if (hook) {
1480                         /* free */
1481                         free(hook->pattern);
1482                         free(hook);
1483                 }
1484         }
1485 }
1486
1487 /******************************************************************************
1488  * section: default callbacks for sessions (session)
1489  *****************************************************************************/
1490
1491 static void _hook_session_(struct afb_session *session, const char *format, ...)
1492 {
1493         va_list ap;
1494         va_start(ap, format);
1495         _hook_("session-%s", format, ap, afb_session_uuid(session));
1496         va_end(ap);
1497 }
1498
1499 static void hook_session_create_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1500 {
1501         _hook_session_(session, "create -> token=%s", afb_session_token(session));
1502 }
1503
1504 static void hook_session_close_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1505 {
1506         _hook_session_(session, "close");
1507 }
1508
1509 static void hook_session_destroy_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1510 {
1511         _hook_session_(session, "destroy");
1512 }
1513
1514 static void hook_session_renew_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1515 {
1516         _hook_session_(session, "renew -> token=%s", afb_session_token(session));
1517 }
1518
1519 static void hook_session_addref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1520 {
1521         _hook_session_(session, "addref");
1522 }
1523
1524 static void hook_session_unref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session)
1525 {
1526         _hook_session_(session, "unref");
1527 }
1528
1529 static struct afb_hook_session_itf hook_session_default_itf = {
1530         .hook_session_create = hook_session_create_cb,
1531         .hook_session_close = hook_session_close_cb,
1532         .hook_session_destroy = hook_session_destroy_cb,
1533         .hook_session_renew = hook_session_renew_cb,
1534         .hook_session_addref = hook_session_addref_cb,
1535         .hook_session_unref = hook_session_unref_cb
1536 };
1537
1538 /******************************************************************************
1539  * section: hooks for tracing sessions (session)
1540  *****************************************************************************/
1541
1542 #define _HOOK_SESSION_(what,...)   \
1543         struct afb_hook_session *hook; \
1544         struct afb_hookid hookid; \
1545         const char *sessid = 0; \
1546         pthread_rwlock_rdlock(&rwlock); \
1547         init_hookid(&hookid); \
1548         hook = list_of_session_hooks; \
1549         while (hook) { \
1550                 if (hook->itf->hook_session_##what \
1551                  && (hook->flags & afb_hook_flag_session_##what) != 0 \
1552                  && MATCH_SESSION(hook->pattern, (sessid?:(sessid=afb_session_uuid(session))))) { \
1553                         hook->itf->hook_session_##what(hook->closure, &hookid, __VA_ARGS__); \
1554                 } \
1555                 hook = hook->next; \
1556         } \
1557         pthread_rwlock_unlock(&rwlock);
1558
1559 void afb_hook_session_create(struct afb_session *session)
1560 {
1561         _HOOK_SESSION_(create, session);
1562 }
1563
1564 void afb_hook_session_close(struct afb_session *session)
1565 {
1566         _HOOK_SESSION_(close, session);
1567 }
1568
1569 void afb_hook_session_destroy(struct afb_session *session)
1570 {
1571         _HOOK_SESSION_(destroy, session);
1572 }
1573
1574 void afb_hook_session_renew(struct afb_session *session)
1575 {
1576         _HOOK_SESSION_(renew, session);
1577 }
1578
1579 void afb_hook_session_addref(struct afb_session *session)
1580 {
1581         _HOOK_SESSION_(addref, session);
1582 }
1583
1584 void afb_hook_session_unref(struct afb_session *session)
1585 {
1586         _HOOK_SESSION_(unref, session);
1587 }
1588
1589
1590 /******************************************************************************
1591  * section: hooking sessions (session)
1592  *****************************************************************************/
1593
1594 struct afb_hook_session *afb_hook_create_session(const char *pattern, int flags, struct afb_hook_session_itf *itf, void *closure)
1595 {
1596         struct afb_hook_session *hook;
1597
1598         /* alloc the result */
1599         hook = calloc(1, sizeof *hook);
1600         if (hook == NULL)
1601                 return NULL;
1602
1603         /* get a copy of the names */
1604         hook->pattern = pattern ? strdup(pattern) : NULL;
1605         if (pattern && !hook->pattern) {
1606                 free(hook);
1607                 return NULL;
1608         }
1609
1610         /* initialise the rest */
1611         hook->refcount = 1;
1612         hook->flags = flags;
1613         hook->itf = itf ? itf : &hook_session_default_itf;
1614         hook->closure = closure;
1615
1616         /* record the hook */
1617         pthread_rwlock_wrlock(&rwlock);
1618         hook->next = list_of_session_hooks;
1619         list_of_session_hooks = hook;
1620         pthread_rwlock_unlock(&rwlock);
1621
1622         /* returns it */
1623         return hook;
1624 }
1625
1626 struct afb_hook_session *afb_hook_addref_session(struct afb_hook_session *hook)
1627 {
1628         pthread_rwlock_wrlock(&rwlock);
1629         hook->refcount++;
1630         pthread_rwlock_unlock(&rwlock);
1631         return hook;
1632 }
1633
1634 void afb_hook_unref_session(struct afb_hook_session *hook)
1635 {
1636         struct afb_hook_session **prv;
1637
1638         if (hook) {
1639                 pthread_rwlock_wrlock(&rwlock);
1640                 if (--hook->refcount)
1641                         hook = NULL;
1642                 else {
1643                         /* unlink */
1644                         prv = &list_of_session_hooks;
1645                         while (*prv && *prv != hook)
1646                                 prv = &(*prv)->next;
1647                         if(*prv)
1648                                 *prv = hook->next;
1649                 }
1650                 pthread_rwlock_unlock(&rwlock);
1651                 if (hook) {
1652                         /* free */
1653                         free(hook->pattern);
1654                         free(hook);
1655                 }
1656         }
1657 }
1658
1659 /******************************************************************************
1660  * section: default callbacks for globals (global)
1661  *****************************************************************************/
1662
1663 static void _hook_global_(const char *format, ...)
1664 {
1665         va_list ap;
1666         va_start(ap, format);
1667         _hook_("global", format, ap);
1668         va_end(ap);
1669 }
1670
1671 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)
1672 {
1673         int len;
1674         char *msg;
1675         va_list ap;
1676
1677         va_copy(ap, args);
1678         len = vasprintf(&msg, fmt, ap);
1679         va_end(ap);
1680
1681         if (len < 0)
1682                 _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt);
1683         else {
1684                 _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg);
1685                 free(msg);
1686         }
1687 }
1688
1689 static struct afb_hook_global_itf hook_global_default_itf = {
1690         .hook_global_vverbose = hook_global_vverbose_cb
1691 };
1692
1693 /******************************************************************************
1694  * section: hooks for tracing globals (global)
1695  *****************************************************************************/
1696
1697 #define _HOOK_GLOBAL_(what,...)   \
1698         struct afb_hook_global *hook; \
1699         struct afb_hookid hookid; \
1700         pthread_rwlock_rdlock(&rwlock); \
1701         init_hookid(&hookid); \
1702         hook = list_of_global_hooks; \
1703         while (hook) { \
1704                 if (hook->itf->hook_global_##what \
1705                  && (hook->flags & afb_hook_flag_global_##what) != 0) { \
1706                         hook->itf->hook_global_##what(hook->closure, &hookid, __VA_ARGS__); \
1707                 } \
1708                 hook = hook->next; \
1709         } \
1710         pthread_rwlock_unlock(&rwlock);
1711
1712 static void afb_hook_global_vverbose(int level, const char *file, int line, const char *func, const char *fmt, va_list args)
1713 {
1714         _HOOK_GLOBAL_(vverbose, level, file ?: "?", line, func ?: "?", fmt ?: "", args);
1715 }
1716
1717 /******************************************************************************
1718  * section: hooking globals (global)
1719  *****************************************************************************/
1720
1721 static void update_global()
1722 {
1723         struct afb_hook_global *hook;
1724         int flags = 0;
1725
1726         pthread_rwlock_rdlock(&rwlock);
1727         hook = list_of_global_hooks;
1728         while (hook) {
1729                 flags = hook->flags;
1730                 hook = hook->next;
1731         }
1732         verbose_observer = (flags & afb_hook_flag_global_vverbose) ? afb_hook_global_vverbose : NULL;
1733         pthread_rwlock_unlock(&rwlock);
1734 }
1735
1736 struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook_global_itf *itf, void *closure)
1737 {
1738         struct afb_hook_global *hook;
1739
1740         /* alloc the result */
1741         hook = calloc(1, sizeof *hook);
1742         if (hook == NULL)
1743                 return NULL;
1744
1745         /* initialise the rest */
1746         hook->refcount = 1;
1747         hook->flags = flags;
1748         hook->itf = itf ? itf : &hook_global_default_itf;
1749         hook->closure = closure;
1750
1751         /* record the hook */
1752         pthread_rwlock_wrlock(&rwlock);
1753         hook->next = list_of_global_hooks;
1754         list_of_global_hooks = hook;
1755         pthread_rwlock_unlock(&rwlock);
1756
1757         /* update hooking */
1758         update_global();
1759
1760         /* returns it */
1761         return hook;
1762 }
1763
1764 struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook)
1765 {
1766         pthread_rwlock_wrlock(&rwlock);
1767         hook->refcount++;
1768         pthread_rwlock_unlock(&rwlock);
1769         return hook;
1770 }
1771
1772 void afb_hook_unref_global(struct afb_hook_global *hook)
1773 {
1774         struct afb_hook_global **prv;
1775
1776         if (hook) {
1777                 pthread_rwlock_wrlock(&rwlock);
1778                 if (--hook->refcount)
1779                         hook = NULL;
1780                 else {
1781                         /* unlink */
1782                         prv = &list_of_global_hooks;
1783                         while (*prv && *prv != hook)
1784                                 prv = &(*prv)->next;
1785                         if(*prv)
1786                                 *prv = hook->next;
1787                 }
1788                 pthread_rwlock_unlock(&rwlock);
1789                 if (hook) {
1790                         /* free */
1791                         free(hook);
1792
1793                         /* update hooking */
1794                         update_global();
1795                 }
1796         }
1797 }
1798