2 * Copyright (C) 2016 "IoT.bzh"
3 * Author "Fulup Ar Foll"
4 * Author José Bollo <jose.bollo@iot.bzh>
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.
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.
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/>.
19 * Contain all generic part to handle REST/API
21 * https://www.gnu.org/software/libmicrohttpd/tutorial.html [search 'largepost.c']
33 #include <sys/types.h>
36 #include "../include/local-def.h"
41 AFB_plugin *plugin; /* descriptor */
44 void *handle; /* context of dlopen */
47 static struct api_desc *apis_array = NULL;
48 static int apis_count = 0;
50 static const char plugin_register_function[] = "pluginRegister";
57 void afb_apis_free_context(int apiidx, void *context)
61 assert(0 <= apiidx && apiidx < apis_count);
62 cb = apis_array[apiidx].plugin->freeCtxCB;
69 const struct AFB_restapi *afb_apis_get(int apiidx, int verbidx)
71 assert(0 <= apiidx && apiidx < apis_count);
72 return &apis_array[apiidx].plugin->apis[verbidx];
75 int afb_apis_get_verbidx(int apiidx, const char *name)
77 const struct AFB_restapi *apis;
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))
88 int afb_apis_get_apiidx(const char *prefix, size_t length)
91 const struct api_desc *a;
94 length = strlen(prefix);
96 for (i = 0 ; i < apis_count ; i++) {
98 if (a->prefixlen == length && !strcasecmp(a->prefix, prefix))
104 int afb_apis_add_plugin(const char *path)
106 struct api_desc *apis;
108 AFB_plugin *(*pluginRegisterFct) (void);
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);
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);
126 fprintf(stderr, "[%s] is a valid AFB plugin\n", path);
128 /* allocates enough memory */
129 apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis);
131 fprintf(stderr, "ERROR: plugin [%s] memory missing. continuing...\n", path);
136 /* init the plugin */
137 plugin = pluginRegisterFct();
138 if (plugin == NULL) {
139 fprintf(stderr, "ERROR: plugin [%s] register function failed. continuing...\n", path);
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);
148 if (plugin->prefix == NULL || *plugin->prefix == 0) {
149 fprintf(stderr, "ERROR: plugin [%s] bad prefix...\n", path);
152 if (plugin->info == NULL || *plugin->info == 0) {
153 fprintf(stderr, "ERROR: plugin [%s] bad description...\n", path);
156 if (plugin->apis == NULL) {
157 fprintf(stderr, "ERROR: plugin [%s] no APIs...\n", path);
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);
168 /* record the plugin */
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;
186 static int adddirs(char path[PATH_MAX], size_t end)
190 struct dirent ent, *result;
193 /* open the DIR now */
196 fprintf(stderr, "ERROR in scanning plugin directory %s, %m\n", path);
200 fprintf(stderr, "Scanning dir=[%s] for plugins\n", path);
202 /* scan each entry */
206 readdir_r(dir, &ent, &result);
210 len = strlen(ent.d_name);
211 if (len + end >= PATH_MAX) {
212 fprintf(stderr, "path too long for %s\n", ent.d_name);
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] == '.') {
221 if (ent.d_name[1] == '.' && len == 2)
224 rc = adddirs(path, end+len);;
225 } else if (ent.d_type == DT_REG) {
227 if (!strstr(ent.d_name, ".so"))
229 rc = afb_apis_add_plugin(path);
236 int afb_apis_add_directory(const char *path)
239 char buffer[PATH_MAX];
241 length = strlen(path);
242 if (length >= sizeof(buffer)) {
243 fprintf(stderr, "path too long %lu [%.99s...]\n", (unsigned long)length, path);
247 memcpy(buffer, path, length + 1);
248 return adddirs(buffer, length);
251 int afb_apis_add_path(const char *path)
256 rc = stat(path, &st);
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);
262 rc = afb_apis_add_plugin(path);
266 int afb_apis_add_pathset(const char *pathset)
268 static char sep[] = ":";
272 ps = strdupa(pathset);
274 p = strsep(&ps, sep);
277 rc = afb_apis_add_path(p);