2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include <json-c/json.h>
27 #include <afb/afb-req-itf.h>
28 #include <afb/afb-event-itf.h>
30 #include "afb-context.h"
32 #include "afb-session.h"
37 * Definition of a hook
40 struct afb_hook *next; /**< next hook */
41 unsigned refcount; /**< reference count */
42 char *api; /**< api hooked or NULL for any */
43 char *verb; /**< verb hooked or NULL for any */
44 struct afb_session *session; /**< session hooked or NULL if any */
45 unsigned flags; /**< hook flags */
46 struct afb_hook_xreq_itf *reqitf; /**< interface of hook */
47 void *closure; /**< closure for callbacks */
51 * Structure for handling subcalls callbacks
54 struct afb_xreq *xreq; /* hookd request */
55 void (*callback)(void*, int, struct json_object*); /* client callback */
56 void *cb_closure; /* cient closure */
59 /* synchronisation across threads */
60 static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
63 static struct afb_hook *list_of_hooks = NULL;
65 /******************************************************************************
66 * section: default callbacks for tracing requests
67 *****************************************************************************/
69 static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...)
76 len = vasprintf(&buffer, format, ap);
80 NOTICE("hook xreq-%06d:%s/%s allocation error", xreq->hookindex, xreq->api, xreq->verb);
82 NOTICE("hook xreq-%06d:%s/%s %s", xreq->hookindex, xreq->api, xreq->verb, buffer);
87 static void hook_xreq_begin_default_cb(void * closure, const struct afb_xreq *xreq)
89 _hook_xreq_(xreq, "BEGIN");
92 static void hook_xreq_end_default_cb(void * closure, const struct afb_xreq *xreq)
94 _hook_xreq_(xreq, "END");
97 static void hook_xreq_json_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj)
99 _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj));
102 static void hook_xreq_get_default_cb(void * closure, const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
104 _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path);
107 static void hook_xreq_success_default_cb(void * closure, const struct afb_xreq *xreq, struct json_object *obj, const char *info)
109 _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info);
112 static void hook_xreq_fail_default_cb(void * closure, const struct afb_xreq *xreq, const char *status, const char *info)
114 _hook_xreq_(xreq, "fail(%s, %s)", status, info);
117 static void hook_xreq_raw_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
119 _hook_xreq_(xreq, "raw() -> %.*s", (int)size, buffer);
122 static void hook_xreq_send_default_cb(void * closure, const struct afb_xreq *xreq, const char *buffer, size_t size)
124 _hook_xreq_(xreq, "send(%.*s)", (int)size, buffer);
127 static void hook_xreq_context_get_default_cb(void * closure, const struct afb_xreq *xreq, void *value)
129 _hook_xreq_(xreq, "context_get() -> %p", value);
132 static void hook_xreq_context_set_default_cb(void * closure, const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
134 _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value);
137 static void hook_xreq_addref_default_cb(void * closure, const struct afb_xreq *xreq)
139 _hook_xreq_(xreq, "addref()");
142 static void hook_xreq_unref_default_cb(void * closure, const struct afb_xreq *xreq)
144 _hook_xreq_(xreq, "unref()");
147 static void hook_xreq_session_close_default_cb(void * closure, const struct afb_xreq *xreq)
149 _hook_xreq_(xreq, "session_close()");
152 static void hook_xreq_session_set_LOA_default_cb(void * closure, const struct afb_xreq *xreq, unsigned level, int result)
154 _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result);
157 static void hook_xreq_subscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
159 _hook_xreq_(xreq, "subscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
162 static void hook_xreq_unsubscribe_default_cb(void * closure, const struct afb_xreq *xreq, struct afb_event event, int result)
164 _hook_xreq_(xreq, "unsubscribe(%s:%p) -> %d", afb_event_name(event), event.closure, result);
167 static void hook_xreq_subcall_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
169 _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
172 static void hook_xreq_subcall_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
174 _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result));
177 static void hook_xreq_subcallsync_default_cb(void * closure, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
179 _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args));
182 static void hook_xreq_subcallsync_result_default_cb(void * closure, const struct afb_xreq *xreq, int status, struct json_object *result)
184 _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result));
187 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
188 .hook_xreq_begin = hook_xreq_begin_default_cb,
189 .hook_xreq_end = hook_xreq_end_default_cb,
190 .hook_xreq_json = hook_xreq_json_default_cb,
191 .hook_xreq_get = hook_xreq_get_default_cb,
192 .hook_xreq_success = hook_xreq_success_default_cb,
193 .hook_xreq_fail = hook_xreq_fail_default_cb,
194 .hook_xreq_raw = hook_xreq_raw_default_cb,
195 .hook_xreq_send = hook_xreq_send_default_cb,
196 .hook_xreq_context_get = hook_xreq_context_get_default_cb,
197 .hook_xreq_context_set = hook_xreq_context_set_default_cb,
198 .hook_xreq_addref = hook_xreq_addref_default_cb,
199 .hook_xreq_unref = hook_xreq_unref_default_cb,
200 .hook_xreq_session_close = hook_xreq_session_close_default_cb,
201 .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb,
202 .hook_xreq_subscribe = hook_xreq_subscribe_default_cb,
203 .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb,
204 .hook_xreq_subcall = hook_xreq_subcall_default_cb,
205 .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb,
206 .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb,
207 .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb,
210 /******************************************************************************
211 * section: hooks for tracing requests
212 *****************************************************************************/
214 #define _HOOK_XREQ_(what,...) \
215 struct afb_hook *hook; \
216 pthread_rwlock_rdlock(&rwlock); \
217 hook = list_of_hooks; \
219 if (hook->reqitf->hook_xreq_##what \
220 && (hook->flags & afb_hook_flag_req_##what) != 0 \
221 && (!hook->session || hook->session == xreq->context.session) \
222 && (!hook->api || !strcasecmp(hook->api, xreq->api)) \
223 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb))) { \
224 hook->reqitf->hook_xreq_##what(hook->closure, __VA_ARGS__); \
228 pthread_rwlock_unlock(&rwlock);
231 void afb_hook_xreq_begin(const struct afb_xreq *xreq)
233 _HOOK_XREQ_(begin, xreq);
236 void afb_hook_xreq_end(const struct afb_xreq *xreq)
238 _HOOK_XREQ_(end, xreq);
241 struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj)
243 _HOOK_XREQ_(json, xreq, obj);
247 struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg)
249 _HOOK_XREQ_(get, xreq, name, arg);
253 void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info)
255 _HOOK_XREQ_(success, xreq, obj, info);
258 void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info)
260 _HOOK_XREQ_(fail, xreq, status, info);
263 const char *afb_hook_xreq_raw(const struct afb_xreq *xreq, const char *buffer, size_t size)
265 _HOOK_XREQ_(raw, xreq, buffer, size);
269 void afb_hook_xreq_send(const struct afb_xreq *xreq, const char *buffer, size_t size)
271 _HOOK_XREQ_(send, xreq, buffer, size);
274 void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value)
276 _HOOK_XREQ_(context_get, xreq, value);
280 void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*))
282 _HOOK_XREQ_(context_set, xreq, value, free_value);
285 void afb_hook_xreq_addref(const struct afb_xreq *xreq)
287 _HOOK_XREQ_(addref, xreq);
290 void afb_hook_xreq_unref(const struct afb_xreq *xreq)
292 _HOOK_XREQ_(unref, xreq);
295 void afb_hook_xreq_session_close(const struct afb_xreq *xreq)
297 _HOOK_XREQ_(session_close, xreq);
300 int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result)
302 _HOOK_XREQ_(session_set_LOA, xreq, level, result);
306 int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
308 _HOOK_XREQ_(subscribe, xreq, event, result);
312 int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event event, int result)
314 _HOOK_XREQ_(unsubscribe, xreq, event, result);
318 void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
320 _HOOK_XREQ_(subcall, xreq, api, verb, args);
323 void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result)
325 _HOOK_XREQ_(subcall_result, xreq, status, result);
328 void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args)
330 _HOOK_XREQ_(subcallsync, xreq, api, verb, args);
333 int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result)
335 _HOOK_XREQ_(subcallsync_result, xreq, status, result);
339 /******************************************************************************
341 *****************************************************************************/
343 void afb_hook_init_xreq(struct afb_xreq *xreq)
349 struct afb_hook *hook;
351 /* scan hook list to get the expected flags */
353 pthread_rwlock_rdlock(&rwlock);
354 hook = list_of_hooks;
356 f = hook->flags & afb_hook_flags_req_all;
358 && (!hook->session || hook->session == xreq->context.session)
359 && (!hook->api || !strcasecmp(hook->api, xreq->api))
360 && (!hook->verb || !strcasecmp(hook->verb, xreq->verb));
365 pthread_rwlock_unlock(&rwlock);
367 /* store the hooking data */
368 xreq->hookflags = flags;
370 pthread_rwlock_wrlock(&rwlock);
373 xreq->hookindex = reqindex;
374 pthread_rwlock_unlock(&rwlock);
378 struct afb_hook *afb_hook_xreq_create(const char *api, const char *verb, struct afb_session *session, unsigned flags, struct afb_hook_xreq_itf *itf, void *closure)
380 struct afb_hook *hook;
382 /* alloc the result */
383 hook = malloc(sizeof *hook);
387 /* get a copy of the names */
388 hook->api = api ? strdup(api) : NULL;
389 hook->verb = verb ? strdup(verb) : NULL;
390 if ((api && !hook->api) || (verb && !hook->verb)) {
397 /* initialise the rest */
398 hook->session = session;
400 afb_session_addref(session);
403 hook->reqitf = itf ? itf : &hook_xreq_default_itf;
404 hook->closure = closure;
406 /* record the hook */
407 pthread_rwlock_wrlock(&rwlock);
408 hook->next = list_of_hooks;
409 list_of_hooks = hook;
410 pthread_rwlock_unlock(&rwlock);
416 struct afb_hook *afb_hook_addref(struct afb_hook *hook)
418 pthread_rwlock_wrlock(&rwlock);
420 pthread_rwlock_unlock(&rwlock);
424 void afb_hook_unref(struct afb_hook *hook)
426 struct afb_hook **prv;
429 pthread_rwlock_wrlock(&rwlock);
430 if (--hook->refcount)
434 prv = &list_of_hooks;
435 while (*prv && *prv != hook)
440 pthread_rwlock_unlock(&rwlock);
446 afb_session_unref(hook->session);