make dist related fixes
[oweals/gnunet.git] / src / util / plugin.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
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_common.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_plugin_lib.h"
32
33 /**
34  * Linked list of active plugins.
35  */
36 struct 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  * Libtool search path before we started.
57  */
58 static char *old_dlsearchpath;
59
60
61 /**
62  * List of plugins we have loaded.
63  */
64 static struct PluginList *plugins;
65
66
67 /**
68  * Setup libtool paths.
69  */
70 void __attribute__ ((constructor)) GNUNET_PLUGIN_init ()
71 {
72   int err;
73   const char *opath;
74   char *path;
75   char *cpath;
76
77 #ifdef MINGW
78   InitWinEnv (NULL);
79 #endif
80
81   err = lt_dlinit ();
82   if (err > 0)
83     {
84       fprintf (stderr,
85                _("Initialization of plugin mechanism failed: %s!\n"),
86                lt_dlerror ());
87       return;
88     }
89   opath = lt_dlgetsearchpath ();
90   if (opath != NULL)
91     old_dlsearchpath = GNUNET_strdup (opath);
92   path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
93   if (path != NULL)
94     {
95       if (opath != NULL)
96         {
97           cpath = GNUNET_malloc (strlen (path) + strlen (opath) + 4);
98           strcpy (cpath, opath);
99           strcat (cpath, ":");
100           strcat (cpath, path);
101           lt_dlsetsearchpath (cpath);
102           GNUNET_free (path);
103           GNUNET_free (cpath);
104         }
105       else
106         {
107           lt_dlsetsearchpath (path);
108           GNUNET_free (path);
109         }
110     }
111 }
112
113
114 /**
115  * Shutdown libtool.
116  */
117 void __attribute__ ((destructor)) GNUNET_PLUGIN_fini ()
118 {
119   lt_dlsetsearchpath (old_dlsearchpath);
120   if (old_dlsearchpath != NULL)
121     {
122       GNUNET_free (old_dlsearchpath);
123       old_dlsearchpath = NULL;
124     }
125
126 #ifdef MINGW
127   ShutdownWinEnv ();
128 #endif
129
130   lt_dlexit ();
131 }
132
133
134 /**
135  * Lookup a function in the plugin.
136  */
137 static GNUNET_PLUGIN_Callback
138 resolve_function (struct PluginList *plug, const char *name)
139 {
140   char *initName;
141   void *mptr;
142
143   GNUNET_asprintf (&initName, "_%s_%s", plug->name, name);
144   mptr = lt_dlsym (plug->handle, &initName[1]);
145   if (mptr == NULL)
146     mptr = lt_dlsym (plug->handle, initName);
147   if (mptr == NULL)
148     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
149                 _("`%s' failed to resolve method '%s' with error: %s\n"),
150                 "lt_dlsym", &initName[1], lt_dlerror ());
151   GNUNET_free (initName);
152   return mptr;
153 }
154
155
156 /**
157  * Setup plugin (runs the "init" callback and returns whatever "init"
158  * returned).  If "init" returns NULL, the plugin is unloaded.
159  *
160  * Note that the library must export symbols called
161  * "library_name_init" and "library_name_done".  These will be called
162  * when the library is loaded and unloaded respectively.
163  *
164  * @param library_name name of the plugin to load
165  * @param arg argument to the plugin initialization function
166  * @return whatever the initialization function returned
167  */
168 void *
169 GNUNET_PLUGIN_load (const char *library_name, void *arg)
170 {
171   void *libhandle;
172   struct PluginList *plug;
173   GNUNET_PLUGIN_Callback init;
174   void *ret;
175
176   libhandle = lt_dlopenext (library_name);
177   if (libhandle == NULL)
178     {
179       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
180                   _("`%s' failed for library `%s' with error: %s\n"),
181                   "lt_dlopenext", library_name, lt_dlerror ());
182       return NULL;
183     }
184   plug = GNUNET_malloc (sizeof (struct PluginList));
185   plug->handle = libhandle;
186   plug->name = GNUNET_strdup (library_name);
187   plug->next = plugins;
188   plugins = plug;
189   init = resolve_function (plug, "init");
190   if ((init == NULL) || (NULL == (ret = init (arg))))
191     {
192       GNUNET_free (plug->name);
193       plugins = plug->next;
194       GNUNET_free (plug);
195       return NULL;
196     }
197   return ret;
198 }
199
200
201 /**
202  * Unload plugin (runs the "done" callback and returns whatever "done"
203  * returned).  The plugin is then unloaded.
204  *
205  * @param library_name name of the plugin to unload
206  * @param arg argument to the plugin shutdown function
207  * @return whatever the shutdown function returned
208  */
209 void *
210 GNUNET_PLUGIN_unload (const char *library_name, void *arg)
211 {
212   struct PluginList *pos;
213   struct PluginList *prev;
214   GNUNET_PLUGIN_Callback done;
215   void *ret;
216
217   prev = NULL;
218   pos = plugins;
219   while ((pos != NULL) && (0 != strcmp (pos->name, library_name)))
220     {
221       prev = pos;
222       pos = pos->next;
223     }
224   if (pos == NULL)
225     return NULL;
226
227   done = resolve_function (pos, "done");
228   ret = NULL;
229   if (done != NULL)
230     ret = done (arg);
231   if (prev == NULL)
232     plugins = pos->next;
233   else
234     prev->next = pos->next;
235   lt_dlclose (pos->handle);
236   GNUNET_free (pos->name);
237   GNUNET_free (pos);
238   return ret;
239 }
240
241
242
243 /* end of plugin.c */