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