Add credential data to xreq
[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
22 #include <json-c/json.h>
23
24 #include <afb/afb-req-itf.h>
25 #include <afb/afb-service-itf.h>
26
27 #include "afb-session.h"
28 #include "afb-context.h"
29 #include "afb-evt.h"
30 #include "afb-msg-json.h"
31 #include "afb-svc.h"
32 #include "afb-xreq.h"
33 #include "afb-cred.h"
34 #include "afb-apis.h"
35 #include "verbose.h"
36
37 /*
38  * Structure for recording service
39  */
40 struct afb_svc
41 {
42         /* session of the service */
43         struct afb_session *session;
44
45         /* event listener of the service or NULL */
46         struct afb_evt_listener *listener;
47
48         /* on event callback for the service */
49         void (*on_event)(const char *event, struct json_object *object);
50 };
51
52 /*
53  * Structure for requests initiated by the service
54  */
55 struct svc_req
56 {
57         struct afb_xreq xreq;
58
59         /* the args */
60         void (*callback)(void*, int, struct json_object*);
61         void *closure;
62 };
63
64 /* functions for services */
65 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object);
66 static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
67                                 void (*callback)(void*, int, struct json_object*), void *cbclosure);
68
69 /* the interface for services */
70 static const struct afb_service_itf service_itf = {
71         .call = svc_call
72 };
73
74 /* the interface for events */
75 static const struct afb_evt_itf evt_itf = {
76         .broadcast = svc_on_event,
77         .push = svc_on_event
78 };
79
80 /* functions for requests of services */
81 static void svcreq_destroy(struct afb_xreq *xreq);
82 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj);
83
84 /* interface for requests of services */
85 const struct afb_xreq_query_itf afb_svc_xreq_itf = {
86         .unref = svcreq_destroy,
87         .reply = svcreq_reply
88 };
89
90 /* the common session for services sharing their session */
91 static struct afb_session *common_session;
92
93 /*
94  * Allocates a new service
95  */
96 static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const char *event, struct json_object *object))
97 {
98         struct afb_svc *svc;
99
100         /* allocates the svc handler */
101         svc = malloc(sizeof * svc);
102         if (svc == NULL)
103                 goto error;
104
105         /* instanciate the session */
106         if (share_session) {
107                 /* session shared with other svcs */
108                 if (common_session == NULL) {
109                         common_session = afb_session_create (NULL, 0);
110                         if (common_session == NULL)
111                                 goto error2;
112                 }
113                 svc->session = afb_session_addref(common_session);
114         } else {
115                 /* session dedicated to the svc */
116                 svc->session = afb_session_create (NULL, 0);
117                 if (svc->session == NULL)
118                         goto error2;
119         }
120
121         /* initialises the listener if needed */
122         svc->on_event = on_event;
123         if (on_event == NULL)
124                 svc->listener = NULL;
125         else {
126                 svc->listener = afb_evt_listener_create(&evt_itf, svc);
127                 if (svc->listener == NULL)
128                         goto error3;
129         }
130
131         return svc;
132
133 error3:
134         afb_session_unref(svc->session);
135 error2:
136         free(svc);
137 error:
138         return NULL;
139 }
140
141 /*
142  * Creates a new service
143  */
144 struct afb_svc *afb_svc_create(int share_session, int (*init)(struct afb_service service), void (*on_event)(const char *event, struct json_object *object))
145 {
146         int rc;
147         struct afb_svc *svc;
148
149         /* allocates the svc handler */
150         svc = afb_svc_alloc(share_session, on_event);
151         if (svc == NULL)
152                 goto error;
153
154         /* initialises the svc now */
155         rc = init((struct afb_service){ .itf = &service_itf, .closure = svc });
156         if (rc < 0)
157                 goto error2;
158
159         return svc;
160
161 error2:
162         if (svc->listener != NULL)
163                 afb_evt_listener_unref(svc->listener);
164         afb_session_unref(svc->session);
165         free(svc);
166 error:
167         return NULL;
168 }
169
170 /*
171  * Creates a new service
172  */
173 struct afb_svc *afb_svc_create_v2(
174                         int share_session,
175                         void (*on_event)(const char *event, struct json_object *object),
176                         int (*start)(const struct afb_binding_interface *interface, struct afb_service service),
177                         const struct afb_binding_interface *interface)
178 {
179         int rc;
180         struct afb_svc *svc;
181
182         /* allocates the svc handler */
183         svc = afb_svc_alloc(share_session, on_event);
184         if (svc == NULL)
185                 goto error;
186
187         /* initialises the svc now */
188         rc = start(interface, (struct afb_service){ .itf = &service_itf, .closure = svc });
189         if (rc < 0)
190                 goto error2;
191
192         return svc;
193
194 error2:
195         if (svc->listener != NULL)
196                 afb_evt_listener_unref(svc->listener);
197         afb_session_unref(svc->session);
198         free(svc);
199 error:
200         return NULL;
201 }
202
203 /*
204  * Propagates the event to the service
205  */
206 static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object)
207 {
208         struct afb_svc *svc = closure;
209         svc->on_event(event, object);
210         json_object_put(object);
211 }
212
213 /*
214  * Initiates a call for the service
215  */
216 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)
217 {
218         struct afb_svc *svc = closure;
219         struct svc_req *svcreq;
220
221         /* allocates the request */
222         svcreq = calloc(1, sizeof *svcreq);
223         if (svcreq == NULL) {
224                 ERROR("out of memory");
225                 json_object_put(args);
226                 callback(cbclosure, 1, afb_msg_json_internal_error());
227                 return;
228         }
229
230         /* initialises the request */
231         afb_xreq_init(&svcreq->xreq, &afb_svc_xreq_itf);
232         afb_context_init(&svcreq->xreq.context, svc->session, NULL);
233         svcreq->xreq.context.validated = 1;
234         svcreq->xreq.cred = afb_cred_current();
235         svcreq->xreq.api = api;
236         svcreq->xreq.verb = verb;
237         svcreq->xreq.listener = svc->listener;
238         svcreq->xreq.json = args;
239         svcreq->callback = callback;
240         svcreq->closure = cbclosure;
241
242         /* terminates and frees ressources if needed */
243         afb_apis_call(&svcreq->xreq);
244         afb_xreq_unref(&svcreq->xreq);
245 }
246
247 static void svcreq_destroy(struct afb_xreq *xreq)
248 {
249         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
250         afb_context_disconnect(&svcreq->xreq.context);
251         json_object_put(svcreq->xreq.json);
252         afb_cred_unref(svcreq->xreq.cred);
253         free(svcreq);
254 }
255
256 static void svcreq_reply(struct afb_xreq *xreq, int iserror, json_object *obj)
257 {
258         struct svc_req *svcreq = CONTAINER_OF_XREQ(struct svc_req, xreq);
259         svcreq->callback(svcreq->closure, iserror, obj);
260         json_object_put(obj);
261 }
262