Add ability to provide binding settings
[src/app-framework-binder.git] / src / afb-export.c
index fbf77f8..c1a716f 100644 (file)
@@ -24,6 +24,9 @@
 #include <ctype.h>
 
 #include <json-c/json.h>
+#if !defined(JSON_C_TO_STRING_NOSLASHESCAPE)
+#define JSON_C_TO_STRING_NOSLASHESCAPE 0
+#endif
 
 #define AFB_BINDING_VERSION 0
 #include <afb/afb-binding.h>
@@ -47,6 +50,8 @@
 #include "afb-calls.h"
 #include "jobs.h"
 #include "verbose.h"
+#include "sig-monitor.h"
+#include "wrap-json.h"
 
 /*************************************************************************
  * internal types
@@ -135,6 +140,9 @@ struct afb_export
        /* event handler list */
        struct event_handler *event_handlers;
 
+       /* settings */
+       struct json_object *settings;
+
        /* internal descriptors */
        union {
 #if defined(WITH_LEGACY_BINDING_V1)
@@ -191,6 +199,41 @@ struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export)
        return to_api_x3(export);
 }
 
+/******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+       SETTINGS
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************/
+
+static struct json_object *configuration;
+
+void afb_export_set_config(struct json_object *config)
+{
+       struct json_object *save = configuration;
+       configuration = json_object_get(config);
+       json_object_put(save);
+}
+
+static struct json_object *get_settings(const char *name)
+{
+       struct json_object *result;
+       struct json_object *obj;
+
+       if (json_object_object_get_ex(configuration, "*", &obj))
+               result = wrap_json_clone(obj);
+       else
+               result = json_object_new_object();
+
+       if (json_object_object_get_ex(configuration, name, &obj))
+               wrap_json_object_add(result, obj);
+
+       return result;
+}
+
 /******************************************************************************
  ******************************************************************************
  ******************************************************************************
@@ -251,7 +294,8 @@ static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, stru
 
        /* check daemon state */
        if (export->state == Api_State_Pre_Init) {
-               ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->api.apiname, name, json_object_to_json_string(object));
+               ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit",
+                       export->api.apiname, name, json_object_to_json_string_ext(object, JSON_C_TO_STRING_NOSLASHESCAPE));
                errno = EINVAL;
                return 0;
        }
@@ -862,6 +906,17 @@ static int delete_api_cb(struct afb_api_x3 *api)
        return 0;
 }
 
+static struct json_object *settings_cb(struct afb_api_x3 *api)
+{
+       struct afb_export *export = from_api_x3(api);
+       struct json_object *result = export->settings;
+       if (!result) {
+               result = get_settings(export->name);
+               export->settings = result;
+       }
+       return result;
+}
+
 static int hooked_api_set_verbs_v2_cb(
                struct afb_api_x3 *api,
                const struct afb_verb_v2 *verbs)
@@ -975,6 +1030,14 @@ static int hooked_delete_api_cb(struct afb_api_x3 *api)
        return result;
 }
 
+static struct json_object *hooked_settings_cb(struct afb_api_x3 *api)
+{
+       struct afb_export *export = from_api_x3(api);
+       struct json_object *result = settings_cb(api);
+       result = afb_hook_api_settings(export, result);
+       return result;
+}
+
 static const struct afb_api_x3_itf api_x3_itf = {
 
        .vverbose = (void*)vverbose_cb,
@@ -1013,6 +1076,7 @@ static const struct afb_api_x3_itf api_x3_itf = {
        .class_require = class_require_cb,
 
        .delete_api = delete_api_cb,
+       .settings = settings_cb,
 };
 
 static const struct afb_api_x3_itf hooked_api_x3_itf = {
@@ -1053,6 +1117,7 @@ static const struct afb_api_x3_itf hooked_api_x3_itf = {
        .class_require = hooked_class_require_cb,
 
        .delete_api = hooked_delete_api_cb,
+       .settings = hooked_settings_cb,
 };
 
 /******************************************************************************
@@ -1148,7 +1213,7 @@ int afb_export_event_handler_add(
        }
 
        /* create the event */
-       handler = malloc(strlen(pattern) + strlen(pattern));
+       handler = malloc(strlen(pattern) + sizeof * handler);
        if (!handler) {
                ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern);
                errno = ENOMEM;
@@ -1160,7 +1225,7 @@ int afb_export_event_handler_add(
        handler->callback = callback;
        handler->closure = closure;
        strcpy(handler->pattern, pattern);
-       export->event_handlers = handler;
+       *previous = handler;
 
        return 0;
 }
@@ -1262,6 +1327,7 @@ void afb_export_destroy(struct afb_export *export)
                afb_apiset_unref(export->call_set);
                if (export->api.apiname != export->name)
                        free((void*)export->api.apiname);
+               json_object_put(export->settings);
                free(export);
        }
 }
@@ -1511,28 +1577,63 @@ void afb_export_userdata_set(struct afb_export *export, void *data)
  ******************************************************************************
  ******************************************************************************/
 
-int afb_export_start(struct afb_export *export, int share_session, int onneed)
+struct init
 {
+       int return_code;
+       struct afb_export *export;
+};
+
+static void do_init(int sig, void *closure)
+{
+       int rc = -1;
+       struct init *init = closure;
+       struct afb_export *export;
+
+       if (sig)
+               errno = EFAULT;
+       else {
+               export = init->export;
+               switch (export->version) {
+#if defined(WITH_LEGACY_BINDING_V1)
+               case Api_Version_1:
+                       rc = export->init.v1 ? export->init.v1(
+                               (struct afb_service_x1){
+                                       .itf = &hooked_service_itf,
+                                       .closure = to_api_x3(export) }) : 0;
+                       break;
+#endif
+               case Api_Version_2:
+                       rc = export->init.v2 ? export->init.v2() : 0;
+                       break;
+               case Api_Version_3:
+                       rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0;
+                       break;
+               default:
+                       errno = EINVAL;
+                       break;
+               }
+       }
+       init->return_code = rc;
+};
+
+
+int afb_export_start(struct afb_export *export)
+{
+       struct init init;
        int rc;
 
        /* check state */
-       if (export->state != Api_State_Pre_Init) {
-               /* not an error when onneed */
-               if (onneed != 0)
-                       goto done;
+       switch (export->state) {
+       case Api_State_Run:
+               return 0;
 
-               /* already started: it is an error */
-               ERROR("Service of API %s already started", export->api.apiname);
+       case Api_State_Init:
+               /* starting in progress: it is an error */
+               ERROR("Service of API %s required started while starting", export->api.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->api.apiname);
-                       return -1;
-               }
+       default:
+               break;
        }
 
        /* set event handling */
@@ -1541,9 +1642,11 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed)
        case Api_Version_1:
 #endif
        case Api_Version_2:
-               if (export->on_any_event_v12)
+               if (export->on_any_event_v12) {
                        rc = afb_export_handle_events_v12(export, export->on_any_event_v12);
-               break;
+                       break;
+               }
+               /*@fallthrough@*/
        default:
                rc = 0;
                break;
@@ -1558,23 +1661,9 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed)
                afb_hook_api_start_before(export);
 
        export->state = Api_State_Init;
-       switch (export->version) {
-#if defined(WITH_LEGACY_BINDING_V1)
-       case Api_Version_1:
-               rc = export->init.v1 ? export->init.v1((struct afb_service_x1){ .itf = &hooked_service_itf, .closure = to_api_x3(export) }) : 0;
-               break;
-#endif
-       case Api_Version_2:
-               rc = export->init.v2 ? export->init.v2() : 0;
-               break;
-       case Api_Version_3:
-               rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0;
-               break;
-       default:
-               errno = EINVAL;
-               rc = -1;
-               break;
-       }
+       init.export = export;
+       sig_monitor(0, do_init, &init);
+       rc = init.return_code;
        export->state = Api_State_Run;
 
        if (export->hooksvc & afb_hook_flag_api_start)
@@ -1586,7 +1675,6 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed)
                return rc;
        }
 
-done:
        return 0;
 }
 
@@ -1638,11 +1726,11 @@ static struct json_object *api_describe_cb(void *closure)
        return result;
 }
 
-static int api_service_start_cb(void *closure, int share_session, int onneed)
+static int api_service_start_cb(void *closure)
 {
        struct afb_export *export = closure;
 
-       return afb_export_start(export, share_session, onneed);
+       return afb_export_start(export);
 }
 
 static void api_update_hooks_cb(void *closure)
@@ -1739,5 +1827,6 @@ void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq)
 void afb_export_context_init(struct afb_export *export, struct afb_context *context)
 {
        afb_context_init(context, export->session, NULL);
+       context->validated = 1;
 }