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