e6b6857c48154f004583e37db3a652e161dfd633
[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 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
20
21 #include <string.h>
22 #include <errno.h>
23
24 #include <json-c/json.h>
25
26 #include <afb/afb-binding.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 = old_vverbose_cb,
180         .event_make = event_make_cb,
181         .event_broadcast = event_broadcast_cb,
182         .get_event_loop = afb_common_get_event_loop,
183         .get_user_bus = afb_common_get_user_bus,
184         .get_system_bus = afb_common_get_system_bus,
185         .rootdir_get_fd = afb_common_rootdir_get_fd,
186         .rootdir_open_locale = rootdir_open_locale_cb,
187         .queue_job = queue_job_cb
188 };
189
190 static const struct afb_daemon_itf hooked_daemon_itf = {
191         .vverbose = hooked_old_vverbose_cb,
192         .event_make = hooked_event_make_cb,
193         .event_broadcast = hooked_event_broadcast_cb,
194         .get_event_loop = hooked_get_event_loop,
195         .get_user_bus = hooked_get_user_bus,
196         .get_system_bus = hooked_get_system_bus,
197         .rootdir_get_fd = hooked_rootdir_get_fd,
198         .rootdir_open_locale = hooked_rootdir_open_locale_cb,
199         .queue_job = hooked_queue_job_cb
200 };
201
202 void afb_ditf_init_v2(struct afb_ditf *ditf, const char *prefix)
203 {
204         ditf->version = 2;
205         ditf->daemon.closure = ditf;
206         afb_ditf_rename(ditf, prefix);
207 }
208
209 void afb_ditf_init_v1(struct afb_ditf *ditf, const char *prefix)
210 {
211         ditf->version = 1;
212         ditf->interface.verbosity = verbosity;
213         ditf->interface.mode = AFB_MODE_LOCAL;
214         ditf->interface.daemon.closure = ditf;
215         afb_ditf_rename(ditf, prefix);
216 }
217
218 void afb_ditf_rename(struct afb_ditf *ditf, const char *prefix)
219 {
220         ditf->prefix = prefix;
221         afb_ditf_update_hook(ditf);
222 }
223
224 void afb_ditf_update_hook(struct afb_ditf *ditf)
225 {
226         int hooked = !!afb_hook_flags_ditf(ditf->prefix);
227         switch (ditf->version) {
228         case 1:
229                 ditf->interface.daemon.itf = hooked ? &hooked_daemon_itf : &daemon_itf;
230                 break;
231         default:
232         case 2:
233                 ditf->daemon.itf = hooked ? &hooked_daemon_itf : &daemon_itf;
234                 break;
235         }
236 }
237