afb-export: prepare to eventid
[src/app-framework-binder.git] / src / afb-export.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author: José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include <json-c/json.h>
25
26 #include <afb/afb-binding-v1.h>
27 #include <afb/afb-binding-v2.h>
28
29 #include "afb-api.h"
30 #include "afb-apiset.h"
31 #include "afb-common.h"
32 #include "afb-cred.h"
33 #include "afb-evt.h"
34 #include "afb-export.h"
35 #include "afb-hook.h"
36 #include "afb-msg-json.h"
37 #include "afb-session.h"
38 #include "afb-xreq.h"
39 #include "jobs.h"
40 #include "verbose.h"
41
42
43 /*************************************************************************
44  * internal types and structures
45  ************************************************************************/
46
47 enum afb_api_version
48 {
49         Api_Version_None = 0,
50         Api_Version_1 = 1,
51         Api_Version_2 = 2,
52         Api_Version_3 = 3
53 };
54
55 enum afb_api_state
56 {
57         Api_State_Pre_Init,
58         Api_State_Init,
59         Api_State_Run
60 };
61
62 struct afb_export
63 {
64         /* name of the api */
65         char *apiname;
66
67         /* version of the api */
68         unsigned version: 4;
69
70         /* current state */
71         unsigned state: 4;
72
73         /* hooking flags */
74         int hookditf;
75         int hooksvc;
76
77         /* session for service */
78         struct afb_session *session;
79
80         /* apiset for service */
81         struct afb_apiset *apiset;
82
83         /* event listener for service or NULL */
84         struct afb_evt_listener *listener;
85
86         /* start function */
87         union {
88                 int (*v1)(struct afb_service);
89                 int (*v2)();
90         } init;
91
92         /* event handling */
93         union {
94                 void (*v12)(const char *event, struct json_object *object);
95         } on_event;
96
97         /* exported data */
98         union {
99                 struct afb_binding_interface_v1 v1;
100                 struct afb_binding_data_v2 *v2;
101         } export;
102 };
103
104 /*************************************************************************************************************
105  *************************************************************************************************************
106  *************************************************************************************************************
107  *************************************************************************************************************
108                                            F R O M     D I T F
109  *************************************************************************************************************
110  *************************************************************************************************************
111  *************************************************************************************************************
112  *************************************************************************************************************/
113
114 /**********************************************
115 * normal flow
116 **********************************************/
117 static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
118 {
119         char *p;
120         struct afb_export *export = closure;
121
122         if (!fmt || vasprintf(&p, fmt, args) < 0)
123                 vverbose(level, file, line, function, fmt, args);
124         else {
125                 verbose(level, file, line, function, "[API %s] %s", export->apiname, p);
126                 free(p);
127         }
128 }
129
130 static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
131 {
132         vverbose_cb(closure, level, file, line, NULL, fmt, args);
133 }
134
135 static struct afb_eventid *eventid_make_cb(void *closure, const char *name)
136 {
137         size_t plen, nlen;
138         char *event;
139         struct afb_export *export = closure;
140
141         /* check daemon state */
142         if (export->state == Api_State_Pre_Init) {
143                 ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name);
144                 errno = EINVAL;
145                 return NULL;
146         }
147
148         /* makes the event name */
149         plen = strlen(export->apiname);
150         nlen = strlen(name);
151         event = alloca(nlen + plen + 2);
152         memcpy(event, export->apiname, plen);
153         event[plen] = '/';
154         memcpy(event + plen + 1, name, nlen + 1);
155
156         /* create the event */
157         return afb_evt_create_event(event);
158 }
159
160 static struct afb_event event_make_cb(void *closure, const char *name)
161 {
162         struct afb_eventid *eventid = eventid_make_cb(closure, name);
163         return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid };
164 }
165
166 static int event_broadcast_cb(void *closure, const char *name, struct json_object *object)
167 {
168         size_t plen, nlen;
169         char *event;
170         struct afb_export *export = closure;
171
172         /* check daemon state */
173         if (export->state == Api_State_Pre_Init) {
174                 ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->apiname, name, json_object_to_json_string(object));
175                 errno = EINVAL;
176                 return 0;
177         }
178
179         /* makes the event name */
180         plen = strlen(export->apiname);
181         nlen = strlen(name);
182         event = alloca(nlen + plen + 2);
183         memcpy(event, export->apiname, plen);
184         event[plen] = '/';
185         memcpy(event + plen + 1, name, nlen + 1);
186
187         /* broadcast the event */
188         return afb_evt_broadcast(event, object);
189 }
190
191 static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
192 {
193         return afb_common_rootdir_open_locale(filename, flags, locale);
194 }
195
196 static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
197 {
198         return jobs_queue(group, timeout, callback, argument);
199 }
200
201 static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq)
202 {
203         return afb_xreq_unstore(sreq);
204 }
205
206 static int require_api_cb(void *closure, const char *name, int initialized)
207 {
208         struct afb_export *export = closure;
209         if (export->state != Api_State_Init) {
210                 ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized);
211                 errno = EINVAL;
212                 return -1;
213         }
214         return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1);
215 }
216
217 static int rename_api_cb(void *closure, const char *name)
218 {
219         struct afb_export *export = closure;
220         if (export->state != Api_State_Pre_Init) {
221                 ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name);
222                 errno = EINVAL;
223                 return -1;
224         }
225         if (!afb_api_is_valid_name(name)) {
226                 ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name);
227                 errno = EINVAL;
228                 return -1;
229         }
230         NOTICE("[API %s] renamed to [API %s]", export->apiname, name);
231         afb_export_rename(export, name);
232         return 0;
233 }
234
235 /**********************************************
236 * hooked flow
237 **********************************************/
238 static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
239 {
240         struct afb_export *export = closure;
241         va_list ap;
242         va_copy(ap, args);
243         vverbose_cb(closure, level, file, line, function, fmt, args);
244         afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap);
245         va_end(ap);
246 }
247
248 static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
249 {
250         hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args);
251 }
252
253 static struct afb_eventid *hooked_eventid_make_cb(void *closure, const char *name)
254 {
255         struct afb_export *export = closure;
256         struct afb_eventid *r = eventid_make_cb(closure, name);
257         afb_hook_ditf_event_make(export, name, r);
258         return r;
259 }
260
261 static struct afb_event hooked_event_make_cb(void *closure, const char *name)
262 {
263         struct afb_eventid *eventid = hooked_eventid_make_cb(closure, name);
264         return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid };
265 }
266
267 static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object)
268 {
269         int r;
270         struct afb_export *export = closure;
271         json_object_get(object);
272         afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object));
273         r = event_broadcast_cb(closure, name, object);
274         afb_hook_ditf_event_broadcast_after(export, name, object, r);
275         json_object_put(object);
276         return r;
277 }
278
279 static struct sd_event *hooked_get_event_loop(void *closure)
280 {
281         struct afb_export *export = closure;
282         struct sd_event *r = afb_common_get_event_loop();
283         return afb_hook_ditf_get_event_loop(export, r);
284 }
285
286 static struct sd_bus *hooked_get_user_bus(void *closure)
287 {
288         struct afb_export *export = closure;
289         struct sd_bus *r = afb_common_get_user_bus();
290         return afb_hook_ditf_get_user_bus(export, r);
291 }
292
293 static struct sd_bus *hooked_get_system_bus(void *closure)
294 {
295         struct afb_export *export = closure;
296         struct sd_bus *r = afb_common_get_system_bus();
297         return afb_hook_ditf_get_system_bus(export, r);
298 }
299
300 static int hooked_rootdir_get_fd(void *closure)
301 {
302         struct afb_export *export = closure;
303         int r = afb_common_rootdir_get_fd();
304         return afb_hook_ditf_rootdir_get_fd(export, r);
305 }
306
307 static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
308 {
309         struct afb_export *export = closure;
310         int r = rootdir_open_locale_cb(closure, filename, flags, locale);
311         return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r);
312 }
313
314 static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
315 {
316         struct afb_export *export = closure;
317         int r = queue_job_cb(closure, callback, argument, group, timeout);
318         return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r);
319 }
320
321 static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq)
322 {
323         struct afb_export *export = closure;
324         afb_hook_ditf_unstore_req(export, sreq);
325         return unstore_req_cb(closure, sreq);
326 }
327
328 static int hooked_require_api_cb(void *closure, const char *name, int initialized)
329 {
330         int result;
331         struct afb_export *export = closure;
332         afb_hook_ditf_require_api(export, name, initialized);
333         result = require_api_cb(closure, name, initialized);
334         return afb_hook_ditf_require_api_result(export, name, initialized, result);
335 }
336
337 static int hooked_rename_api_cb(void *closure, const char *name)
338 {
339         struct afb_export *export = closure;
340         const char *oldname = export->apiname;
341         int result = rename_api_cb(closure, name);
342         return afb_hook_ditf_rename_api(export, oldname, name, result);
343 }
344
345 /**********************************************
346 * vectors
347 **********************************************/
348 static const struct afb_daemon_itf daemon_itf = {
349         .vverbose_v1 = old_vverbose_cb,
350         .vverbose_v2 = vverbose_cb,
351         .event_make = event_make_cb,
352         .event_broadcast = event_broadcast_cb,
353         .get_event_loop = afb_common_get_event_loop,
354         .get_user_bus = afb_common_get_user_bus,
355         .get_system_bus = afb_common_get_system_bus,
356         .rootdir_get_fd = afb_common_rootdir_get_fd,
357         .rootdir_open_locale = rootdir_open_locale_cb,
358         .queue_job = queue_job_cb,
359         .unstore_req = unstore_req_cb,
360         .require_api = require_api_cb,
361         .rename_api = rename_api_cb
362 };
363
364 static const struct afb_daemon_itf hooked_daemon_itf = {
365         .vverbose_v1 = hooked_old_vverbose_cb,
366         .vverbose_v2 = hooked_vverbose_cb,
367         .event_make = hooked_event_make_cb,
368         .event_broadcast = hooked_event_broadcast_cb,
369         .get_event_loop = hooked_get_event_loop,
370         .get_user_bus = hooked_get_user_bus,
371         .get_system_bus = hooked_get_system_bus,
372         .rootdir_get_fd = hooked_rootdir_get_fd,
373         .rootdir_open_locale = hooked_rootdir_open_locale_cb,
374         .queue_job = hooked_queue_job_cb,
375         .unstore_req = hooked_unstore_req_cb,
376         .require_api = hooked_require_api_cb,
377         .rename_api = hooked_rename_api_cb
378 };
379
380
381 /*************************************************************************************************************
382  *************************************************************************************************************
383  *************************************************************************************************************
384  *************************************************************************************************************
385                                            F R O M     S V C
386  *************************************************************************************************************
387  *************************************************************************************************************
388  *************************************************************************************************************
389  *************************************************************************************************************/
390
391 /* the common session for services sharing their session */
392 static struct afb_session *common_session;
393
394 /*************************************************************************************************************
395  *************************************************************************************************************
396  *************************************************************************************************************
397  *************************************************************************************************************
398                                            F R O M     S V C
399  *************************************************************************************************************
400  *************************************************************************************************************
401  *************************************************************************************************************
402  *************************************************************************************************************/
403
404 /*
405  * Structure for requests initiated by the service
406  */
407 struct call_req
408 {
409         struct afb_xreq xreq;
410
411         struct afb_export *export;
412
413         /* the args */
414         void (*callback)(void*, int, struct json_object*);
415         void *closure;
416
417         /* sync */
418         struct jobloop *jobloop;
419         struct json_object *result;
420         int status;
421 };
422
423 /*
424  * destroys the call_req
425  */
426 static void callreq_destroy(struct afb_xreq *xreq)
427 {
428         struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
429
430         afb_context_disconnect(&callreq->xreq.context);
431         json_object_put(callreq->xreq.json);
432         afb_cred_unref(callreq->xreq.cred);
433         free(callreq);
434 }
435
436 static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj)
437 {
438         struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
439         if (callreq->callback)
440                 callreq->callback(callreq->closure, status, obj);
441         json_object_put(obj);
442 }
443
444 static void callreq_sync_leave(struct call_req *callreq)
445 {
446         struct jobloop *jobloop = callreq->jobloop;
447
448         if (jobloop) {
449                 callreq->jobloop = NULL;
450                 jobs_leave(jobloop);
451         }
452 }
453
454 static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj)
455 {
456         struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq);
457         callreq->status = status;
458         callreq->result = obj;
459         callreq_sync_leave(callreq);
460 }
461
462 static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
463 {
464         struct call_req *callreq = closure;
465
466         if (!signum) {
467                 callreq->jobloop = jobloop;
468                 afb_xreq_process(&callreq->xreq, callreq->export->apiset);
469         } else {
470                 callreq->result = afb_msg_json_internal_error();
471                 callreq->status = -1;
472                 callreq_sync_leave(callreq);
473         }
474 }
475
476 /* interface for requests of services */
477 const struct afb_xreq_query_itf afb_export_xreq_itf = {
478         .unref = callreq_destroy,
479         .reply = callreq_reply
480 };
481
482 /* interface for requests of services */
483 const struct afb_xreq_query_itf afb_export_xreq_sync_itf = {
484         .unref = callreq_destroy,
485         .reply = callreq_reply_sync
486 };
487
488 /*
489  * create an call_req
490  */
491 static struct call_req *callreq_create(struct afb_export *export, const char *api, const char *verb, struct json_object *args, const struct afb_xreq_query_itf *itf)
492 {
493         struct call_req *callreq;
494         size_t lenapi, lenverb;
495         char *copy;
496
497         /* allocates the request */
498         lenapi = 1 + strlen(api);
499         lenverb = 1 + strlen(verb);
500         callreq = malloc(lenapi + lenverb + sizeof *callreq);
501         if (callreq != NULL) {
502                 /* initialises the request */
503                 afb_xreq_init(&callreq->xreq, itf);
504                 afb_context_init(&callreq->xreq.context, export->session, NULL);
505                 callreq->xreq.context.validated = 1;
506                 copy = (char*)&callreq[1];
507                 memcpy(copy, api, lenapi);
508                 callreq->xreq.api = copy;
509                 copy = &copy[lenapi];
510                 memcpy(copy, verb, lenverb);
511                 callreq->xreq.verb = copy;
512                 callreq->xreq.listener = export->listener;
513                 callreq->xreq.json = args;
514                 callreq->export = export;
515         }
516         return callreq;
517 }
518
519 /*
520  * Initiates a call for the service
521  */
522 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure)
523 {
524         struct afb_export *export = closure;
525         struct call_req *callreq;
526         struct json_object *ierr;
527
528         /* allocates the request */
529         callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf);
530         if (callreq == NULL) {
531                 ERROR("out of memory");
532                 json_object_put(args);
533                 ierr = afb_msg_json_internal_error();
534                 if (callback)
535                         callback(cbclosure, -1, ierr);
536                 json_object_put(ierr);
537                 return;
538         }
539
540         /* initialises the request */
541         callreq->jobloop = NULL;
542         callreq->callback = callback;
543         callreq->closure = cbclosure;
544
545         /* terminates and frees ressources if needed */
546         afb_xreq_process(&callreq->xreq, export->apiset);
547 }
548
549 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
550                                 struct json_object **result)
551 {
552         struct afb_export *export = closure;
553         struct call_req *callreq;
554         struct json_object *resu;
555         int rc;
556
557         /* allocates the request */
558         callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf);
559         if (callreq == NULL) {
560                 ERROR("out of memory");
561                 errno = ENOMEM;
562                 json_object_put(args);
563                 resu = afb_msg_json_internal_error();
564                 rc = -1;
565         } else {
566                 /* initialises the request */
567                 callreq->jobloop = NULL;
568                 callreq->callback = NULL;
569                 callreq->result = NULL;
570                 callreq->status = 0;
571                 afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */
572                 rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq);
573                 if (rc >= 0)
574                         rc = callreq->status;
575                 resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error();
576                 afb_xreq_unhooked_unref(&callreq->xreq);
577         }
578         if (result)
579                 *result = resu;
580         else
581                 json_object_put(resu);
582         return rc;
583 }
584
585 struct hooked_call
586 {
587         struct afb_export *export;
588         void (*callback)(void*, int, struct json_object*);
589         void *cbclosure;
590 };
591
592 static void svc_hooked_call_result(void *closure, int status, struct json_object *result)
593 {
594         struct hooked_call *hc = closure;
595         afb_hook_svc_call_result(hc->export, status, result);
596         hc->callback(hc->cbclosure, status, result);
597         free(hc);
598 }
599
600 static void svc_hooked_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure)
601 {
602         struct afb_export *export = closure;
603         struct hooked_call *hc;
604
605         if (export->hooksvc & afb_hook_flag_svc_call)
606                 afb_hook_svc_call(export, api, verb, args);
607
608         if (export->hooksvc & afb_hook_flag_svc_call_result) {
609                 hc = malloc(sizeof *hc);
610                 if (!hc)
611                         WARNING("allocation failed");
612                 else {
613                         hc->export = export;
614                         hc->callback = callback;
615                         hc->cbclosure = cbclosure;
616                         callback = svc_hooked_call_result;
617                         cbclosure = hc;
618                 }
619         }
620         svc_call(closure, api, verb, args, callback, cbclosure);
621 }
622
623 static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
624                                 struct json_object **result)
625 {
626         struct afb_export *export = closure;
627         struct json_object *resu;
628         int rc;
629
630         if (export->hooksvc & afb_hook_flag_svc_callsync)
631                 afb_hook_svc_callsync(export, api, verb, args);
632
633         rc = svc_call_sync(closure, api, verb, args, &resu);
634
635         if (export->hooksvc & afb_hook_flag_svc_callsync_result)
636                 afb_hook_svc_callsync_result(export, rc, resu);
637
638         if (result)
639                 *result = resu;
640         else
641                 json_object_put(resu);
642
643         return rc;
644 }
645
646 /* the interface for services */
647 static const struct afb_service_itf service_itf = {
648         .call = svc_call,
649         .call_sync = svc_call_sync
650 };
651
652 /* the interface for services */
653 static const struct afb_service_itf hooked_service_itf = {
654         .call = svc_hooked_call,
655         .call_sync = svc_hooked_call_sync
656 };
657
658 /*************************************************************************************************************
659  *************************************************************************************************************
660  *************************************************************************************************************
661  *************************************************************************************************************
662                                            F R O M     S V C
663  *************************************************************************************************************
664  *************************************************************************************************************
665  *************************************************************************************************************
666  *************************************************************************************************************/
667
668 /*
669  * Propagates the event to the service
670  */
671 static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object)
672 {
673         struct afb_export *export = closure;
674
675         if (export->hooksvc & afb_hook_flag_svc_on_event_before)
676                 afb_hook_svc_on_event_before(export, event, eventid, object);
677         export->on_event.v12(event, object);
678         if (export->hooksvc & afb_hook_flag_svc_on_event_after)
679                 afb_hook_svc_on_event_after(export, event, eventid, object);
680         json_object_put(object);
681 }
682
683 /* the interface for events */
684 static const struct afb_evt_itf evt_v12_itf = {
685         .broadcast = export_on_event_v12,
686         .push = export_on_event_v12
687 };
688
689 /*************************************************************************************************************
690  *************************************************************************************************************
691  *************************************************************************************************************
692  *************************************************************************************************************
693                                            M E R G E D
694  *************************************************************************************************************
695  *************************************************************************************************************
696  *************************************************************************************************************
697  *************************************************************************************************************/
698
699 static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version)
700 {
701         struct afb_export *export;
702
703         /* session shared with other exports */
704         if (common_session == NULL) {
705                 common_session = afb_session_create (NULL, 0);
706                 if (common_session == NULL)
707                         return NULL;
708         }
709         export = calloc(1, sizeof *export);
710         if (!export)
711                 errno = ENOMEM;
712         else {
713                 memset(export, 0, sizeof *export);
714                 export->apiname = strdup(apiname);
715                 export->version = version;
716                 export->state = Api_State_Pre_Init;
717                 export->session = afb_session_addref(common_session);
718                 export->apiset = afb_apiset_addref(apiset);
719         }
720         return export;
721 }
722
723 void afb_export_destroy(struct afb_export *export)
724 {
725         if (export) {
726                 if (export->listener != NULL)
727                         afb_evt_listener_unref(export->listener);
728                 afb_session_unref(export->session);
729                 afb_apiset_unref(export->apiset);
730                 free(export->apiname);
731                 free(export);
732         }
733 }
734
735 struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*))
736 {
737         struct afb_export *export = create(apiset, apiname, Api_Version_1);
738         if (export) {
739                 export->init.v1 = init;
740                 export->on_event.v12 = onevent;
741                 export->export.v1.verbosity = verbosity;
742                 export->export.v1.mode = AFB_MODE_LOCAL;
743                 export->export.v1.daemon.closure = export;
744                 afb_export_update_hook(export);
745         }
746         return export;
747 }
748
749 struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*))
750 {
751         struct afb_export *export = create(apiset, apiname, Api_Version_2);
752         if (export) {
753                 export->init.v2 = init;
754                 export->on_event.v12 = onevent;
755                 export->export.v2 = data;
756                 data->verbosity = verbosity;
757                 data->daemon.closure = export;
758                 data->service.closure = export;
759                 afb_export_update_hook(export);
760         }
761         return export;
762 }
763
764 void afb_export_rename(struct afb_export *export, const char *apiname)
765 {
766         free(export->apiname);
767         export->apiname = strdup(apiname);
768         afb_export_update_hook(export);
769 }
770
771 const char *afb_export_apiname(const struct afb_export *export)
772 {
773         return export->apiname;
774 }
775
776 void afb_export_update_hook(struct afb_export *export)
777 {
778         export->hookditf = afb_hook_flags_ditf(export->apiname);
779         export->hooksvc = afb_hook_flags_svc(export->apiname);
780         switch (export->version) {
781         case Api_Version_1:
782                 export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
783                 break;
784         default:
785         case Api_Version_2:
786                 export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf;
787                 export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf;
788                 break;
789         }
790 }
791
792 struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export)
793 {
794         return export->version == Api_Version_1 ? &export->export.v1 : NULL;
795 }
796
797 int afb_export_unshare_session(struct afb_export *export)
798 {
799         if (export->session == common_session) {
800                 export->session = afb_session_create (NULL, 0);
801                 if (export->session)
802                         afb_session_unref(common_session);
803                 else {
804                         export->session = common_session;
805                         return -1;
806                 }
807         }
808         return 0;
809 }
810
811 void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset)
812 {
813         struct afb_apiset *prvset = export->apiset;
814         export->apiset = afb_apiset_addref(apiset);
815         afb_apiset_unref(prvset);
816 }
817
818 struct afb_apiset *afb_export_get_apiset(struct afb_export *export)
819 {
820         return export->apiset;
821 }
822
823 /*
824  * Creates a new service
825  */
826 int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object))
827 {
828         /* check version */
829         switch (export->version) {
830         case Api_Version_1: case Api_Version_2: break;
831         default:
832                 ERROR("invalid version 12 for API %s", export->apiname);
833                 errno = EINVAL;
834                 return -1;
835         }
836
837         /* set the event handler */
838         if (!on_event) {
839                 if (export->listener) {
840                         afb_evt_listener_unref(export->listener);
841                         export->listener = NULL;
842                 }
843                 export->on_event.v12 = on_event;
844         } else {
845                 export->on_event.v12 = on_event;
846                 if (!export->listener) {
847                         export->listener = afb_evt_listener_create(&evt_v12_itf, export);
848                         if (export->listener == NULL)
849                                 return -1;
850                 }
851         }
852         return 0;
853 }
854
855 /*
856  * Starts a new service (v1)
857  */
858 struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*))
859 {
860         return regfun(&export->export.v1);
861 }
862
863 int afb_export_verbosity_get(const struct afb_export *export)
864 {
865         switch (export->version) {
866         case Api_Version_1: return export->export.v1.verbosity;
867         case Api_Version_2: return export->export.v2->verbosity;
868         }
869         return verbosity;
870 }
871
872 void afb_export_verbosity_set(struct afb_export *export, int level)
873 {
874         switch (export->version) {
875         case Api_Version_1: export->export.v1.verbosity = level; break;
876         case Api_Version_2: export->export.v2->verbosity = level; break;
877         }
878 }
879
880 /*************************************************************************************************************
881  *************************************************************************************************************
882  *************************************************************************************************************
883  *************************************************************************************************************
884                                            N E W
885  *************************************************************************************************************
886  *************************************************************************************************************
887  *************************************************************************************************************
888  *************************************************************************************************************/
889
890 int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset)
891 {
892         int rc;
893
894         /* check state */
895         if (export->state != Api_State_Pre_Init) {
896                 /* not an error when onneed */
897                 if (onneed != 0)
898                         goto done;
899
900                 /* already started: it is an error */
901                 ERROR("Service of API %s already started", export->apiname);
902                 return -1;
903         }
904
905         /* unshare the session if asked */
906         if (!share_session) {
907                 rc = afb_export_unshare_session(export);
908                 if (rc < 0) {
909                         ERROR("Can't unshare the session for %s", export->apiname);
910                         return -1;
911                 }
912         }
913
914         /* set event handling */
915         switch (export->version) {
916         case Api_Version_1:
917         case Api_Version_2:
918                 rc = afb_export_handle_events_v12(export, export->on_event.v12);
919                 break;
920         default:
921                 rc = 0;
922                 break;
923         }
924         if (rc < 0) {
925                 ERROR("Can't set event handler for %s", export->apiname);
926                 return -1;
927         }
928
929         /* Starts the service */
930         if (export->hooksvc & afb_hook_flag_svc_start_before)
931                 afb_hook_svc_start_before(export);
932         export->state = Api_State_Init;
933         switch (export->version) {
934         case Api_Version_1:
935                 rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0;
936                 break;
937         case Api_Version_2:
938                 rc = export->init.v2 ? export->init.v2() : 0;
939                 break;
940         default:
941                 break;
942         }
943         export->state = Api_State_Run;
944         if (export->hooksvc & afb_hook_flag_svc_start_after)
945                 afb_hook_svc_start_after(export, rc);
946         if (rc < 0) {
947                 /* initialisation error */
948                 ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc);
949                 return rc;
950         }
951
952 done:
953         return 0;
954 }
955