From 11e2d4395056c7bd2a618b4fa7ffdd70af05d14e Mon Sep 17 00:00:00 2001
From: José Bollo <jose.bollo@iot.bzh>
Date: Thu, 31 Aug 2017 09:30:19 +0200
Subject: afb-svc: make service existing during its initialisation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The initialisation of services is splitted in two parts:

 - the creation and allocation of the structure for the
   service.

 - the initialisation once the structure is ready and
   recorded.

Change-Id: I05c89fb513869d45e6b8413699fba234f00ce6b1
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
---
 src/afb-api-so-v1.c |  16 +++++--
 src/afb-api-so-v2.c |  14 +++++-
 src/afb-svc.c       | 120 +++++++++++++++++-----------------------------------
 src/afb-svc.h       |  15 +++----
 4 files changed, 71 insertions(+), 94 deletions(-)

diff --git a/src/afb-api-so-v1.c b/src/afb-api-so-v1.c
index 7e987c22..3eea4645 100644
--- a/src/afb-api-so-v1.c
+++ b/src/afb-api-so-v1.c
@@ -78,6 +78,7 @@ static void call_cb(void *closure, struct afb_xreq *xreq)
 
 static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
 {
+	int rc;
 	int (*init)(struct afb_service service);
 	void (*onevent)(const char *event, struct json_object *object);
 
@@ -108,13 +109,22 @@ static int service_start_cb(void *closure, int share_session, int onneed, struct
 	}
 
 	/* get the event handler if any */
-	desc->service = afb_svc_create_v1(desc->binding->v1.prefix, apiset, share_session, init, onevent);
+	desc->service = afb_svc_create(desc->binding->v1.prefix, apiset, share_session, onevent, NULL);
 	if (desc->service == NULL) {
-		/* starting error */
-		ERROR("Starting service %s failed", desc->binding->v1.prefix);
+		ERROR("Creation of service %s failed", desc->binding->v1.prefix);
 		return -1;
 	}
 
+	/* Starts the service */
+	rc = afb_svc_start_v1(desc->service, init);
+	if (rc < 0) {
+		/* initialisation error */
+		ERROR("Initialisation of service %s failed (%d): %m", desc->binding->v1.prefix, rc);
+		afb_svc_destroy(desc->service, NULL);
+		desc->service = NULL;
+		return rc;
+	}
+
 	return 0;
 }
 
diff --git a/src/afb-api-so-v2.c b/src/afb-api-so-v2.c
index bc5ecdf7..038f1ce2 100644
--- a/src/afb-api-so-v2.c
+++ b/src/afb-api-so-v2.c
@@ -103,6 +103,7 @@ static void call_sync_cb(void *closure, struct afb_xreq *xreq)
 
 static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
 {
+	int rc;
 	int (*start)();
 	void (*onevent)(const char *event, struct json_object *object);
 
@@ -133,13 +134,24 @@ static int service_start_cb(void *closure, int share_session, int onneed, struct
 	}
 
 	/* get the event handler if any */
-	desc->service = afb_svc_create_v2(desc->binding->api, apiset, share_session, start, onevent, desc->data);
+	desc->service = afb_svc_create(desc->binding->api, apiset, share_session, onevent, &desc->data->service);
 	if (desc->service == NULL) {
 		/* starting error */
 		ERROR("Starting service %s failed", desc->binding->api);
 		return -1;
 	}
 
+	/* Starts the service */
+	rc = afb_svc_start_v2(desc->service, start);
+	if (rc < 0) {
+		/* initialisation error */
+		ERROR("Initialisation of service %s failed (%d): %m", desc->binding->api, rc);
+		afb_svc_destroy(desc->service, &desc->data->service);
+		desc->service = NULL;
+		return rc;
+	}
+
+
 	return 0;
 }
 
diff --git a/src/afb-svc.c b/src/afb-svc.c
index 7d9f8dcb..212ecfa3 100644
--- a/src/afb-svc.c
+++ b/src/afb-svc.c
@@ -101,23 +101,29 @@ static inline struct afb_service to_afb_service(struct afb_svc *svc)
 /*
  * Frees a service
  */
-static void svc_free(struct afb_svc *svc)
+void afb_svc_destroy(struct afb_svc *svc, struct afb_service *service)
 {
-	if (svc->listener != NULL)
-		afb_evt_listener_unref(svc->listener);
-	if (svc->session)
-		afb_session_unref(svc->session);
-	afb_apiset_unref(svc->apiset);
-	free(svc);
+	if (service)
+		*service = (struct afb_service){ .itf = NULL, .closure = NULL };
+	if (svc) {
+		if (svc->listener != NULL)
+			afb_evt_listener_unref(svc->listener);
+		if (svc->session)
+			afb_session_unref(svc->session);
+		afb_apiset_unref(svc->apiset);
+		free(svc);
+	}
 }
 
 /*
- * Allocates a new service
+ * Creates a new service
  */
-static struct afb_svc *afb_svc_alloc(
+struct afb_svc *afb_svc_create(
 			const char *api,
 			struct afb_apiset *apiset,
-			int share_session
+			int share_session,
+			void (*on_event)(const char *event, struct json_object *object),
+			struct afb_service *service
 )
 {
 	struct afb_svc *svc;
@@ -150,31 +156,8 @@ static struct afb_svc *afb_svc_alloc(
 	}
 
 	svc->hookflags = afb_hook_flags_svc(svc->api);
-	return svc;
-
-error:
-	svc_free(svc);
-	return NULL;
-}
-
-/*
- * Creates a new service
- */
-struct afb_svc *afb_svc_create_v1(
-			const char *api,
-			struct afb_apiset *apiset,
-			int share_session,
-			int (*start)(struct afb_service service),
-			void (*on_event)(const char *event, struct json_object *object)
-)
-{
-	int rc;
-	struct afb_svc *svc;
-
-	/* allocates the svc handler */
-	svc = afb_svc_alloc(api, apiset, share_session);
-	if (svc == NULL)
-		goto error;
+	if (service)
+		*service = to_afb_service(svc);
 
 	/* initialises the listener if needed */
 	if (on_event) {
@@ -184,67 +167,42 @@ struct afb_svc *afb_svc_create_v1(
 			goto error;
 	}
 
-	/* initialises the svc now */
-	if (start) {
-		HOOK(start_before, svc);
-		rc = start(to_afb_service(svc));
-		HOOK(start_after, svc, rc);
-		if (rc < 0)
-			goto error;
-	}
-
 	return svc;
 
 error:
-	svc_free(svc);
+	afb_svc_destroy(svc, service);
 	return NULL;
 }
 
 /*
- * Creates a new service
+ * Starts a new service (v1)
  */
-struct afb_svc *afb_svc_create_v2(
-			const char *api,
-			struct afb_apiset *apiset,
-			int share_session,
-			int (*start)(),
-			void (*on_event)(const char *event, struct json_object *object),
-			struct afb_binding_data_v2 *data
-)
+int afb_svc_start_v1(struct afb_svc *svc, int (*start)(struct afb_service))
 {
 	int rc;
-	struct afb_svc *svc;
-
-	/* allocates the svc handler */
-	svc = afb_svc_alloc(api, apiset, share_session);
-	if (svc == NULL)
-		goto error;
-	data->service = to_afb_service(svc);
-
-	/* initialises the listener if needed */
-	if (on_event) {
-		svc->on_event = on_event;
-		svc->listener = afb_evt_listener_create(&evt_itf, svc);
-		if (svc->listener == NULL)
-			goto error;
-	}
 
-	/* starts the svc if needed */
-	if (start) {
-		HOOK(start_before, svc);
-		rc = start();
-		HOOK(start_after, svc, rc);
-		if (rc < 0)
-			goto error;
-	}
+	HOOK(start_before, svc);
+	rc = start(to_afb_service(svc));
+	HOOK(start_after, svc, rc);
+	return rc;
+}
 
-	return svc;
+/*
+ * Starts a new service (v2)
+ */
+int afb_svc_start_v2(struct afb_svc *svc, int (*start)())
+{
+	int rc;
 
-error:
-	svc_free(svc);
-	return NULL;
+	HOOK(start_before, svc);
+	rc = start();
+	HOOK(start_after, svc, rc);
+	return rc;
 }
 
+/*
+ * Request to updates the hooks
+ */
 void afb_svc_update_hook(struct afb_svc *svc)
 {
 	svc->hookflags = afb_hook_flags_svc(svc->api);
diff --git a/src/afb-svc.h b/src/afb-svc.h
index fb82e3c4..e23c2867 100644
--- a/src/afb-svc.h
+++ b/src/afb-svc.h
@@ -50,20 +50,17 @@ struct afb_svc
 	int hookflags;
 };
 
-extern struct afb_svc *afb_svc_create_v1(
-			const char *api,
-			struct afb_apiset *apiset,
-			int share_session,
-			int (*start)(struct afb_service service),
-			void (*on_event)(const char *event, struct json_object *object));
+extern void afb_svc_destroy(struct afb_svc *svc, struct afb_service *service);
 
-extern struct afb_svc *afb_svc_create_v2(
+extern struct afb_svc *afb_svc_create(
 			const char *api,
 			struct afb_apiset *apiset,
 			int share_session,
-			int (*start)(),
 			void (*on_event)(const char *event, struct json_object *object),
-			struct afb_binding_data_v2 *data);
+			struct afb_service *service);
+
+extern int afb_svc_start_v1(struct afb_svc *svc, int (*start)(struct afb_service));
+extern int afb_svc_start_v2(struct afb_svc *svc, int (*start)());
 
 extern void afb_svc_update_hook(struct afb_svc *svc);
 
-- 
cgit