removes session files
[src/app-framework-binder.git] / src / afb-apis.c
1 /*
2  * Copyright (C) 2016 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  * Author José Bollo <jose.bollo@iot.bzh>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  * 
19  * Contain all generic part to handle REST/API
20  * 
21  *  https://www.gnu.org/software/libmicrohttpd/tutorial.html [search 'largepost.c']
22  */
23
24 #define _GNU_SOURCE
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <dirent.h>
30 #include <dlfcn.h>
31 #include <unistd.h>
32 #include <limits.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include "../include/local-def.h"
37
38 #include "afb-apis.h"
39
40 struct api_desc {
41         AFB_plugin *plugin;     /* descriptor */
42         size_t prefixlen;
43         const char *prefix;
44         void *handle;           /* context of dlopen */
45 };
46
47 static struct api_desc *apis_array = NULL;
48 static int apis_count = 0;
49
50 static const char plugin_register_function[] = "pluginRegister";
51
52 int afb_apis_count()
53 {
54         return apis_count;
55 }
56
57 void afb_apis_free_context(int apiidx, void *context)
58 {
59         void (*cb)(void*);
60
61         assert(0 <= apiidx && apiidx < apis_count);
62         cb = apis_array[apiidx].plugin->freeCtxCB;
63         if (cb)
64                 cb(context);
65         else
66                 free(context);
67 }
68
69 const struct AFB_restapi *afb_apis_get(int apiidx, int verbidx)
70 {
71         assert(0 <= apiidx && apiidx < apis_count);
72         return &apis_array[apiidx].plugin->apis[verbidx];
73 }
74
75 int afb_apis_get_verbidx(int apiidx, const char *name)
76 {
77         const struct AFB_restapi *apis;
78         int idx;
79
80         assert(0 <= apiidx && apiidx < apis_count);
81         apis = apis_array[apiidx].plugin->apis;
82         for (idx = 0 ; apis[idx].name ; idx++)
83                 if (!strcasecmp(apis[idx].name, name))
84                         return idx;
85         return -1;
86 }
87
88 int afb_apis_get_apiidx(const char *prefix, size_t length)
89 {
90         int i;
91         const struct api_desc *a;
92
93         if (!length)
94                 length = strlen(prefix);
95
96         for (i = 0 ; i < apis_count ; i++) {
97                 a = &apis_array[i];
98                 if (a->prefixlen == length && !strcasecmp(a->prefix, prefix))
99                         return i;
100         }
101         return -1;
102 }
103
104 int afb_apis_add_plugin(const char *path)
105 {
106         struct api_desc *apis;
107         AFB_plugin *plugin;
108         AFB_plugin *(*pluginRegisterFct) (void);
109         void *handle;
110         size_t len;
111
112         // This is a loadable library let's check if it's a plugin
113         handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
114         if (handle == NULL) {
115                 fprintf(stderr, "[%s] not loadable, continuing...\n", path);
116                 goto error;
117         }
118
119         /* retrieves the register function */
120         pluginRegisterFct = dlsym(handle, plugin_register_function);
121         if (!pluginRegisterFct) {
122                 fprintf(stderr, "[%s] not an AFB plugin, continuing...\n", path);
123                 goto error2;
124         }
125         if (verbose)
126                 fprintf(stderr, "[%s] is a valid AFB plugin\n", path);
127
128         /* allocates enough memory */
129         apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis);
130         if (apis == NULL) {
131                 fprintf(stderr, "ERROR: plugin [%s] memory missing. continuing...\n", path);
132                 goto error2;
133         }
134         apis_array = apis;
135
136         /* init the plugin */
137         plugin = pluginRegisterFct();
138         if (plugin == NULL) {
139                 fprintf(stderr, "ERROR: plugin [%s] register function failed. continuing...\n", path);
140                 goto error2;
141         }
142
143         /* check the returned structure */
144         if (plugin->type != AFB_PLUGIN_JSON) {
145                 fprintf(stderr, "ERROR: plugin [%s] invalid type %d...\n", path, plugin->type);
146                 goto error2;
147         }
148         if (plugin->prefix == NULL || *plugin->prefix == 0) {
149                 fprintf(stderr, "ERROR: plugin [%s] bad prefix...\n", path);
150                 goto error2;
151         }
152         if (plugin->info == NULL || *plugin->info == 0) {
153                 fprintf(stderr, "ERROR: plugin [%s] bad description...\n", path);
154                 goto error2;
155         }
156         if (plugin->apis == NULL) {
157                 fprintf(stderr, "ERROR: plugin [%s] no APIs...\n", path);
158                 goto error2;
159         }
160
161         /* check previously existing plugin */
162         len = strlen(plugin->prefix);
163         if (afb_apis_get_apiidx(plugin->prefix, len) >= 0) {
164                 fprintf(stderr, "ERROR: plugin [%s] prefix %s duplicated...\n", path, plugin->prefix);
165                 goto error2;
166         }
167
168         /* record the plugin */
169         if (verbose)
170                 fprintf(stderr, "Loading plugin[%lu] prefix=[%s] info=%s\n", (unsigned long)apis_count, plugin->prefix, plugin->info);
171         apis = &apis_array[apis_count];
172         apis->plugin = plugin;
173         apis->prefixlen = len;
174         apis->prefix = plugin->prefix;
175         apis->handle = handle;
176         apis_count++;
177
178         return 0;
179
180 error2:
181         dlclose(handle);
182 error:
183         return -1;
184 }
185
186 static int adddirs(char path[PATH_MAX], size_t end)
187 {
188         int rc;
189         DIR *dir;
190         struct dirent ent, *result;
191         size_t len;
192
193         /* open the DIR now */
194         dir = opendir(path);
195         if (dir == NULL) {
196                 fprintf(stderr, "ERROR in scanning plugin directory %s, %m\n", path);
197                 return -1;
198         }
199         if (verbose)
200                 fprintf(stderr, "Scanning dir=[%s] for plugins\n", path);
201
202         /* scan each entry */
203         if (end)
204                 path[end++] = '/';
205         for (;;) {
206                 readdir_r(dir, &ent, &result);
207                 if (result == NULL)
208                         break;
209
210                 len = strlen(ent.d_name);
211                 if (len + end >= PATH_MAX) {
212                         fprintf(stderr, "path too long for %s\n", ent.d_name);
213                         continue;
214                 }
215                 memcpy(&path[end], ent.d_name, len+1);
216                 if (ent.d_type == DT_DIR) {
217                         /* case of directories */
218                         if (ent.d_name[0] == '.') {
219                                 if (len == 1)
220                                         continue;
221                                 if (ent.d_name[1] == '.' && len == 2)
222                                         continue;
223                         }
224                         rc = adddirs(path, end+len);;
225                 } else if (ent.d_type == DT_REG) {
226                         /* case of files */
227                         if (!strstr(ent.d_name, ".so"))
228                                 continue;
229                         rc = afb_apis_add_plugin(path);
230                 }
231         }
232         closedir(dir);
233         return 0;
234 }
235
236 int afb_apis_add_directory(const char *path)
237 {
238         size_t length;
239         char buffer[PATH_MAX];
240
241         length = strlen(path);
242         if (length >= sizeof(buffer)) {
243                 fprintf(stderr, "path too long %lu [%.99s...]\n", (unsigned long)length, path);
244                 return -1;
245         }
246
247         memcpy(buffer, path, length + 1);
248         return adddirs(buffer, length);
249 }
250
251 int afb_apis_add_path(const char *path)
252 {
253         struct stat st;
254         int rc;
255
256         rc = stat(path, &st);
257         if (rc < 0)
258                 fprintf(stderr, "Invalid plugin path [%s]: %m\n", path);
259         else if (S_ISDIR(st.st_mode))
260                 rc = afb_apis_add_directory(path);
261         else
262                 rc = afb_apis_add_plugin(path);
263         return rc;
264 }
265
266 int afb_apis_add_pathset(const char *pathset)
267 {
268         static char sep[] = ":";
269         char *ps, *p;
270         int rc;
271
272         ps = strdupa(pathset);
273         for (;;) {
274                 p = strsep(&ps, sep);
275                 if (!p)
276                         return 0;
277                 rc = afb_apis_add_path(p);
278         };
279 }
280