7122a33d21428d12189898fad1fdfee17e0a6c33
[src/app-framework-binder.git] / src / afb-evt.c
1 /*
2  * Copyright (C) 2015-2019 "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 <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <pthread.h>
25
26 #include <json-c/json.h>
27 #include <afb/afb-event-x2-itf.h>
28 #include <afb/afb-event-x1.h>
29
30 #include "afb-evt.h"
31 #include "afb-hook.h"
32 #include "verbose.h"
33 #include "jobs.h"
34 #include "uuid.h"
35
36 struct afb_evt_watch;
37
38 /*
39  * Structure for event listeners
40  */
41 struct afb_evt_listener {
42
43         /* chaining listeners */
44         struct afb_evt_listener *next;
45
46         /* interface for callbacks */
47         const struct afb_evt_itf *itf;
48
49         /* closure for the callback */
50         void *closure;
51
52         /* head of the list of events listened */
53         struct afb_evt_watch *watchs;
54
55         /* rwlock of the listener */
56         pthread_rwlock_t rwlock;
57
58         /* count of reference to the listener */
59         uint16_t refcount;
60 };
61
62 /*
63  * Structure for describing events
64  */
65 struct afb_evtid {
66
67         /* interface */
68         struct afb_event_x2 eventid;
69
70         /* next event */
71         struct afb_evtid *next;
72
73         /* head of the list of listeners watching the event */
74         struct afb_evt_watch *watchs;
75
76         /* rwlock of the event */
77         pthread_rwlock_t rwlock;
78
79 #if WITH_AFB_HOOK
80         /* hooking */
81         int hookflags;
82 #endif
83
84         /* refcount */
85         uint16_t refcount;
86
87         /* id of the event */
88         uint16_t id;
89
90         /* fullname of the event */
91         char fullname[];
92 };
93
94 /*
95  * Structure for associating events and listeners
96  */
97 struct afb_evt_watch {
98
99         /* the evtid */
100         struct afb_evtid *evtid;
101
102         /* link to the next watcher for the same evtid */
103         struct afb_evt_watch *next_by_evtid;
104
105         /* the listener */
106         struct afb_evt_listener *listener;
107
108         /* link to the next watcher for the same listener */
109         struct afb_evt_watch *next_by_listener;
110 };
111
112 /*
113  * structure for job of broadcasting events
114  */
115 struct job_broadcast
116 {
117         /** object atached to the event */
118         struct json_object *object;
119
120         /** the uuid of the event */
121         uuid_binary_t  uuid;
122
123         /** remaining hop */
124         uint8_t hop;
125
126         /** name of the event to broadcast */
127         char event[];
128 };
129
130 /*
131  * structure for job of broadcasting or pushing events
132  */
133 struct job_evtid
134 {
135         /** the event to broadcast */
136         struct afb_evtid *evtid;
137
138         /** object atached to the event */
139         struct json_object *object;
140 };
141
142 /* the interface for events */
143 static struct afb_event_x2_itf afb_evt_event_x2_itf = {
144         .broadcast = (void*)afb_evt_evtid_broadcast,
145         .push = (void*)afb_evt_evtid_push,
146         .unref = (void*)afb_evt_evtid_unref,
147         .name = (void*)afb_evt_evtid_name,
148         .addref = (void*)afb_evt_evtid_addref
149 };
150
151 #if WITH_AFB_HOOK
152 /* the interface for events */
153 static struct afb_event_x2_itf afb_evt_hooked_event_x2_itf = {
154         .broadcast = (void*)afb_evt_evtid_hooked_broadcast,
155         .push = (void*)afb_evt_evtid_hooked_push,
156         .unref = (void*)afb_evt_evtid_hooked_unref,
157         .name = (void*)afb_evt_evtid_hooked_name,
158         .addref = (void*)afb_evt_evtid_hooked_addref
159 };
160 #endif
161
162 /* job groups for events push/broadcast */
163 #define BROADCAST_JOB_GROUP  (&afb_evt_event_x2_itf)
164 #define PUSH_JOB_GROUP       (&afb_evt_event_x2_itf)
165
166 /* head of the list of listeners */
167 static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER;
168 static struct afb_evt_listener *listeners = NULL;
169
170 /* handling id of events */
171 static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER;
172 static struct afb_evtid *evtids = NULL;
173 static uint16_t event_genid = 0;
174 static uint16_t event_count = 0;
175
176 /* head of uniqueness of events */
177 #if !defined(EVENT_BROADCAST_HOP_MAX)
178 #  define EVENT_BROADCAST_HOP_MAX  10
179 #endif
180 #if !defined(EVENT_BROADCAST_MEMORY_COUNT)
181 #  define EVENT_BROADCAST_MEMORY_COUNT  8
182 #endif
183
184 #if EVENT_BROADCAST_MEMORY_COUNT
185 static struct {
186         pthread_mutex_t mutex;
187         uint8_t base;
188         uint8_t count;
189         uuid_binary_t uuids[EVENT_BROADCAST_MEMORY_COUNT];
190 } uniqueness = {
191         .mutex = PTHREAD_MUTEX_INITIALIZER,
192         .base = 0,
193         .count = 0
194 };
195 #endif
196
197 /*
198  * Create structure for job of broadcasting string 'event' with 'object'
199  * Returns the created structure or NULL if out of memory
200  */
201 static struct job_broadcast *make_job_broadcast(const char *event, struct json_object *object, const uuid_binary_t uuid, uint8_t hop)
202 {
203         size_t sz = 1 + strlen(event);
204         struct job_broadcast *jb = malloc(sz + sizeof *jb);
205         if (jb) {
206                 jb->object = object;
207                 memcpy(jb->uuid, uuid, sizeof jb->uuid);
208                 jb->hop = hop;
209                 memcpy(jb->event, event, sz);
210         }
211         return jb;
212 }
213
214 /*
215  * Destroy structure 'jb' for job of broadcasting string events
216  */
217 static void destroy_job_broadcast(struct job_broadcast *jb)
218 {
219         json_object_put(jb->object);
220         free(jb);
221 }
222
223 /*
224  * Create structure for job of broadcasting or pushing 'evtid' with 'object'
225  * Returns the created structure or NULL if out of memory
226  */
227 static struct job_evtid *make_job_evtid(struct afb_evtid *evtid, struct json_object *object)
228 {
229         struct job_evtid *je = malloc(sizeof *je);
230         if (je) {
231                 je->evtid = afb_evt_evtid_addref(evtid);
232                 je->object = object;
233         }
234         return je;
235 }
236
237 /*
238  * Destroy structure for job of broadcasting or pushing evtid
239  */
240 static void destroy_job_evtid(struct job_evtid *je)
241 {
242         afb_evt_evtid_unref(je->evtid);
243         json_object_put(je->object);
244         free(je);
245 }
246
247 /*
248  * Broadcasts the 'event' of 'id' with its 'object'
249  */
250 static void broadcast(struct job_broadcast *jb)
251 {
252         struct afb_evt_listener *listener;
253
254         pthread_rwlock_rdlock(&listeners_rwlock);
255         listener = listeners;
256         while(listener) {
257                 if (listener->itf->broadcast != NULL)
258                         listener->itf->broadcast(listener->closure, jb->event, json_object_get(jb->object), jb->uuid, jb->hop);
259                 listener = listener->next;
260         }
261         pthread_rwlock_unlock(&listeners_rwlock);
262 }
263
264 /*
265  * Jobs callback for broadcasting string asynchronously
266  */
267 static void broadcast_job(int signum, void *closure)
268 {
269         struct job_broadcast *jb = closure;
270
271         if (signum == 0)
272                 broadcast(jb);
273         destroy_job_broadcast(jb);
274 }
275
276 /*
277  * Broadcasts the string 'event' with its 'object'
278  */
279 static int unhooked_broadcast(const char *event, struct json_object *object, const uuid_binary_t uuid, uint8_t hop)
280 {
281         uuid_binary_t local_uuid;
282         struct job_broadcast *jb;
283         int rc;
284 #if EVENT_BROADCAST_MEMORY_COUNT
285         int iter, count;
286 #endif
287
288         /* check if lately sent */
289         if (!uuid) {
290                 uuid_new_binary(local_uuid);
291                 uuid = local_uuid;
292                 hop = EVENT_BROADCAST_HOP_MAX;
293 #if EVENT_BROADCAST_MEMORY_COUNT
294                 pthread_mutex_lock(&uniqueness.mutex);
295         } else {
296                 pthread_mutex_lock(&uniqueness.mutex);
297                 iter = (int)uniqueness.base;
298                 count = (int)uniqueness.count;
299                 while (count) {
300                         if (0 == memcmp(uuid, uniqueness.uuids[iter], sizeof(uuid_binary_t))) {
301                                 pthread_mutex_unlock(&uniqueness.mutex);
302                                 return 0;
303                         }
304                         if (++iter == EVENT_BROADCAST_MEMORY_COUNT)
305                                 iter = 0;
306                         count--;
307                 }
308         }
309         iter = (int)uniqueness.base;
310         if (uniqueness.count < EVENT_BROADCAST_MEMORY_COUNT)
311                 iter += (int)(uniqueness.count++);
312         else if (++uniqueness.base == EVENT_BROADCAST_MEMORY_COUNT)
313                 uniqueness.base = 0;
314         memcpy(uniqueness.uuids[iter], uuid, sizeof(uuid_binary_t));
315         pthread_mutex_unlock(&uniqueness.mutex);
316 #else
317         }
318 #endif
319
320         /* create the structure for the job */
321         jb = make_job_broadcast(event, object, uuid, hop);
322         if (jb == NULL) {
323                 ERROR("Cant't create broadcast string job item for %s(%s)",
324                         event, json_object_to_json_string(object));
325                 json_object_put(object);
326                 return -1;
327         }
328
329         /* queue the job */
330         rc = jobs_queue(BROADCAST_JOB_GROUP, 0, broadcast_job, jb);
331         if (rc) {
332                 ERROR("cant't queue broadcast string job item for %s(%s)",
333                         event, json_object_to_json_string(object));
334                 destroy_job_broadcast(jb);
335         }
336         return rc;
337 }
338
339 /*
340  * Broadcasts the event 'evtid' with its 'object'
341  * 'object' is released (like json_object_put)
342  * Returns the count of listener that received the event.
343  */
344 int afb_evt_evtid_broadcast(struct afb_evtid *evtid, struct json_object *object)
345 {
346         return unhooked_broadcast(evtid->fullname, object, NULL, 0);
347 }
348
349 #if WITH_AFB_HOOK
350 /*
351  * Broadcasts the event 'evtid' with its 'object'
352  * 'object' is released (like json_object_put)
353  * Returns the count of listener that received the event.
354  */
355 int afb_evt_evtid_hooked_broadcast(struct afb_evtid *evtid, struct json_object *object)
356 {
357         int result;
358
359         json_object_get(object);
360
361         if (evtid->hookflags & afb_hook_flag_evt_broadcast_before)
362                 afb_hook_evt_broadcast_before(evtid->fullname, evtid->id, object);
363
364         result = afb_evt_evtid_broadcast(evtid, object);
365
366         if (evtid->hookflags & afb_hook_flag_evt_broadcast_after)
367                 afb_hook_evt_broadcast_after(evtid->fullname, evtid->id, object, result);
368
369         json_object_put(object);
370
371         return result;
372 }
373 #endif
374
375 int afb_evt_rebroadcast(const char *event, struct json_object *object, const uuid_binary_t uuid, uint8_t hop)
376 {
377         int result;
378
379 #if WITH_AFB_HOOK
380         json_object_get(object);
381         afb_hook_evt_broadcast_before(event, 0, object);
382 #endif
383
384         result = unhooked_broadcast(event, object, uuid, hop);
385
386 #if WITH_AFB_HOOK
387         afb_hook_evt_broadcast_after(event, 0, object, result);
388         json_object_put(object);
389 #endif
390         return result;
391 }
392
393 /*
394  * Broadcasts the 'event' with its 'object'
395  * 'object' is released (like json_object_put)
396  * Returns the count of listener having receive the event.
397  */
398 int afb_evt_broadcast(const char *event, struct json_object *object)
399 {
400         return afb_evt_rebroadcast(event, object, NULL, 0);
401 }
402
403 /*
404  * Pushes the event 'evtid' with 'obj' to its listeners
405  * Returns the count of listener that received the event.
406  */
407 static void push_evtid(struct afb_evtid *evtid, struct json_object *object)
408 {
409         struct afb_evt_watch *watch;
410         struct afb_evt_listener *listener;
411
412         pthread_rwlock_rdlock(&evtid->rwlock);
413         watch = evtid->watchs;
414         while(watch) {
415                 listener = watch->listener;
416                 assert(listener->itf->push != NULL);
417                 listener->itf->push(listener->closure, evtid->fullname, evtid->id, json_object_get(object));
418                 watch = watch->next_by_evtid;
419         }
420         pthread_rwlock_unlock(&evtid->rwlock);
421 }
422
423 /*
424  * Jobs callback for pushing evtid asynchronously
425  */
426 static void push_job_evtid(int signum, void *closure)
427 {
428         struct job_evtid *je = closure;
429
430         if (signum == 0)
431                 push_evtid(je->evtid, je->object);
432         destroy_job_evtid(je);
433 }
434
435 /*
436  * Pushes the event 'evtid' with 'obj' to its listeners
437  * 'obj' is released (like json_object_put)
438  * Returns 1 if at least one listener exists or 0 if no listener exists or
439  * -1 in case of error and the event can't be delivered
440  */
441 int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *object)
442 {
443         struct job_evtid *je;
444         int rc;
445
446         if (!evtid->watchs)
447                 return 0;
448
449         je = make_job_evtid(evtid, object);
450         if (je == NULL) {
451                 ERROR("Cant't create push evtid job item for %s(%s)",
452                         evtid->fullname, json_object_to_json_string(object));
453                 json_object_put(object);
454                 return -1;
455         }
456
457         rc = jobs_queue(PUSH_JOB_GROUP, 0, push_job_evtid, je);
458         if (rc == 0)
459                 rc = 1;
460         else {
461                 ERROR("cant't queue push evtid job item for %s(%s)",
462                         evtid->fullname, json_object_to_json_string(object));
463                 destroy_job_evtid(je);
464         }
465
466         return rc;
467 }
468
469 #if WITH_AFB_HOOK
470 /*
471  * Pushes the event 'evtid' with 'obj' to its listeners
472  * 'obj' is released (like json_object_put)
473  * Emits calls to hooks.
474  * Returns the count of listener taht received the event.
475  */
476 int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj)
477 {
478
479         int result;
480
481         /* lease the object */
482         json_object_get(obj);
483
484         /* hook before push */
485         if (evtid->hookflags & afb_hook_flag_evt_push_before)
486                 afb_hook_evt_push_before(evtid->fullname, evtid->id, obj);
487
488         /* push */
489         result = afb_evt_evtid_push(evtid, obj);
490
491         /* hook after push */
492         if (evtid->hookflags & afb_hook_flag_evt_push_after)
493                 afb_hook_evt_push_after(evtid->fullname, evtid->id, obj, result);
494
495         /* release the object */
496         json_object_put(obj);
497         return result;
498 }
499 #endif
500
501 static void unwatch(struct afb_evt_listener *listener, struct afb_evtid *evtid, int remove)
502 {
503         /* notify listener if needed */
504         if (remove && listener->itf->remove != NULL)
505                 listener->itf->remove(listener->closure, evtid->fullname, evtid->id);
506 }
507
508 static void evtid_unwatch(struct afb_evtid *evtid, struct afb_evt_listener *listener, struct afb_evt_watch *watch, int remove)
509 {
510         struct afb_evt_watch **prv;
511
512         /* notify listener if needed */
513         unwatch(listener, evtid, remove);
514
515         /* unlink the watch for its event */
516         pthread_rwlock_wrlock(&listener->rwlock);
517         prv = &listener->watchs;
518         while(*prv) {
519                 if (*prv == watch) {
520                         *prv = watch->next_by_listener;
521                         break;
522                 }
523                 prv = &(*prv)->next_by_listener;
524         }
525         pthread_rwlock_unlock(&listener->rwlock);
526
527         /* recycle memory */
528         free(watch);
529 }
530
531 static void listener_unwatch(struct afb_evt_listener *listener, struct afb_evtid *evtid, struct afb_evt_watch *watch, int remove)
532 {
533         struct afb_evt_watch **prv;
534
535         /* notify listener if needed */
536         unwatch(listener, evtid, remove);
537
538         /* unlink the watch for its event */
539         pthread_rwlock_wrlock(&evtid->rwlock);
540         prv = &evtid->watchs;
541         while(*prv) {
542                 if (*prv == watch) {
543                         *prv = watch->next_by_evtid;
544                         break;
545                 }
546                 prv = &(*prv)->next_by_evtid;
547         }
548         pthread_rwlock_unlock(&evtid->rwlock);
549
550         /* recycle memory */
551         free(watch);
552 }
553
554 /*
555  * Creates an event of name 'fullname' and returns it or NULL on error.
556  */
557 struct afb_evtid *afb_evt_evtid_create(const char *fullname)
558 {
559         size_t len;
560         struct afb_evtid *evtid, *oevt;
561         uint16_t id;
562
563         /* allocates the event */
564         len = strlen(fullname);
565         evtid = malloc(len + 1 + sizeof * evtid);
566         if (evtid == NULL)
567                 goto error;
568
569         /* allocates the id */
570         pthread_rwlock_wrlock(&events_rwlock);
571         if (event_count == UINT16_MAX) {
572                 pthread_rwlock_unlock(&events_rwlock);
573                 free(evtid);
574                 ERROR("Can't create more events");
575                 return NULL;
576         }
577         event_count++;
578         do {
579                 /* TODO add a guard (counting number of event created) */
580                 id = ++event_genid;
581                 if (!id)
582                         id = event_genid = 1;
583                 oevt = evtids;
584                 while(oevt != NULL && oevt->id != id)
585                         oevt = oevt->next;
586         } while (oevt != NULL);
587
588         /* initialize the event */
589         memcpy(evtid->fullname, fullname, len + 1);
590         evtid->next = evtids;
591         evtid->refcount = 1;
592         evtid->watchs = NULL;
593         evtid->id = id;
594         pthread_rwlock_init(&evtid->rwlock, NULL);
595         evtids = evtid;
596 #if WITH_AFB_HOOK
597         evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
598         evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
599         if (evtid->hookflags & afb_hook_flag_evt_create)
600                 afb_hook_evt_create(evtid->fullname, evtid->id);
601 #else
602         evtid->eventid.itf = &afb_evt_event_x2_itf;
603 #endif
604         pthread_rwlock_unlock(&events_rwlock);
605
606         /* returns the event */
607         return evtid;
608 error:
609         return NULL;
610 }
611
612 /*
613  * Creates an event of name 'prefix'/'name' and returns it or NULL on error.
614  */
615 struct afb_evtid *afb_evt_evtid_create2(const char *prefix, const char *name)
616 {
617         size_t prelen, postlen;
618         char *fullname;
619
620         /* makes the event fullname */
621         prelen = strlen(prefix);
622         postlen = strlen(name);
623         fullname = alloca(prelen + postlen + 2);
624         memcpy(fullname, prefix, prelen);
625         fullname[prelen] = '/';
626         memcpy(fullname + prelen + 1, name, postlen + 1);
627
628         /* create the event */
629         return afb_evt_evtid_create(fullname);
630 }
631
632 /*
633  * increment the reference count of the event 'evtid'
634  */
635 struct afb_evtid *afb_evt_evtid_addref(struct afb_evtid *evtid)
636 {
637         __atomic_add_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED);
638         return evtid;
639 }
640
641 #if WITH_AFB_HOOK
642 /*
643  * increment the reference count of the event 'evtid'
644  */
645 struct afb_evtid *afb_evt_evtid_hooked_addref(struct afb_evtid *evtid)
646 {
647         if (evtid->hookflags & afb_hook_flag_evt_addref)
648                 afb_hook_evt_addref(evtid->fullname, evtid->id);
649         return afb_evt_evtid_addref(evtid);
650 }
651 #endif
652
653 /*
654  * decrement the reference count of the event 'evtid'
655  * and destroy it when the count reachs zero
656  */
657 void afb_evt_evtid_unref(struct afb_evtid *evtid)
658 {
659         struct afb_evtid **prv, *oev;
660         struct afb_evt_watch *watch, *nwatch;
661
662         if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) {
663                 /* unlinks the event if valid! */
664                 pthread_rwlock_wrlock(&events_rwlock);
665                 prv = &evtids;
666                 for(;;) {
667                         oev = *prv;
668                         if (oev == evtid)
669                                 break;
670                         if (!oev) {
671                                 ERROR("unexpected event");
672                                 pthread_rwlock_unlock(&events_rwlock);
673                                 return;
674                         }
675                         prv = &oev->next;
676                 }
677                 event_count--;
678                 *prv = evtid->next;
679                 pthread_rwlock_unlock(&events_rwlock);
680
681                 /* removes all watchers */
682                 pthread_rwlock_wrlock(&evtid->rwlock);
683                 watch = evtid->watchs;
684                 evtid->watchs = NULL;
685                 pthread_rwlock_unlock(&evtid->rwlock);
686                 while(watch) {
687                         nwatch = watch->next_by_evtid;
688                         evtid_unwatch(evtid, watch->listener, watch, 1);
689                         watch = nwatch;
690                 }
691
692                 /* free */
693                 pthread_rwlock_destroy(&evtid->rwlock);
694                 free(evtid);
695         }
696 }
697
698 #if WITH_AFB_HOOK
699 /*
700  * decrement the reference count of the event 'evtid'
701  * and destroy it when the count reachs zero
702  */
703 void afb_evt_evtid_hooked_unref(struct afb_evtid *evtid)
704 {
705         if (evtid->hookflags & afb_hook_flag_evt_unref)
706                 afb_hook_evt_unref(evtid->fullname, evtid->id);
707         afb_evt_evtid_unref(evtid);
708 }
709 #endif
710
711 /*
712  * Returns the true name of the 'event'
713  */
714 const char *afb_evt_evtid_fullname(struct afb_evtid *evtid)
715 {
716         return evtid->fullname;
717 }
718
719 /*
720  * Returns the name of the 'event'
721  */
722 const char *afb_evt_evtid_name(struct afb_evtid *evtid)
723 {
724         const char *name = strchr(evtid->fullname, '/');
725         return name ? name + 1 : evtid->fullname;
726 }
727
728 #if WITH_AFB_HOOK
729 /*
730  * Returns the name associated to the event 'evtid'.
731  */
732 const char *afb_evt_evtid_hooked_name(struct afb_evtid *evtid)
733 {
734         const char *result = afb_evt_evtid_name(evtid);
735         if (evtid->hookflags & afb_hook_flag_evt_name)
736                 afb_hook_evt_name(evtid->fullname, evtid->id, result);
737         return result;
738 }
739 #endif
740
741 /*
742  * Returns the id of the 'event'
743  */
744 uint16_t afb_evt_evtid_id(struct afb_evtid *evtid)
745 {
746         return evtid->id;
747 }
748
749 /*
750  * Returns an instance of the listener defined by the 'send' callback
751  * and the 'closure'.
752  * Returns NULL in case of memory depletion.
753  */
754 struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, void *closure)
755 {
756         struct afb_evt_listener *listener;
757
758         /* search if an instance already exists */
759         pthread_rwlock_wrlock(&listeners_rwlock);
760         listener = listeners;
761         while (listener != NULL) {
762                 if (listener->itf == itf && listener->closure == closure) {
763                         listener = afb_evt_listener_addref(listener);
764                         goto found;
765                 }
766                 listener = listener->next;
767         }
768
769         /* allocates */
770         listener = calloc(1, sizeof *listener);
771         if (listener != NULL) {
772                 /* init */
773                 listener->itf = itf;
774                 listener->closure = closure;
775                 listener->watchs = NULL;
776                 listener->refcount = 1;
777                 pthread_rwlock_init(&listener->rwlock, NULL);
778                 listener->next = listeners;
779                 listeners = listener;
780         }
781  found:
782         pthread_rwlock_unlock(&listeners_rwlock);
783         return listener;
784 }
785
786 /*
787  * Increases the reference count of 'listener' and returns it
788  */
789 struct afb_evt_listener *afb_evt_listener_addref(struct afb_evt_listener *listener)
790 {
791         __atomic_add_fetch(&listener->refcount, 1, __ATOMIC_RELAXED);
792         return listener;
793 }
794
795 /*
796  * Decreases the reference count of the 'listener' and destroys it
797  * when no more used.
798  */
799 void afb_evt_listener_unref(struct afb_evt_listener *listener)
800 {
801         struct afb_evt_listener **prv, *olis;
802
803         if (listener && !__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) {
804
805                 /* unlink the listener */
806                 pthread_rwlock_wrlock(&listeners_rwlock);
807                 prv = &listeners;
808                 for(;;) {
809                         olis = *prv;
810                         if (olis == listener)
811                                 break;
812                         if (!olis) {
813                                 ERROR("unexpected listener");
814                                 pthread_rwlock_unlock(&listeners_rwlock);
815                                 return;
816                         }
817                         prv = &olis->next;
818                 }
819                 *prv = listener->next;
820                 pthread_rwlock_unlock(&listeners_rwlock);
821
822                 /* remove the watchers */
823                 afb_evt_listener_unwatch_all(listener, 0);
824
825                 /* free the listener */
826                 pthread_rwlock_destroy(&listener->rwlock);
827                 free(listener);
828         }
829 }
830
831 /*
832  * Makes the 'listener' watching 'evtid'
833  * Returns 0 in case of success or else -1.
834  */
835 int afb_evt_listener_watch_evt(struct afb_evt_listener *listener, struct afb_evtid *evtid)
836 {
837         struct afb_evt_watch *watch;
838
839         /* check parameter */
840         if (listener->itf->push == NULL) {
841                 errno = EINVAL;
842                 return -1;
843         }
844
845         /* search the existing watch for the listener */
846         pthread_rwlock_wrlock(&listener->rwlock);
847         watch = listener->watchs;
848         while(watch != NULL) {
849                 if (watch->evtid == evtid)
850                         goto end;
851                 watch = watch->next_by_listener;
852         }
853
854         /* not found, allocate a new */
855         watch = malloc(sizeof *watch);
856         if (watch == NULL) {
857                 pthread_rwlock_unlock(&listener->rwlock);
858                 errno = ENOMEM;
859                 return -1;
860         }
861
862         /* initialise and link */
863         watch->evtid = evtid;
864         watch->listener = listener;
865         watch->next_by_listener = listener->watchs;
866         listener->watchs = watch;
867         pthread_rwlock_wrlock(&evtid->rwlock);
868         watch->next_by_evtid = evtid->watchs;
869         evtid->watchs = watch;
870         pthread_rwlock_unlock(&evtid->rwlock);
871
872         if (listener->itf->add != NULL)
873                 listener->itf->add(listener->closure, evtid->fullname, evtid->id);
874 end:
875         pthread_rwlock_unlock(&listener->rwlock);
876         return 0;
877 }
878
879 /*
880  * Avoids the 'listener' to watch 'evtid'
881  * Returns 0 in case of success or else -1.
882  */
883 int afb_evt_listener_unwatch_evt(struct afb_evt_listener *listener, struct afb_evtid *evtid)
884 {
885         struct afb_evt_watch *watch, **pwatch;
886
887         /* search the existing watch */
888         pthread_rwlock_wrlock(&listener->rwlock);
889         pwatch = &listener->watchs;
890         for (;;) {
891                 watch = *pwatch;
892                 if (!watch) {
893                         pthread_rwlock_unlock(&listener->rwlock);
894                         errno = ENOENT;
895                         return -1;
896                 }
897                 if (evtid == watch->evtid) {
898                         *pwatch = watch->next_by_listener;
899                         pthread_rwlock_unlock(&listener->rwlock);
900                         listener_unwatch(listener, evtid, watch, 1);
901                         return 0;
902                 }
903                 pwatch = &watch->next_by_listener;
904         }
905 }
906
907 /*
908  * Avoids the 'listener' to watch 'eventid'
909  * Returns 0 in case of success or else -1.
910  */
911 int afb_evt_listener_unwatch_id(struct afb_evt_listener *listener, uint16_t eventid)
912 {
913         struct afb_evt_watch *watch, **pwatch;
914         struct afb_evtid *evtid;
915
916         /* search the existing watch */
917         pthread_rwlock_wrlock(&listener->rwlock);
918         pwatch = &listener->watchs;
919         for (;;) {
920                 watch = *pwatch;
921                 if (!watch) {
922                         pthread_rwlock_unlock(&listener->rwlock);
923                         errno = ENOENT;
924                         return -1;
925                 }
926                 evtid = watch->evtid;
927                 if (evtid->id == eventid) {
928                         *pwatch = watch->next_by_listener;
929                         pthread_rwlock_unlock(&listener->rwlock);
930                         listener_unwatch(listener, evtid, watch, 1);
931                         return 0;
932                 }
933                 pwatch = &watch->next_by_listener;
934         }
935 }
936
937 /*
938  * Avoids the 'listener' to watch any event, calling the callback
939  * 'remove' of the interface if 'remoe' is not zero.
940  */
941 void afb_evt_listener_unwatch_all(struct afb_evt_listener *listener, int remove)
942 {
943         struct afb_evt_watch *watch, *nwatch;
944
945         /* search the existing watch */
946         pthread_rwlock_wrlock(&listener->rwlock);
947         watch = listener->watchs;
948         listener->watchs = NULL;
949         pthread_rwlock_unlock(&listener->rwlock);
950         while(watch) {
951                 nwatch = watch->next_by_listener;
952                 listener_unwatch(listener, watch->evtid, watch, remove);
953                 watch = nwatch;
954         }
955 }
956
957 #if WITH_AFB_HOOK
958 /*
959  * update the hooks for events
960  */
961 void afb_evt_update_hooks()
962 {
963         struct afb_evtid *evtid;
964
965         pthread_rwlock_rdlock(&events_rwlock);
966         for (evtid = evtids ; evtid ; evtid = evtid->next) {
967                 evtid->hookflags = afb_hook_flags_evt(evtid->fullname);
968                 evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_event_x2_itf : &afb_evt_event_x2_itf;
969         }
970         pthread_rwlock_unlock(&events_rwlock);
971 }
972 #endif
973
974 inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid)
975 {
976         return (struct afb_evtid*)eventid;
977 }
978
979 inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid)
980 {
981         return &evtid->eventid;
982 }
983
984 /*
985  * Creates an event of 'fullname' and returns it.
986  * Returns an event with closure==NULL in case of error.
987  */
988 struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname)
989 {
990         return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname));
991 }
992
993 /*
994  * Creates an event of name 'prefix'/'name' and returns it.
995  * Returns an event with closure==NULL in case of error.
996  */
997 struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name)
998 {
999         return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name));
1000 }
1001
1002 /*
1003  * Returns the fullname of the 'eventid'
1004  */
1005 const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid)
1006 {
1007         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1008         return evtid ? evtid->fullname : NULL;
1009 }
1010
1011 /*
1012  * Returns the id of the 'eventid'
1013  */
1014 uint16_t afb_evt_event_x2_id(struct afb_event_x2 *eventid)
1015 {
1016         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1017         return evtid ? evtid->id : 0;
1018 }
1019
1020 /*
1021  * Makes the 'listener' watching 'eventid'
1022  * Returns 0 in case of success or else -1.
1023  */
1024 int afb_evt_listener_watch_x2(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
1025 {
1026         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1027
1028         /* check parameter */
1029         if (!evtid) {
1030                 errno = EINVAL;
1031                 return -1;
1032         }
1033
1034         /* search the existing watch for the listener */
1035         return afb_evt_listener_watch_evt(listener, evtid);
1036 }
1037
1038 /*
1039  * Avoids the 'listener' to watch 'eventid'
1040  * Returns 0 in case of success or else -1.
1041  */
1042 int afb_evt_listener_unwatch_x2(struct afb_evt_listener *listener, struct afb_event_x2 *eventid)
1043 {
1044         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1045
1046         /* check parameter */
1047         if (!evtid) {
1048                 errno = EINVAL;
1049                 return -1;
1050         }
1051
1052         /* search the existing watch */
1053         return afb_evt_listener_unwatch_evt(listener, evtid);
1054 }
1055
1056 int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object)
1057 #if WITH_AFB_HOOK
1058 {
1059         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1060         if (evtid)
1061                 return afb_evt_evtid_hooked_push(evtid, object);
1062         json_object_put(object);
1063         return 0;
1064 }
1065 #else
1066         __attribute__((alias("afb_evt_event_x2_unhooked_push")));
1067 #endif
1068
1069 int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object)
1070 {
1071         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1072         if (evtid)
1073                 return afb_evt_evtid_push(evtid, object);
1074         json_object_put(object);
1075         return 0;
1076 }
1077
1078 #if WITH_LEGACY_BINDING_V1 || WITH_LEGACY_BINDING_V2
1079 struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid)
1080 {
1081         return evtid
1082 #if WITH_AFB_HOOK
1083                 ? (struct afb_event_x1){ .itf = &afb_evt_hooked_event_x2_itf, .closure = &evtid->eventid }
1084 #else
1085                 ? (struct afb_event_x1){ .itf = &afb_evt_event_x2_itf, .closure = &evtid->eventid }
1086 #endif
1087                 : (struct afb_event_x1){ .itf = NULL, .closure = NULL };
1088 }
1089 #endif
1090
1091 void afb_evt_event_x2_unref(struct afb_event_x2 *eventid)
1092 {
1093         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1094         if (evtid)
1095                 afb_evt_evtid_unref(evtid);
1096 }
1097
1098 struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid)
1099 {
1100         struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid);
1101         if (evtid)
1102                 afb_evt_evtid_addref(evtid);
1103         return eventid;
1104 }
1105