474c58cf57c17a58337946a426ceac22dbb57e94
[src/app-framework-binder.git] / src / afb-ditf.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 <string.h>
21 #include <errno.h>
22
23 #include <json-c/json.h>
24
25 #include <afb/afb-binding-v1.h>
26 #include <afb/afb-binding-v2.h>
27
28 #include "afb-ditf.h"
29 #include "afb-evt.h"
30 #include "afb-common.h"
31 #include "afb-hook.h"
32 #include "jobs.h"
33 #include "verbose.h"
34
35 /**********************************************
36 * normal flow
37 **********************************************/
38 static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
39 {
40         char *p;
41         struct afb_ditf *ditf = closure;
42
43         if (vasprintf(&p, fmt, args) < 0)
44                 vverbose(level, file, line, function, fmt, args);
45         else {
46                 verbose(level, file, line, function, "%s {binding %s}", p, ditf->prefix);
47                 free(p);
48         }
49 }
50
51 static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
52 {
53         vverbose_cb(closure, level, file, line, "?", fmt, args);
54 }
55
56 static struct afb_event event_make_cb(void *closure, const char *name)
57 {
58         size_t plen, nlen;
59         char *event;
60         struct afb_ditf *ditf = closure;
61
62         /* makes the event name */
63         plen = strlen(ditf->prefix);
64         nlen = strlen(name);
65         event = alloca(nlen + plen + 2);
66         memcpy(event, ditf->prefix, plen);
67         event[plen] = '/';
68         memcpy(event + plen + 1, name, nlen + 1);
69
70         /* create the event */
71         return afb_evt_create_event(event);
72 }
73
74 static int event_broadcast_cb(void *closure, const char *name, struct json_object *object)
75 {
76         size_t plen, nlen;
77         char *event;
78         struct afb_ditf *ditf = closure;
79
80         /* makes the event name */
81         plen = strlen(ditf->prefix);
82         nlen = strlen(name);
83         event = alloca(nlen + plen + 2);
84         memcpy(event, ditf->prefix, plen);
85         event[plen] = '/';
86         memcpy(event + plen + 1, name, nlen + 1);
87
88         /* broadcast the event */
89         return afb_evt_broadcast(event, object);
90 }
91
92 static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
93 {
94         return afb_common_rootdir_open_locale(filename, flags, locale);
95 }
96
97 static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
98 {
99         return jobs_queue(group, timeout, callback, argument);
100 }
101
102 /**********************************************
103 * hooked flow
104 **********************************************/
105 static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args)
106 {
107         struct afb_ditf *ditf = closure;
108         vverbose_cb(closure, level, file, line, function, fmt, args);
109         afb_hook_ditf_vverbose(ditf, level, file, line, function, fmt, args);
110 }
111
112 static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args)
113 {
114         hooked_vverbose_cb(closure, level, file, line, "?", fmt, args);
115 }
116
117 static struct afb_event hooked_event_make_cb(void *closure, const char *name)
118 {
119         struct afb_ditf *ditf = closure;
120         struct afb_event r = event_make_cb(closure, name);
121         return afb_hook_ditf_event_make(ditf, name, r);
122 }
123
124 static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object)
125 {
126         int r;
127         struct afb_ditf *ditf = closure;
128         json_object_get(object);
129         afb_hook_ditf_event_broadcast_before(ditf, name, json_object_get(object));
130         r = event_broadcast_cb(closure, name, object);
131         afb_hook_ditf_event_broadcast_after(ditf, name, object, r);
132         json_object_put(object);
133         return r;
134 }
135
136 static struct sd_event *hooked_get_event_loop(void *closure)
137 {
138         struct afb_ditf *ditf = closure;
139         struct sd_event *r = afb_common_get_event_loop();
140         return afb_hook_ditf_get_event_loop(ditf, r);
141 }
142
143 static struct sd_bus *hooked_get_user_bus(void *closure)
144 {
145         struct afb_ditf *ditf = closure;
146         struct sd_bus *r = afb_common_get_user_bus();
147         return afb_hook_ditf_get_user_bus(ditf, r);
148 }
149
150 static struct sd_bus *hooked_get_system_bus(void *closure)
151 {
152         struct afb_ditf *ditf = closure;
153         struct sd_bus *r = afb_common_get_system_bus();
154         return afb_hook_ditf_get_system_bus(ditf, r);
155 }
156
157 static int hooked_rootdir_get_fd(void *closure)
158 {
159         struct afb_ditf *ditf = closure;
160         int r = afb_common_rootdir_get_fd();
161         return afb_hook_ditf_rootdir_get_fd(ditf, r);
162 }
163
164 static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale)
165 {
166         struct afb_ditf *ditf = closure;
167         int r = rootdir_open_locale_cb(closure, filename, flags, locale);
168         return afb_hook_ditf_rootdir_open_locale(ditf, filename, flags, locale, r);
169 }
170
171 static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout)
172 {
173         struct afb_ditf *ditf = closure;
174         int r = queue_job_cb(closure, callback, argument, group, timeout);
175         return afb_hook_ditf_queue_job(ditf, callback, argument, group, timeout, r);
176 }
177
178 static const struct afb_daemon_itf daemon_itf = {
179         .vverbose_v1 = old_vverbose_cb,
180         .vverbose_v2 = vverbose_cb,
181         .event_make = event_make_cb,
182         .event_broadcast = event_broadcast_cb,
183         .get_event_loop = afb_common_get_event_loop,
184         .get_user_bus = afb_common_get_user_bus,
185         .get_system_bus = afb_common_get_system_bus,
186         .rootdir_get_fd = afb_common_rootdir_get_fd,
187         .rootdir_open_locale = rootdir_open_locale_cb,
188         .queue_job = queue_job_cb
189 };
190
191 static const struct afb_daemon_itf hooked_daemon_itf = {
192         .vverbose_v1 = hooked_old_vverbose_cb,
193         .vverbose_v2 = hooked_vverbose_cb,
194         .event_make = hooked_event_make_cb,
195         .event_broadcast = hooked_event_broadcast_cb,
196         .get_event_loop = hooked_get_event_loop,
197         .get_user_bus = hooked_get_user_bus,
198         .get_system_bus = hooked_get_system_bus,
199         .rootdir_get_fd = hooked_rootdir_get_fd,
200         .rootdir_open_locale = hooked_rootdir_open_locale_cb,
201         .queue_job = hooked_queue_job_cb
202 };
203
204 void afb_ditf_init_v2(struct afb_ditf *ditf, const char *prefix, struct afb_binding_data_v2 *data)
205 {
206         ditf->version = 2;
207         ditf->v2 = data;
208         data->daemon.closure = ditf;
209         afb_ditf_rename(ditf, prefix);
210 }
211
212 void afb_ditf_init_v1(struct afb_ditf *ditf, const char *prefix, struct afb_binding_interface_v1 *itf)
213 {
214         ditf->version = 1;
215         ditf->v1 = itf;
216         itf->verbosity = verbosity;
217         itf->mode = AFB_MODE_LOCAL;
218         itf->daemon.closure = ditf;
219         afb_ditf_rename(ditf, prefix);
220 }
221
222 void afb_ditf_rename(struct afb_ditf *ditf, const char *prefix)
223 {
224         ditf->prefix = prefix;
225         afb_ditf_update_hook(ditf);
226 }
227
228 void afb_ditf_update_hook(struct afb_ditf *ditf)
229 {
230         int hooked = !!afb_hook_flags_ditf(ditf->prefix);
231         switch (ditf->version) {
232         case 1:
233                 ditf->v1->daemon.itf = hooked ? &hooked_daemon_itf : &daemon_itf;
234                 break;
235         default:
236         case 2:
237                 ditf->v2->daemon.itf = hooked ? &hooked_daemon_itf : &daemon_itf;
238                 break;
239         }
240 }
241