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