aboutsummaryrefslogtreecommitdiff
path: root/src/util/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/plugin.c')
-rw-r--r--src/util/plugin.c460
1 files changed, 0 insertions, 460 deletions
diff --git a/src/util/plugin.c b/src/util/plugin.c
deleted file mode 100644
index 6ee41eec9..000000000
--- a/src/util/plugin.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2002-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/plugin.c
23 * @brief Methods to access plugins
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include <ltdl.h>
29#include "gnunet_util_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-plugin", __VA_ARGS__)
32
33/**
34 * Linked list of active plugins.
35 */
36struct PluginList
37{
38 /**
39 * This is a linked list.
40 */
41 struct PluginList *next;
42
43 /**
44 * Name of the library.
45 */
46 char *name;
47
48 /**
49 * System handle.
50 */
51 void *handle;
52};
53
54
55/**
56 * Have we been initialized?
57 */
58static int initialized;
59
60/**
61 * Libtool search path before we started.
62 */
63static char *old_dlsearchpath;
64
65/**
66 * List of plugins we have loaded.
67 */
68static struct PluginList *plugins;
69
70
71/**
72 * Setup libtool paths.
73 */
74static void
75plugin_init (void)
76{
77 int err;
78 const char *opath;
79 char *path;
80 char *cpath;
81
82 err = lt_dlinit ();
83 if (err > 0)
84 {
85 fprintf (stderr,
86 _ ("Initialization of plugin mechanism failed: %s!\n"),
87 lt_dlerror ());
88 return;
89 }
90 opath = lt_dlgetsearchpath ();
91 if (NULL != opath)
92 old_dlsearchpath = GNUNET_strdup (opath);
93 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
94 if (NULL != path)
95 {
96 if (NULL != opath)
97 {
98 GNUNET_asprintf (&cpath,
99 "%s:%s",
100 opath,
101 path);
102 lt_dlsetsearchpath (cpath);
103 GNUNET_free (path);
104 GNUNET_free (cpath);
105 }
106 else
107 {
108 lt_dlsetsearchpath (path);
109 GNUNET_free (path);
110 }
111 }
112}
113
114
115/**
116 * Shutdown libtool.
117 */
118static void
119plugin_fini (void)
120{
121 lt_dlsetsearchpath (old_dlsearchpath);
122 if (NULL != old_dlsearchpath)
123 {
124 GNUNET_free (old_dlsearchpath);
125 old_dlsearchpath = NULL;
126 }
127 lt_dlexit ();
128}
129
130
131/**
132 * Lookup a function in the plugin.
133 *
134 * @param plug the plugin to check
135 * @param name name of the symbol to look for
136 * @return NULL if the symbol was not found
137 */
138static GNUNET_PLUGIN_Callback
139resolve_function (struct PluginList *plug,
140 const char *name)
141{
142 char *initName;
143 void *mptr;
144
145 GNUNET_asprintf (&initName,
146 "_%s_%s",
147 plug->name,
148 name);
149 mptr = lt_dlsym (plug->handle,
150 &initName[1]);
151 if (NULL == mptr)
152 mptr = lt_dlsym (plug->handle,
153 initName);
154 if (NULL == mptr)
155 LOG (GNUNET_ERROR_TYPE_ERROR,
156 _ ("`%s' failed to resolve method '%s' with error: %s\n"),
157 "lt_dlsym",
158 &initName[1],
159 lt_dlerror ());
160 GNUNET_free (initName);
161 return mptr;
162}
163
164
165/**
166 * Test if a plugin exists.
167 *
168 * Note that the library must export a symbol called
169 * `library_name_init` for the test to succeed.
170 *
171 * @param library_name name of the plugin to test if it is installed
172 * @return #GNUNET_YES if the plugin exists, #GNUNET_NO if not
173 */
174int
175GNUNET_PLUGIN_test (const char *library_name)
176{
177 void *libhandle;
178 GNUNET_PLUGIN_Callback init;
179 struct PluginList plug;
180
181 if (! initialized)
182 {
183 initialized = GNUNET_YES;
184 plugin_init ();
185 }
186 libhandle = lt_dlopenext (library_name);
187 if (NULL == libhandle)
188 return GNUNET_NO;
189 plug.handle = libhandle;
190 plug.name = (char *) library_name;
191 init = resolve_function (&plug,
192 "init");
193 if (NULL == init)
194 {
195 GNUNET_break (0);
196 lt_dlclose (libhandle);
197 return GNUNET_NO;
198 }
199 lt_dlclose (libhandle);
200 return GNUNET_YES;
201}
202
203
204/**
205 * Setup plugin (runs the `init` callback and returns whatever `init`
206 * returned). If `init` returns NULL, the plugin is unloaded.
207 *
208 * Note that the library must export symbols called
209 * `library_name_init` and `library_name_done`. These will be called
210 * when the library is loaded and unloaded respectively.
211 *
212 * @param library_name name of the plugin to load
213 * @param arg argument to the plugin initialization function
214 * @return whatever the initialization function returned
215 */
216void *
217GNUNET_PLUGIN_load (const char *library_name,
218 void *arg)
219{
220 void *libhandle;
221 struct PluginList *plug;
222 GNUNET_PLUGIN_Callback init;
223 void *ret;
224
225 if (! initialized)
226 {
227 initialized = GNUNET_YES;
228 plugin_init ();
229 }
230 libhandle = lt_dlopenext (library_name);
231 if (NULL == libhandle)
232 {
233 LOG (GNUNET_ERROR_TYPE_ERROR,
234 _ ("`%s' failed for library `%s' with error: %s\n"),
235 "lt_dlopenext",
236 library_name,
237 lt_dlerror ());
238 return NULL;
239 }
240 plug = GNUNET_new (struct PluginList);
241 plug->handle = libhandle;
242 plug->name = GNUNET_strdup (library_name);
243 plug->next = plugins;
244 plugins = plug;
245 init = resolve_function (plug,
246 "init");
247 if ( (NULL == init) ||
248 (NULL == (ret = init (arg))) )
249 {
250 lt_dlclose (libhandle);
251 GNUNET_free (plug->name);
252 plugins = plug->next;
253 GNUNET_free (plug);
254 return NULL;
255 }
256 return ret;
257}
258
259
260/**
261 * Unload plugin (runs the `done` callback and returns whatever `done`
262 * returned). The plugin is then unloaded.
263 *
264 * @param library_name name of the plugin to unload
265 * @param arg argument to the plugin shutdown function
266 * @return whatever the shutdown function returned
267 */
268void *
269GNUNET_PLUGIN_unload (const char *library_name,
270 void *arg)
271{
272 struct PluginList *pos;
273 struct PluginList *prev;
274 GNUNET_PLUGIN_Callback done;
275 void *ret;
276
277 prev = NULL;
278 pos = plugins;
279 while ( (NULL != pos) &&
280 (0 != strcmp (pos->name,
281 library_name)) )
282 {
283 prev = pos;
284 pos = pos->next;
285 }
286 if (NULL == pos)
287 return NULL;
288
289 done = resolve_function (pos,
290 "done");
291 ret = NULL;
292 if (NULL == prev)
293 plugins = pos->next;
294 else
295 prev->next = pos->next;
296 if (NULL != done)
297 ret = done (arg);
298 lt_dlclose (pos->handle);
299 GNUNET_free (pos->name);
300 GNUNET_free (pos);
301 if (NULL == plugins)
302 {
303 plugin_fini ();
304 initialized = GNUNET_NO;
305 }
306 return ret;
307}
308
309
310/**
311 * Closure for #find_libraries().
312 */
313struct LoadAllContext
314{
315 /**
316 * Prefix the plugin names we find have to match.
317 */
318 const char *basename;
319
320 /**
321 * Argument to give to 'init' when loading the plugin.
322 */
323 void *arg;
324
325 /**
326 * Function to call for each plugin.
327 */
328 GNUNET_PLUGIN_LoaderCallback cb;
329
330 /**
331 * Closure for @e cb
332 */
333 void *cb_cls;
334};
335
336
337/**
338 * Function called on each plugin in the directory. Loads
339 * the plugins that match the given basename.
340 *
341 * @param cls the `struct LoadAllContext` describing which
342 * plugins to load and what to do with them
343 * @param filename name of a plugin library to check
344 * @return #GNUNET_OK (continue loading)
345 */
346static int
347find_libraries (void *cls,
348 const char *filename)
349{
350 struct LoadAllContext *lac = cls;
351 const char *slashpos;
352 const char *libname;
353 char *basename;
354 char *dot;
355 void *lib_ret;
356 size_t n;
357
358 libname = filename;
359 while (NULL != (slashpos = strstr (libname,
360 DIR_SEPARATOR_STR)))
361 libname = slashpos + 1;
362 n = strlen (libname);
363 if (0 != strncmp (lac->basename,
364 libname,
365 strlen (lac->basename)))
366 return GNUNET_OK; /* wrong name */
367 if ( (n > 3) &&
368 (0 == strcmp (&libname[n - 3], ".la")) )
369 return GNUNET_OK; /* .la file */
370 basename = GNUNET_strdup (libname);
371 if (NULL != (dot = strstr (basename, ".")))
372 *dot = '\0';
373 lib_ret = GNUNET_PLUGIN_load (basename,
374 lac->arg);
375 if (NULL != lib_ret)
376 lac->cb (lac->cb_cls,
377 basename,
378 lib_ret);
379 GNUNET_free (basename);
380 return GNUNET_OK;
381}
382
383
384/**
385 * Load all compatible plugins with the given base name.
386 *
387 * Note that the library must export symbols called
388 * `basename_ANYTHING_init` and `basename_ANYTHING__done`. These will
389 * be called when the library is loaded and unloaded respectively.
390 *
391 * If you are writing a service to which third-party applications can connect,
392 * like GNUnet's own GNS service for example, you should use
393 * #GNUNET_PLUGIN_load_all_in_context instead of this function, passing your
394 * service's project data as context.
395 *
396 * @param basename basename of the plugins to load
397 * @param arg argument to the plugin initialization function
398 * @param cb function to call for each plugin found
399 * @param cb_cls closure for @a cb
400 */
401void
402GNUNET_PLUGIN_load_all (const char *basename,
403 void *arg,
404 GNUNET_PLUGIN_LoaderCallback cb,
405 void *cb_cls)
406{
407 struct LoadAllContext lac;
408 char *path;
409
410 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
411 if (NULL == path)
412 {
413 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414 _ ("Could not determine plugin installation path.\n"));
415 return;
416 }
417 lac.basename = basename;
418 lac.arg = arg;
419 lac.cb = cb;
420 lac.cb_cls = cb_cls;
421 GNUNET_DISK_directory_scan (path,
422 &find_libraries,
423 &lac);
424 GNUNET_free (path);
425}
426
427
428/**
429 * Load all compatible plugins with the given base name while inside the given
430 * context (i.e. a specific project data structure.)
431 *
432 * Note that the library must export symbols called `basename_ANYTHING_init`
433 * and `basename_ANYTHING__done`. These will be called when the library is
434 * loaded and unloaded respectively.
435 *
436 * @param ctx the context used to find the plugins
437 * @param basename basename of the plugins to load
438 * @param arg argument to the plugin initialization function
439 * @param cb function to call for each plugin found
440 * @param cb_cls closure for @a cb
441 */
442void
443GNUNET_PLUGIN_load_all_in_context (const struct GNUNET_OS_ProjectData *ctx,
444 const char *basename,
445 void *arg,
446 GNUNET_PLUGIN_LoaderCallback cb,
447 void *cb_cls)
448{
449 const struct GNUNET_OS_ProjectData *cpd = GNUNET_OS_project_data_get ();
450
451 GNUNET_OS_init (ctx);
452 GNUNET_PLUGIN_load_all (basename,
453 arg,
454 cb,
455 cb_cls);
456 GNUNET_OS_init (cpd);
457}
458
459
460/* end of plugin.c */