gam-resource-manager: adjust to updated proxied call callback signature.
[profile/ivi/murphy.git] / src / core / method.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *   * Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *   * Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *   * Neither the name of Intel Corporation nor the names of its contributors
14  *     may be used to endorse or promote products derived from this software
15  *     without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <errno.h>
31
32 #include <murphy/common/macros.h>
33 #include <murphy/common/log.h>
34 #include <murphy/common/debug.h>
35 #include <murphy/common/mm.h>
36 #include <murphy/common/list.h>
37 #include <murphy/common/hashtbl.h>
38 #include <murphy/common/utils.h>
39 #include <murphy/core/plugin.h>
40 #include <murphy/core/method.h>
41
42
43 typedef struct {
44     char            *name;               /* name of methods in this chain */
45     mrp_list_hook_t  methods;            /* list of exported methods */
46 } method_list_t;
47
48
49 typedef struct {
50     __MRP_METHOD_FIELDS();               /* method fields */
51     mrp_list_hook_t hook;                /* to method table */
52 } method_t;
53
54
55 static void purge_method_list(void *key, void *object);
56
57
58 static mrp_htbl_t *methods = NULL;       /* hash table of method lists */
59
60
61 static int create_method_table(void)
62 {
63     mrp_htbl_config_t hcfg;
64
65     mrp_clear(&hcfg);
66     hcfg.comp = mrp_string_comp;
67     hcfg.hash = mrp_string_hash;
68     hcfg.free = purge_method_list;
69
70     methods = mrp_htbl_create(&hcfg);
71
72     if (methods != NULL)
73         return 0;
74     else
75         return -1;
76 }
77
78
79 MRP_EXIT static void destroy_method_table(void)
80 {
81     mrp_htbl_destroy(methods, TRUE);
82     methods = NULL;
83 }
84
85
86 static void free_method(method_t *m)
87 {
88     if (m != NULL) {
89         mrp_free(m->name);
90         mrp_free(m->signature);
91         mrp_free(m);
92     }
93 }
94
95
96 static method_t *alloc_method(mrp_method_descr_t *method)
97 {
98     method_t *m;
99
100     m = mrp_allocz(sizeof(*m));
101
102     if (m != NULL) {
103         mrp_list_init(&m->hook);
104         m->name      = mrp_strdup(method->name);
105         m->signature = mrp_strdup(method->signature);
106
107         if (m->name != NULL &&
108             (m->signature != NULL || method->signature == NULL)) {
109             m->native_ptr = method->native_ptr;
110             m->script_ptr = method->script_ptr;
111             m->plugin     = method->plugin;
112         }
113         else {
114             free_method(m);
115             m = NULL;
116         }
117     }
118
119     return m;
120 }
121
122
123 static method_list_t *create_method_list(const char *name)
124 {
125     method_list_t *l;
126
127     if (MRP_UNLIKELY(methods == NULL)) {
128         if (create_method_table() < 0)
129             return NULL;
130     }
131
132     l = mrp_allocz(sizeof(*l));
133
134     if (l != NULL) {
135         mrp_list_init(&l->methods);
136         l->name = mrp_strdup(name);
137
138         if (l->name != NULL) {
139             if (mrp_htbl_insert(methods, (void *)l->name, (void *)l))
140                 return l;
141         }
142
143         mrp_free(l->name);
144         mrp_free(l);
145     }
146
147     return NULL;
148 }
149
150
151 static void free_method_list(method_list_t *l)
152 {
153     mrp_list_hook_t *p, *n;
154     method_t        *m;
155
156     if (l != NULL) {
157         mrp_list_foreach(&l->methods, p, n) {
158             m = mrp_list_entry(p, typeof(*m), hook);
159
160             mrp_list_delete(&m->hook);
161             free_method(m);
162         }
163
164         mrp_free(l->name);
165         mrp_free(l);
166     }
167 }
168
169
170 static void purge_method_list(void *key, void *object)
171 {
172     MRP_UNUSED(key);
173
174     free_method_list(object);
175 }
176
177
178 static method_list_t *lookup_method_list(const char *name)
179 {
180     method_list_t *l;
181
182     if (methods != NULL)
183         l = mrp_htbl_lookup(methods, (void *)name);
184     else
185         l = NULL;
186
187     return l;
188 }
189
190
191 static inline int check_signatures(const char *sig1, const char *sig2)
192 {
193     static int warned = FALSE;
194
195     MRP_UNUSED(sig1);
196     MRP_UNUSED(sig2);
197
198     if (!warned) {
199         mrp_log_warning("XXX TODO: implement signature checking (%s@%s:%d)",
200                         __FUNCTION__, __FILE__, __LINE__);
201         warned = TRUE;
202     }
203
204     return TRUE;
205 }
206
207
208 static method_t *lookup_method(const char *name, const char *signature,
209                                void *native_ptr,
210                                int (*script_ptr)(mrp_plugin_t *plugin,
211                                                  const char *name,
212                                                  mrp_script_env_t *env),
213                                mrp_plugin_t *plugin)
214 {
215     method_list_t   *l;
216     method_t        *m;
217     mrp_list_hook_t *p, *n;
218
219     l = lookup_method_list(name);
220
221     if (l != NULL) {
222         mrp_list_foreach(&l->methods, p, n) {
223             m = mrp_list_entry(p, typeof(*m), hook);
224
225             if (((m->signature == NULL && signature == NULL) ||
226                  (m->signature != NULL && signature != NULL &&
227                   !strcmp(m->signature, signature))) &&
228                 m->native_ptr == native_ptr && m->script_ptr == script_ptr &&
229                 m->plugin == plugin)
230                 return m;
231         }
232     }
233
234     return NULL;
235 }
236
237
238 method_t *find_method(const char *name, const char *signature)
239 {
240     method_list_t   *l;
241     method_t        *m;
242     mrp_list_hook_t *p, *n;
243     const char      *base;
244     int              plen;
245
246     base = strrchr(name, '.');
247     if (base != NULL) {
248         plen = base - name;
249         base = base + 1;
250     }
251     else {
252         base = name;
253         plen = 0;
254     }
255
256     l = lookup_method_list(base);
257
258     if (l != NULL) {
259         mrp_list_foreach(&l->methods, p, n) {
260             m = mrp_list_entry(p, typeof(*m), hook);
261
262             if (signature != NULL && m->signature != NULL)
263                 if (!check_signatures(signature, m->signature))
264                     continue;
265
266             if (plen != 0) {
267                 if (m->plugin == NULL)
268                     continue;
269                 if (strncmp(name, m->plugin->instance, plen) ||
270                     m->plugin->instance[plen] != '\0')
271                     continue;
272             }
273
274             return m;
275         }
276     }
277
278     errno = ENOENT;
279     return NULL;
280 }
281
282
283 static int export_method(method_t *method)
284 {
285     method_list_t *l;
286
287     l = lookup_method_list(method->name);
288
289     if (l == NULL) {
290         l = create_method_list(method->name);
291
292         if (l == NULL)
293             return -1;
294     }
295
296     mrp_ref_plugin(method->plugin);
297     mrp_list_append(&l->methods, &method->hook);
298
299     return 0;
300 }
301
302
303 static int remove_method(const char *name, const char *signature,
304                          void *native_ptr,
305                          int (*script_ptr)(mrp_plugin_t *plugin,
306                                            const char *name,
307                                            mrp_script_env_t *env),
308                          mrp_plugin_t *plugin)
309 {
310     method_t *m;
311
312     m = lookup_method(name, signature, native_ptr, script_ptr, plugin);
313
314     if (m != NULL) {
315         mrp_list_delete(&m->hook);
316         mrp_unref_plugin(m->plugin);
317         free_method(m);
318
319         return 0;
320     }
321     else {
322         errno = ENOENT;
323         return -1;
324     }
325 }
326
327
328 int mrp_export_method(mrp_method_descr_t *method)
329 {
330     method_t *m;
331
332     if (lookup_method(method->name, method->signature,
333                       method->native_ptr, method->script_ptr,
334                       method->plugin) != NULL)
335         errno = EEXIST;
336     else {
337         m = alloc_method(method);
338
339         if (m != NULL) {
340             if (export_method(m) == 0) {
341                 mrp_log_info("exported method %s (%s) %s%s.",
342                              method->name,
343                              method->signature ? method->signature : "-",
344                              method->plugin ? "from plugin " : "",
345                              method->plugin ? method->plugin->instance : "");
346                 return 0;
347             }
348             else
349                 free_method(m);
350         }
351     }
352
353     mrp_log_error("Failed to export method %s (%s) %s%s.",
354                   method->name, method->signature,
355                   method->plugin ? "from plugin " : "",
356                   method->plugin ? method->plugin->instance : "");
357
358     return -1;
359 }
360
361
362 int mrp_remove_method(mrp_method_descr_t *method)
363 {
364     return remove_method(method->name, method->signature,
365                          method->native_ptr, method->script_ptr,
366                          method->plugin);
367 }
368
369
370 int mrp_import_method(const char *name, const char *signature,
371                       void **native_ptr,
372                       int (**script_ptr)(mrp_plugin_t *plugin, const char *name,
373                                          mrp_script_env_t *env),
374                       mrp_plugin_t **plugin)
375 {
376     method_t *m;
377
378     if ((script_ptr != NULL && plugin == NULL) ||
379         (script_ptr == NULL && plugin != NULL)) {
380         errno = EINVAL;
381         return -1;
382     }
383
384     m = find_method(name, signature);
385
386     if (m == NULL) {
387         errno = ENOENT;
388         return -1;
389     }
390
391     if ((native_ptr != NULL && m->native_ptr == NULL) ||
392         (script_ptr != NULL && m->script_ptr == NULL)) {
393         errno = EINVAL;
394         return -1;
395     }
396
397     mrp_ref_plugin(m->plugin);
398
399     if (native_ptr != NULL)
400         *native_ptr = m->native_ptr;
401     if (script_ptr != NULL) {
402         *script_ptr = m->script_ptr;
403         *plugin     = m->plugin;
404     }
405
406     return 0;
407 }
408
409
410 int mrp_release_method(const char *name, const char *signature,
411                        void **native_ptr,
412                        int (**script_ptr)(mrp_plugin_t *plugin,
413                                           const char *name,
414                                           mrp_script_env_t *env))
415 {
416     method_t *m;
417
418     m = find_method(name, signature);
419
420     if (m == NULL) {
421         errno = ENOENT;
422         return -1;
423     }
424
425     if ((native_ptr != NULL && (*native_ptr != m->native_ptr)) ||
426         (script_ptr != NULL && (*script_ptr != m->script_ptr))) {
427         errno = EINVAL;
428         return -1;
429     }
430
431     mrp_unref_plugin(m->plugin);
432
433     if (native_ptr != NULL)
434         *native_ptr = NULL;
435     if (script_ptr != NULL)
436         *script_ptr = NULL;
437
438     return 0;
439 }