fad13286dc9328a72a35949f555e41b2ad7541db
[src/app-framework-binder.git] / src / afb-svc.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 <stdlib.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-session.h"
30 #include "afb-context.h"
31 #include "afb-evt.h"
32 #include "afb-msg-json.h"
33 #include "afb-svc.h"
34 #include "afb-xreq.h"
35 #include "afb-cred.h"
36 #include "afb-apiset.h"
37 #include "jobs.h"
38 #include "verbose.h"
39
40 /*
41  * Structure for recording service
42  */
43 struct afb_svc
44 {
45         /* api/prefix */
46         const char *api;
47
48         /* session of the service */
49         struct afb_session *session;
50
51         /* the apiset for the service */
52         struct afb_apiset *apiset;
53
54         /* event listener of the service or NULL */
55         struct afb_evt_listener *listener;
56
57         /* on event callback for the service */
58         void (*on_event)(const char *event, struct json_object *object);
59 };
60
61 /*
62  * Structure for requests initiated by the service
63  */
64 struct svc_req
65 {
66         struct afb_xreq xreq;
67
68         struct afb_svc *svc;
69
70         /* the args */
71         void (*callback)(void*, int, struct json_object*);
72         void *closure;
73
74         /* sync */
75         struct jobloop *jobloop;
76         struct json_object *result;
77         int iserror;
78 };
79
80 /* functions for services */
81 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object);
82 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
83                                 void (*callback)(void*, int, struct json_object*), void *cbclosure);
84 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
85                                 struct json_object **result);
86
87 /* the interface for services */
88 static const struct afb_service_itf service_itf = {
89         .call = svc_call,
90         .call_sync = svc_call_sync
91 };
92
93 /* the interface for events */
94 static const struct afb_evt_itf evt_itf = {
95         .broadcast = svc_on_event,
96         .push = svc_on_event
97 };
98
99 /* functions for requests of services */
100 static void svcreq_destroy(struct afb_xreq *xreq);
101 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj);
102
103 /* interface for requests of services */
104 const struct afb_xreq_query_itf afb_svc_xreq_itf = {
105         .unref = svcreq_destroy,
106         .reply = svcreq_reply
107 };
108
109 /* the common session for services sharing their session */
110 static struct afb_session *common_session;
111
112 static inline struct afb_service to_afb_service(struct afb_svc *svc)
113 {
114         return (struct afb_service){ .itf = &service_itf, .closure = svc };
115 }
116
117 /*
118  * Frees a service
119  */
120 static void svc_free(struct afb_svc *svc)
121 {
122         if (svc->listener != NULL)
123                 afb_evt_listener_unref(svc->listener);
124         if (svc->session)
125                 afb_session_unref(svc->session);
126         afb_apiset_unref(svc->apiset);
127         free(svc);
128 }
129
130 /*
131  * Allocates a new service
132  */
133 static struct afb_svc *afb_svc_alloc(
134                         const char *api,
135                         struct afb_apiset *apiset,
136                         int share_session
137 )
138 {
139         struct afb_svc *svc;
140
141         /* allocates the svc handler */
142         svc = calloc(1, sizeof * svc);
143         if (svc == NULL) {
144                 errno = ENOMEM;
145                 return NULL;
146         }
147
148         /* instanciate the apiset */
149         svc->api = api;
150         svc->apiset = afb_apiset_addref(apiset);
151
152         /* instanciate the session */
153         if (share_session) {
154                 /* session shared with other svcs */
155                 if (common_session == NULL) {
156                         common_session = afb_session_create (NULL, 0);
157                         if (common_session == NULL)
158                                 goto error;
159                 }
160                 svc->session = afb_session_addref(common_session);
161         } else {
162                 /* session dedicated to the svc */
163                 svc->session = afb_session_create (NULL, 0);
164                 if (svc->session == NULL)
165                         goto error;
166         }
167
168         return svc;
169
170 error:
171         svc_free(svc);
172         return NULL;
173 }
174
175 /*
176  * Creates a new service
177  */
178 struct afb_svc *afb_svc_create_v1(
179                         const char *api,
180                         struct afb_apiset *apiset,
181                         int share_session,
182                         int (*start)(struct afb_service service),
183                         void (*on_event)(const char *event, struct json_object *object)
184 )
185 {
186         int rc;
187         struct afb_svc *svc;
188
189         /* allocates the svc handler */
190         svc = afb_svc_alloc(api, apiset, share_session);
191         if (svc == NULL)
192                 goto error;
193
194         /* initialises the listener if needed */
195         if (on_event) {
196                 svc->on_event = on_event;
197                 svc->listener = afb_evt_listener_create(&evt_itf, svc);
198                 if (svc->listener == NULL)
199                         goto error;
200         }
201
202         /* initialises the svc now */
203         if (start) {
204                 rc = start(to_afb_service(svc));
205                 if (rc < 0)
206                         goto error;
207         }
208
209         return svc;
210
211 error:
212         svc_free(svc);
213         return NULL;
214 }
215
216 /*
217  * Creates a new service
218  */
219 struct afb_svc *afb_svc_create_v2(
220                         const char *api,
221                         struct afb_apiset *apiset,
222                         int share_session,
223                         int (*start)(),
224                         void (*on_event)(const char *event, struct json_object *object),
225                         struct afb_binding_data_v2 *data
226 )
227 {
228         int rc;
229         struct afb_svc *svc;
230
231         /* allocates the svc handler */
232         svc = afb_svc_alloc(api, apiset, share_session);
233         if (svc == NULL)
234                 goto error;
235         data->service = to_afb_service(svc);
236
237         /* initialises the listener if needed */
238         if (on_event) {
239                 svc->on_event = on_event;
240                 svc->listener = afb_evt_listener_create(&evt_itf, svc);
241                 if (svc->listener == NULL)
242                         goto error;
243         }
244
245         /* starts the svc if needed */
246         if (start) {
247                 rc = start();
248                 if (rc < 0)
249                         goto error;
250         }
251
252         return svc;
253
254 error:
255         svc_free(svc);
256         return NULL;
257 }
258
259 /*
260  * Propagates the event to the service
261  */
262 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object)
263 {
264         struct afb_svc *svc = closure;
265         svc->on_event(event, object);
266         json_object_put(object);
267 }
268
269 /*
270  * create an svc_req
271  */
272 static struct svc_req *svcreq_create(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args)
273 {
274         struct svc_req *svcreq;
275         size_t lenapi, lenverb;
276         char *copy;
277
278         /* allocates the request */
279         lenapi = 1 + strlen(api);
280         lenverb = 1 + strlen(verb);
281         svcreq = malloc(lenapi + lenverb + sizeof *svcreq);
282         if (svcreq != NULL) {
283                 /* initialises the request */
284                 afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf);
285                 afb_context_init(&svcreq->xreq.context, svc->session, NULL);
286                 svcreq->xreq.context.validated = 1;
287                 copy = (char*)&svcreq[1];
288                 memcpy(copy, api, lenapi);
289                 svcreq->xreq.api = copy;
290                 copy = &copy[lenapi];
291                 memcpy(copy, verb, lenverb);
292                 svcreq->xreq.verb = copy;
293                 svcreq->xreq.listener = svc->listener;
294                 svcreq->xreq.json = args;
295                 svcreq->svc = svc;
296         }
297         return svcreq;
298 }
299
300 /*
301  * destroys the svc_req
302  */
303 static void svcreq_destroy(struct afb_xreq *xreq)
304 {
305         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
306
307         afb_context_disconnect(&svcreq->xreq.context);
308         json_object_put(svcreq->xreq.json);
309         afb_cred_unref(svcreq->xreq.cred);
310         free(svcreq);
311 }
312
313 static void svcreq_sync_leave(struct svc_req *svcreq)
314 {
315         struct jobloop *jobloop = svcreq->jobloop;
316
317         if (jobloop) {
318                 svcreq->jobloop = NULL;
319                 jobs_leave(jobloop);
320         }
321 }
322
323 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj)
324 {
325         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
326         if (svcreq->callback) {
327                 svcreq->callback(svcreq->closure, iserror, obj);
328                 json_object_put(obj);
329         } else {
330                 svcreq->iserror = iserror;
331                 svcreq->result = obj;
332                 svcreq_sync_leave(svcreq);
333         }
334 }
335
336 static void svcreq_sync_enter(int signum, void *closure, struct jobloop *jobloop)
337 {
338         struct svc_req *svcreq = closure;
339
340         if (!signum) {
341                 svcreq->jobloop = jobloop;
342                 afb_xreq_process(&svcreq->xreq, svcreq->svc->apiset);
343         } else {
344                 svcreq->result = afb_msg_json_internal_error();
345                 svcreq->iserror = 1;
346                 svcreq_sync_leave(svcreq);
347         }
348 }
349
350 /*
351  * Initiates a call for the service
352  */
353 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)
354 {
355         struct afb_svc *svc = closure;
356         struct svc_req *svcreq;
357         struct json_object *ierr;
358
359         /* allocates the request */
360         svcreq = svcreq_create(svc, api, verb, args);
361         if (svcreq == NULL) {
362                 ERROR("out of memory");
363                 json_object_put(args);
364                 ierr = afb_msg_json_internal_error();
365                 callback(cbclosure, 1, ierr);
366                 json_object_put(ierr);
367                 return;
368         }
369
370         /* initialises the request */
371         svcreq->jobloop = NULL;
372         svcreq->callback = callback;
373         svcreq->closure = cbclosure;
374
375         /* terminates and frees ressources if needed */
376         afb_xreq_process(&svcreq->xreq, svc->apiset);
377 }
378
379 static int svc_call_sync(void *closure, const char *api, const char *verb, struct json_object *args,
380                                 struct json_object **result)
381 {
382         struct afb_svc *svc = closure;
383         struct svc_req *svcreq;
384         int rc;
385
386         /* allocates the request */
387         svcreq = svcreq_create(svc, api, verb, args);
388         if (svcreq == NULL) {
389                 ERROR("out of memory");
390                 errno = ENOMEM;
391                 json_object_put(args);
392                 *result = afb_msg_json_internal_error();
393                 return -1;
394         }
395
396         /* initialises the request */
397         svcreq->jobloop = NULL;
398         svcreq->callback = NULL;
399         svcreq->result = NULL;
400         svcreq->iserror = 1;
401         afb_xreq_addref(&svcreq->xreq);
402         rc = jobs_enter(NULL, 0, svcreq_sync_enter, svcreq);
403         rc = rc >= 0 && !svcreq->iserror;
404         *result = (rc || svcreq->result) ? svcreq->result : afb_msg_json_internal_error();
405         afb_xreq_unref(&svcreq->xreq);
406         return rc;
407 }
408