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