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