X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-export.c;h=7fd475abac656bd2a3d65c465596f3f5870c4f2e;hb=7f4444176bd6efaa5e189a148351bab5a72c2853;hp=70a637746dd8af5877b52945b1bf029f8f85ed6e;hpb=33e615ea0cc26131532f4615ef4a2034488fa48e;p=src%2Fapp-framework-binder.git diff --git a/src/afb-export.c b/src/afb-export.c index 70a63774..7fd475ab 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -23,11 +23,12 @@ #include -#include -#include +#define AFB_BINDING_VERSION 0 +#include #include "afb-api.h" #include "afb-apiset.h" +#include "afb-api-dyn.h" #include "afb-common.h" #include "afb-cred.h" #include "afb-evt.h" @@ -39,18 +40,15 @@ #include "jobs.h" #include "verbose.h" -extern struct afb_apiset *main_apiset; - /************************************************************************* * internal types and structures ************************************************************************/ enum afb_api_version { - Api_Version_None = 0, + Api_Version_Dyn = 0, Api_Version_1 = 1, Api_Version_2 = 2, - Api_Version_3 = 3 }; enum afb_api_state @@ -62,6 +60,9 @@ enum afb_api_state struct afb_export { + /* keep it first */ + struct afb_dynapi dynapi; + /* name of the api */ char *apiname; @@ -74,7 +75,10 @@ struct afb_export /* hooking flags */ int hookditf; int hooksvc; - + + /* dynamic api */ + struct afb_api_dyn *apidyn; + /* session for service */ struct afb_session *session; @@ -84,8 +88,18 @@ struct afb_export /* event listener for service or NULL */ struct afb_evt_listener *listener; - /* event callback for service */ - void (*on_event)(const char *event, struct json_object *object); + /* start function */ + union { + int (*v1)(struct afb_service); + int (*v2)(); + int (*vdyn)(struct afb_dynapi *dynapi); + } init; + + /* event handling */ + union { + void (*v12)(const char *event, struct json_object *object); + void (*vdyn)(struct afb_dynapi *dynapi, const char *event, struct json_object *object); + } on_event; /* exported data */ union { @@ -94,6 +108,18 @@ struct afb_export } export; }; +/************************************************************************************************************/ + +static inline struct afb_dynapi *to_dynapi(struct afb_export *export) +{ + return (struct afb_dynapi*)export; +} + +static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi) +{ + return (struct afb_export*)dynapi; +} + /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -125,7 +151,7 @@ static void old_vverbose_cb(void *closure, int level, const char *file, int line vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_event event_make_cb(void *closure, const char *name) +static struct afb_eventid *eventid_make_cb(void *closure, const char *name) { size_t plen, nlen; char *event; @@ -135,7 +161,7 @@ static struct afb_event event_make_cb(void *closure, const char *name) if (export->state == Api_State_Pre_Init) { ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name); errno = EINVAL; - return (struct afb_event){ .itf = NULL, .closure = NULL }; + return NULL; } /* makes the event name */ @@ -150,6 +176,12 @@ static struct afb_event event_make_cb(void *closure, const char *name) return afb_evt_create_event(event); } +static struct afb_event event_make_cb(void *closure, const char *name) +{ + struct afb_eventid *eventid = eventid_make_cb(closure, name); + return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid }; +} + static int event_broadcast_cb(void *closure, const char *name, struct json_object *object) { size_t plen, nlen; @@ -198,7 +230,7 @@ static int require_api_cb(void *closure, const char *name, int initialized) errno = EINVAL; return -1; } - return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(main_apiset, name, 1); + return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1); } static int rename_api_cb(void *closure, const char *name) @@ -219,6 +251,17 @@ static int rename_api_cb(void *closure, const char *name) return 0; } +static int api_new_api_cb( + void *closure, + const char *api, + const char *info, + int (*preinit)(void*, struct afb_dynapi *), + void *preinit_closure) +{ + struct afb_export *export = closure; + return afb_api_dyn_add(export->apiset, api, info, preinit, preinit_closure); +} + /********************************************** * hooked flow **********************************************/ @@ -237,11 +280,18 @@ static void hooked_old_vverbose_cb(void *closure, int level, const char *file, i hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_event hooked_event_make_cb(void *closure, const char *name) +static struct afb_eventid *hooked_eventid_make_cb(void *closure, const char *name) { struct afb_export *export = closure; - struct afb_event r = event_make_cb(closure, name); - return afb_hook_ditf_event_make(export, name, r); + struct afb_eventid *r = eventid_make_cb(closure, name); + afb_hook_ditf_event_make(export, name, r); + return r; +} + +static struct afb_event hooked_event_make_cb(void *closure, const char *name) +{ + struct afb_eventid *eventid = hooked_eventid_make_cb(closure, name); + return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid }; } static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object) @@ -322,6 +372,16 @@ static int hooked_rename_api_cb(void *closure, const char *name) return afb_hook_ditf_rename_api(export, oldname, name, result); } +static int hooked_api_new_api_cb( + void *closure, + const char *api, + const char *info, + int (*preinit)(void*, struct afb_dynapi *), + void *preinit_closure) +{ + /* TODO */ + return api_new_api_cb(closure, api, info, preinit, preinit_closure); +} /********************************************** * vectors **********************************************/ @@ -338,7 +398,8 @@ static const struct afb_daemon_itf daemon_itf = { .queue_job = queue_job_cb, .unstore_req = unstore_req_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb + .rename_api = rename_api_cb, + .new_api = api_new_api_cb, }; static const struct afb_daemon_itf hooked_daemon_itf = { @@ -354,10 +415,10 @@ static const struct afb_daemon_itf hooked_daemon_itf = { .queue_job = hooked_queue_job_cb, .unstore_req = hooked_unstore_req_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb + .rename_api = hooked_rename_api_cb, + .new_api = hooked_api_new_api_cb, }; - /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -391,14 +452,16 @@ struct call_req struct afb_export *export; /* the args */ - void (*callback)(void*, int, struct json_object*); + union { + void (*callback)(void*, int, struct json_object*); + void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); + }; void *closure; /* sync */ struct jobloop *jobloop; struct json_object *result; int status; - int async; }; /* @@ -414,7 +477,7 @@ static void callreq_destroy(struct afb_xreq *xreq) free(callreq); } -static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj) +static void callreq_reply_async(struct afb_xreq *xreq, int status, json_object *obj) { struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); if (callreq->callback) @@ -422,6 +485,14 @@ static void callreq_reply(struct afb_xreq *xreq, int status, json_object *obj) json_object_put(obj); } +static void callreq_reply_async_dynapi(struct afb_xreq *xreq, int status, json_object *obj) +{ + struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); + if (callreq->callback_dynapi) + callreq->callback_dynapi(callreq->closure, status, obj, to_dynapi(callreq->export)); + json_object_put(obj); +} + static void callreq_sync_leave(struct call_req *callreq) { struct jobloop *jobloop = callreq->jobloop; @@ -455,9 +526,15 @@ static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloo } /* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_itf = { +const struct afb_xreq_query_itf afb_export_xreq_async_itf = { .unref = callreq_destroy, - .reply = callreq_reply + .reply = callreq_reply_async +}; + +/* interface for requests of services */ +const struct afb_xreq_query_itf afb_export_xreq_async_dynapi_itf = { + .unref = callreq_destroy, + .reply = callreq_reply_async_dynapi }; /* interface for requests of services */ @@ -469,7 +546,12 @@ const struct afb_xreq_query_itf afb_export_xreq_sync_itf = { /* * create an call_req */ -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) +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) { struct call_req *callreq; size_t lenapi, lenverb; @@ -486,10 +568,10 @@ static struct call_req *callreq_create(struct afb_export *export, const char *ap callreq->xreq.context.validated = 1; copy = (char*)&callreq[1]; memcpy(copy, api, lenapi); - callreq->xreq.api = copy; + callreq->xreq.request.api = copy; copy = ©[lenapi]; memcpy(copy, verb, lenverb); - callreq->xreq.verb = copy; + callreq->xreq.request.verb = copy; callreq->xreq.listener = export->listener; callreq->xreq.json = args; callreq->export = export; @@ -500,14 +582,20 @@ static struct call_req *callreq_create(struct afb_export *export, const char *ap /* * Initiates a call for the service */ -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) +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) { struct afb_export *export = closure; struct call_req *callreq; struct json_object *ierr; /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_itf); + callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_itf); if (callreq == NULL) { ERROR("out of memory"); json_object_put(args); @@ -522,14 +610,50 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js callreq->jobloop = NULL; callreq->callback = callback; callreq->closure = cbclosure; - callreq->async = 1; /* terminates and frees ressources if needed */ afb_xreq_process(&callreq->xreq, export->apiset); } -static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, - struct json_object **result) +static void svc_call_dynapi( + struct afb_dynapi *dynapi, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), + void *cbclosure) +{ + struct afb_export *export = from_dynapi(dynapi); + struct call_req *callreq; + struct json_object *ierr; + + /* allocates the request */ + callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_dynapi_itf); + if (callreq == NULL) { + ERROR("out of memory"); + json_object_put(args); + ierr = afb_msg_json_internal_error(); + if (callback) + callback(cbclosure, -1, ierr, to_dynapi(export)); + json_object_put(ierr); + return; + } + + /* initialises the request */ + callreq->jobloop = NULL; + callreq->callback_dynapi = callback; + callreq->closure = cbclosure; + + /* terminates and frees ressources if needed */ + afb_xreq_process(&callreq->xreq, export->apiset); +} + +static int svc_call_sync( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) { struct afb_export *export = closure; struct call_req *callreq; @@ -550,13 +674,12 @@ static int svc_call_sync(void *closure, const char *api, const char *verb, struc callreq->callback = NULL; callreq->result = NULL; callreq->status = 0; - callreq->async = 0; - afb_xreq_addref(&callreq->xreq); + afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq); if (rc >= 0) rc = callreq->status; resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error(); - afb_xreq_unref(&callreq->xreq); + afb_xreq_unhooked_unref(&callreq->xreq); } if (result) *result = resu; @@ -568,7 +691,10 @@ static int svc_call_sync(void *closure, const char *api, const char *verb, struc struct hooked_call { struct afb_export *export; - void (*callback)(void*, int, struct json_object*); + union { + void (*callback)(void*, int, struct json_object*); + void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); + }; void *cbclosure; }; @@ -580,7 +706,21 @@ static void svc_hooked_call_result(void *closure, int status, struct json_object free(hc); } -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) +static void svc_hooked_call_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi) +{ + struct hooked_call *hc = closure; + afb_hook_svc_call_result(hc->export, status, result); + hc->callback_dynapi(hc->cbclosure, status, result, dynapi); + free(hc); +} + +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) { struct afb_export *export = closure; struct hooked_call *hc; @@ -603,8 +743,41 @@ static void svc_hooked_call(void *closure, const char *api, const char *verb, st svc_call(closure, api, verb, args, callback, cbclosure); } -static int svc_hooked_call_sync(void *closure, const char *api, const char *verb, struct json_object *args, - struct json_object **result) +static void svc_hooked_call_dynapi( + struct afb_dynapi *dynapi, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), + void *cbclosure) +{ + struct afb_export *export = from_dynapi(dynapi); + struct hooked_call *hc; + + if (export->hooksvc & afb_hook_flag_svc_call) + afb_hook_svc_call(export, api, verb, args); + + if (export->hooksvc & afb_hook_flag_svc_call_result) { + hc = malloc(sizeof *hc); + if (!hc) + WARNING("allocation failed"); + else { + hc->export = export; + hc->callback_dynapi = callback; + hc->cbclosure = cbclosure; + callback = svc_hooked_call_dynapi_result; + cbclosure = hc; + } + } + svc_call_dynapi(dynapi, api, verb, args, callback, cbclosure); +} + +static int svc_hooked_call_sync( + void *closure, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) { struct afb_export *export = closure; struct json_object *resu; @@ -638,6 +811,197 @@ static const struct afb_service_itf hooked_service_itf = { .call_sync = svc_hooked_call_sync }; +/************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + F R O M D Y N A P I + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + *************************************************************************************************************/ + +static int api_set_verbs_v2_cb( + struct afb_dynapi *dynapi, + const struct afb_verb_v2 *verbs) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) { + afb_api_dyn_set_verbs_v2(export->apidyn, verbs); + return 0; + } + + errno = EPERM; + return -1; +} + +static int api_add_verb_cb( + struct afb_dynapi *dynapi, + const char *verb, + const char *info, + void (*callback)(struct afb_request *request), + void *vcbdata, + const struct afb_auth *auth, + uint32_t session) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) + return afb_api_dyn_add_verb(export->apidyn, verb, info, callback, vcbdata, auth, session); + + errno = EPERM; + return -1; +} + +static int api_sub_verb_cb( + struct afb_dynapi *dynapi, + const char *verb) +{ + struct afb_export *export = from_dynapi(dynapi); + + if (export->apidyn) + return afb_api_dyn_sub_verb(export->apidyn, verb); + + errno = EPERM; + return -1; +} + +static int api_set_on_event_cb( + struct afb_dynapi *dynapi, + void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + struct afb_export *export = from_dynapi(dynapi); + return afb_export_handle_events_vdyn(export, onevent); +} + +static int api_set_on_init_cb( + struct afb_dynapi *dynapi, + int (*oninit)(struct afb_dynapi *dynapi)) +{ + struct afb_export *export = from_dynapi(dynapi); + + return afb_export_handle_init_vdyn(export, oninit); +} + +static void api_seal_cb( + struct afb_dynapi *dynapi) +{ + struct afb_export *export = from_dynapi(dynapi); + + export->apidyn = NULL; +} + +static int hooked_api_set_verbs_v2_cb( + struct afb_dynapi *dynapi, + const struct afb_verb_v2 *verbs) +{ + /* TODO */ + return api_set_verbs_v2_cb(dynapi, verbs); +} + +static int hooked_api_add_verb_cb( + struct afb_dynapi *dynapi, + const char *verb, + const char *info, + void (*callback)(struct afb_request *request), + void *vcbdata, + const struct afb_auth *auth, + uint32_t session) +{ + /* TODO */ + return api_add_verb_cb(dynapi, verb, info, callback, vcbdata, auth, session); +} + +static int hooked_api_sub_verb_cb( + struct afb_dynapi *dynapi, + const char *verb) +{ + /* TODO */ + return api_sub_verb_cb(dynapi, verb); +} + +static int hooked_api_set_on_event_cb( + struct afb_dynapi *dynapi, + void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + /* TODO */ + return api_set_on_event_cb(dynapi, onevent); +} + +static int hooked_api_set_on_init_cb( + struct afb_dynapi *dynapi, + int (*oninit)(struct afb_dynapi *dynapi)) +{ + /* TODO */ + return api_set_on_init_cb(dynapi, oninit); +} + +static void hooked_api_seal_cb( + struct afb_dynapi *dynapi) +{ + /* TODO */ + api_seal_cb(dynapi); +} + +static const struct afb_dynapi_itf dynapi_itf = { + + .vverbose = (void*)vverbose_cb, + + .get_event_loop = afb_common_get_event_loop, + .get_user_bus = afb_common_get_user_bus, + .get_system_bus = afb_common_get_system_bus, + .rootdir_get_fd = afb_common_rootdir_get_fd, + .rootdir_open_locale = rootdir_open_locale_cb, + .queue_job = queue_job_cb, + + .require_api = require_api_cb, + .rename_api = rename_api_cb, + + .event_broadcast = event_broadcast_cb, + .eventid_make = eventid_make_cb, + + .call = svc_call_dynapi, + .call_sync = svc_call_sync, + + .api_new_api = api_new_api_cb, + .api_set_verbs_v2 = api_set_verbs_v2_cb, + .api_add_verb = api_add_verb_cb, + .api_sub_verb = api_sub_verb_cb, + .api_set_on_event = api_set_on_event_cb, + .api_set_on_init = api_set_on_init_cb, + .api_seal = api_seal_cb, +}; + +static const struct afb_dynapi_itf hooked_dynapi_itf = { + + .vverbose = hooked_vverbose_cb, + + .get_event_loop = hooked_get_event_loop, + .get_user_bus = hooked_get_user_bus, + .get_system_bus = hooked_get_system_bus, + .rootdir_get_fd = hooked_rootdir_get_fd, + .rootdir_open_locale = hooked_rootdir_open_locale_cb, + .queue_job = hooked_queue_job_cb, + + .require_api = hooked_require_api_cb, + .rename_api = hooked_rename_api_cb, + + .event_broadcast = hooked_event_broadcast_cb, + .eventid_make = hooked_eventid_make_cb, + + .call = svc_hooked_call_dynapi, + .call_sync = svc_hooked_call_sync, + + .api_new_api = hooked_api_new_api_cb, + .api_set_verbs_v2 = hooked_api_set_verbs_v2_cb, + .api_add_verb = hooked_api_add_verb_cb, + .api_sub_verb = hooked_api_sub_verb_cb, + .api_set_on_event = hooked_api_set_on_event_cb, + .api_set_on_init = hooked_api_set_on_init_cb, + .api_seal = hooked_api_seal_cb, +}; + /************************************************************************************************************* ************************************************************************************************************* ************************************************************************************************************* @@ -651,22 +1015,43 @@ static const struct afb_service_itf hooked_service_itf = { /* * Propagates the event to the service */ -static void export_on_event(void *closure, const char *event, int eventid, struct json_object *object) +static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object) { struct afb_export *export = closure; if (export->hooksvc & afb_hook_flag_svc_on_event_before) afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event(event, object); + export->on_event.v12(event, object); if (export->hooksvc & afb_hook_flag_svc_on_event_after) afb_hook_svc_on_event_after(export, event, eventid, object); json_object_put(object); } /* the interface for events */ -static const struct afb_evt_itf evt_itf = { - .broadcast = export_on_event, - .push = export_on_event +static const struct afb_evt_itf evt_v12_itf = { + .broadcast = export_on_event_v12, + .push = export_on_event_v12 +}; + +/* + * Propagates the event to the service + */ +static void export_on_event_vdyn(void *closure, const char *event, int eventid, struct json_object *object) +{ + struct afb_export *export = closure; + + if (export->hooksvc & afb_hook_flag_svc_on_event_before) + afb_hook_svc_on_event_before(export, event, eventid, object); + export->on_event.vdyn(to_dynapi(export), event, object); + if (export->hooksvc & afb_hook_flag_svc_on_event_after) + afb_hook_svc_on_event_after(export, event, eventid, object); + json_object_put(object); +} + +/* the interface for events */ +static const struct afb_evt_itf evt_vdyn_itf = { + .broadcast = export_on_event_vdyn, + .push = export_on_event_vdyn }; /************************************************************************************************************* @@ -679,7 +1064,7 @@ static const struct afb_evt_itf evt_itf = { ************************************************************************************************************* *************************************************************************************************************/ -static struct afb_export *create(const char *apiname, enum afb_api_version version) +static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version) { struct afb_export *export; @@ -695,10 +1080,11 @@ static struct afb_export *create(const char *apiname, enum afb_api_version versi else { memset(export, 0, sizeof *export); export->apiname = strdup(apiname); + export->dynapi.apiname = export->apiname; export->version = version; export->state = Api_State_Pre_Init; export->session = afb_session_addref(common_session); - export->apiset = afb_apiset_addref(main_apiset); + export->apiset = afb_apiset_addref(apiset); } return export; } @@ -715,25 +1101,41 @@ void afb_export_destroy(struct afb_export *export) } } -struct afb_export *afb_export_create_v1(const char *apiname) +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*)) { - struct afb_export *export = create(apiname, Api_Version_1); + struct afb_export *export = create(apiset, apiname, Api_Version_1); if (export) { - export->export.v1.verbosity = verbosity; + export->init.v1 = init; + export->on_event.v12 = onevent; export->export.v1.mode = AFB_MODE_LOCAL; export->export.v1.daemon.closure = export; + afb_export_verbosity_set(export, verbosity); afb_export_update_hook(export); } return export; } -struct afb_export *afb_export_create_v2(const char *apiname, struct afb_binding_data_v2 *data) +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*)) { - struct afb_export *export = create(apiname, Api_Version_2); + struct afb_export *export = create(apiset, apiname, Api_Version_2); if (export) { + export->init.v2 = init; + export->on_event.v12 = onevent; export->export.v2 = data; data->daemon.closure = export; data->service.closure = export; + afb_export_verbosity_set(export, verbosity); + afb_export_update_hook(export); + } + return export; +} + +struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *apidyn) +{ + struct afb_export *export = create(apiset, apiname, Api_Version_Dyn); + if (export) { + export->apidyn = apidyn; + afb_export_verbosity_set(export, verbosity); afb_export_update_hook(export); } return export; @@ -743,6 +1145,7 @@ void afb_export_rename(struct afb_export *export, const char *apiname) { free(export->apiname); export->apiname = strdup(apiname); + export->dynapi.apiname = export->apiname; afb_export_update_hook(export); } @@ -755,11 +1158,12 @@ void afb_export_update_hook(struct afb_export *export) { export->hookditf = afb_hook_flags_ditf(export->apiname); export->hooksvc = afb_hook_flags_svc(export->apiname); + export->dynapi.itf = export->hookditf|export->hooksvc ? &hooked_dynapi_itf : &dynapi_itf; + switch (export->version) { case Api_Version_1: export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; break; - default: case Api_Version_2: export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf; @@ -792,33 +1196,81 @@ void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset) export->apiset = afb_apiset_addref(apiset); afb_apiset_unref(prvset); } - -/* - * Creates a new service - */ -int afb_export_handle_events(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) + +struct afb_apiset *afb_export_get_apiset(struct afb_export *export) { - if (on_event != export->on_event) { - if (!on_event) { + return export->apiset; +} + +int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) +{ + /* check version */ + switch (export->version) { + case Api_Version_1: case Api_Version_2: break; + default: + ERROR("invalid version 12 for API %s", export->apiname); + errno = EINVAL; + return -1; + } + + /* set the event handler */ + if (!on_event) { + if (export->listener) { afb_evt_listener_unref(export->listener); export->listener = NULL; - } else if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_itf, export); + } + export->on_event.v12 = on_event; + } else { + export->on_event.v12 = on_event; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_v12_itf, export); if (export->listener == NULL) return -1; } - export->on_event = on_event; } return 0; } +int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +{ + /* check version */ + switch (export->version) { + case Api_Version_Dyn: break; + default: + ERROR("invalid version Dyn for API %s", export->apiname); + errno = EINVAL; + return -1; + } + /* set the event handler */ + if (!on_event) { + if (export->listener) { + afb_evt_listener_unref(export->listener); + export->listener = NULL; + } + export->on_event.vdyn = on_event; + } else { + export->on_event.vdyn = on_event; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_vdyn_itf, export); + if (export->listener == NULL) + return -1; + } + } + return 0; +} -int afb_export_is_started(const struct afb_export *export) +int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)) { - return export->state != Api_State_Pre_Init; -} + if (export->state != Api_State_Pre_Init) { + ERROR("[API %s] Bad call to 'afb_dynapi_on_init', must be in PreInit", export->apiname); + errno = EINVAL; + return -1; + } + export->init.vdyn = oninit; + return 0; +} /* * Starts a new service (v1) @@ -826,57 +1278,103 @@ int afb_export_is_started(const struct afb_export *export) struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)) { return regfun(&export->export.v1); - } -int afb_export_start_v1(struct afb_export *export, int (*start)(struct afb_service)) +int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure) { - int rc; - struct afb_service svc = { .itf = &hooked_service_itf, .closure = export }; + return preinit(closure, to_dynapi(export)); +} - if (export->hooksvc & afb_hook_flag_svc_start_before) - afb_hook_svc_start_before(export); - export->state = Api_State_Init; - rc = start ? start(svc) : 0; - export->state = Api_State_Run; - if (export->hooksvc & afb_hook_flag_svc_start_after) - afb_hook_svc_start_after(export, rc); - return rc; +int afb_export_verbosity_get(const struct afb_export *export) +{ + return export->dynapi.verbosity; } -/* - * Starts a new service (v2) - */ -int afb_export_start_v2(struct afb_export *export, int (*start)()) +void afb_export_verbosity_set(struct afb_export *export, int level) +{ + export->dynapi.verbosity = level; + switch (export->version) { + case Api_Version_1: export->export.v1.verbosity = level; break; + case Api_Version_2: export->export.v2->verbosity = level; break; + } +} + +/************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + N E W + ************************************************************************************************************* + ************************************************************************************************************* + ************************************************************************************************************* + *************************************************************************************************************/ + +int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset) { int rc; + /* check state */ + if (export->state != Api_State_Pre_Init) { + /* not an error when onneed */ + if (onneed != 0) + goto done; + + /* already started: it is an error */ + ERROR("Service of API %s already started", export->apiname); + return -1; + } + + /* unshare the session if asked */ + if (!share_session) { + rc = afb_export_unshare_session(export); + if (rc < 0) { + ERROR("Can't unshare the session for %s", export->apiname); + return -1; + } + } + + /* set event handling */ + switch (export->version) { + case Api_Version_1: + case Api_Version_2: + rc = afb_export_handle_events_v12(export, export->on_event.v12); + break; + default: + rc = 0; + break; + } + if (rc < 0) { + ERROR("Can't set event handler for %s", export->apiname); + return -1; + } + + /* Starts the service */ if (export->hooksvc & afb_hook_flag_svc_start_before) afb_hook_svc_start_before(export); export->state = Api_State_Init; - rc = start ? start() : 0; + switch (export->version) { + case Api_Version_1: + rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0; + break; + case Api_Version_2: + rc = export->init.v2 ? export->init.v2() : 0; + break; + case Api_Version_Dyn: + rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0; + break; + default: + break; + } export->state = Api_State_Run; if (export->hooksvc & afb_hook_flag_svc_start_after) afb_hook_svc_start_after(export, rc); - if (rc >= 0) - export->state = Api_State_Run; - return rc; -} - -int afb_export_verbosity_get(const struct afb_export *export) -{ - switch (export->version) { - case Api_Version_1: return export->export.v1.verbosity; - case Api_Version_2: return export->export.v2->verbosity; + if (rc < 0) { + /* initialisation error */ + ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc); + return rc; } - return verbosity; -} -void afb_export_verbosity_set(struct afb_export *export, int level) -{ - switch (export->version) { - case Api_Version_1: export->export.v1.verbosity = level; break; - case Api_Version_2: export->export.v2->verbosity = level; break; - } +done: + return 0; }