- mem debug
[oweals/gnunet.git] / src / transport / gnunet-service-transport_plugins.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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 3, 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 transport/gnunet-service-transport_plugins.c
23  * @brief plugin management
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-transport.h"
28 #include "gnunet-service-transport_hello.h"
29 #include "gnunet-service-transport_plugins.h"
30
31 /**
32  * Entry in doubly-linked list of all of our plugins.
33  */
34 struct TransportPlugin
35 {
36   /**
37    * This is a doubly-linked list.
38    */
39   struct TransportPlugin *next;
40
41   /**
42    * This is a doubly-linked list.
43    */
44   struct TransportPlugin *prev;
45
46   /**
47    * API of the transport as returned by the plugin's
48    * initialization function.
49    */
50   struct GNUNET_TRANSPORT_PluginFunctions *api;
51
52   /**
53    * Short name for the plugin (i.e. "tcp").
54    */
55   char *short_name;
56
57   /**
58    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
59    */
60   char *lib_name;
61
62   /**
63    * Environment this transport service is using
64    * for this plugin.
65    */
66   struct GNUNET_TRANSPORT_PluginEnvironment env;
67
68 };
69
70 /**
71  * Head of DLL of all loaded plugins.
72  */
73 static struct TransportPlugin *plugins_head;
74
75 /**
76  * Head of DLL of all loaded plugins.
77  */
78 static struct TransportPlugin *plugins_tail;
79
80
81
82 /**
83  * Load and initialize all plugins.  The respective functions will be
84  * invoked by the plugins when the respective events happen.  The
85  * closure will be set to a 'const char*' containing the name of the
86  * plugin that caused the call.
87  *
88  * @param recv_cb function to call when data is received
89  * @param address_cb function to call when our public addresses changed
90  * @param session_end_cb function to call when a session was terminated
91  * @param address_type_cb function to call when a address type is requested
92  */
93 void
94 GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
95                   GNUNET_TRANSPORT_AddressNotification address_cb,
96                   GNUNET_TRANSPORT_SessionEnd session_end_cb,
97                   GNUNET_TRANSPORT_AddressToType address_type_cb)
98 {
99   struct TransportPlugin *plug;
100   struct TransportPlugin *next;
101   unsigned long long tneigh;
102   char *libname;
103   char *plugs;
104   char *pos;
105
106   if (GNUNET_OK !=
107       GNUNET_CONFIGURATION_get_value_number (GST_cfg, "TRANSPORT",
108                                              "NEIGHBOUR_LIMIT", &tneigh))
109   {
110     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
111                 _("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
112     return;
113   }
114   if (GNUNET_OK !=
115       GNUNET_CONFIGURATION_get_value_string (GST_cfg, "TRANSPORT", "PLUGINS",
116                                              &plugs))
117     return;
118   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
119               plugs);
120   for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
121   {
122     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
123                 pos);
124     GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos);
125     plug = GNUNET_malloc (sizeof (struct TransportPlugin));
126     plug->short_name = GNUNET_strdup (pos);
127     plug->lib_name = libname;
128     plug->env.cfg = GST_cfg;
129     plug->env.my_identity = &GST_my_identity;
130     plug->env.get_our_hello = &GST_hello_get;
131     plug->env.cls = plug->short_name;
132     plug->env.receive = recv_cb;
133     plug->env.notify_address = address_cb;
134     plug->env.session_end = session_end_cb;
135     plug->env.get_address_type = address_type_cb;
136     plug->env.max_connections = tneigh;
137     plug->env.stats = GST_stats;
138     GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug);
139   }
140   GNUNET_free (plugs);
141   next = plugins_head;
142   while (next != NULL)
143   {
144     plug = next;
145     next = plug->next;
146     plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env);
147     if (plug->api == NULL)
148     {
149       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
150                   _("Failed to load transport plugin for `%s'\n"),
151                   plug->lib_name);
152       GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
153       GNUNET_free (plug->short_name);
154       GNUNET_free (plug->lib_name);
155       GNUNET_free (plug);
156     }
157   }
158 }
159
160
161 /**
162  * Unload all plugins
163  */
164 void
165 GST_plugins_unload ()
166 {
167   struct TransportPlugin *plug;
168
169   while (NULL != (plug = plugins_head))
170   {
171     GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
172     GNUNET_free (plug->lib_name);
173     GNUNET_free (plug->short_name);
174     GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
175     GNUNET_free (plug);
176   }
177 }
178
179
180 /**
181  * Obtain the plugin API based on a plugin name.
182  *
183  * @param name name of the plugin
184  * @return the plugin's API, NULL if the plugin is not loaded
185  */
186 struct GNUNET_TRANSPORT_PluginFunctions *
187 GST_plugins_find (const char *name)
188 {
189   struct TransportPlugin *head = plugins_head;
190
191   while ((head != NULL) && (0 != strcmp (name, head->short_name)))
192     head = head->next;
193   if (NULL == head)
194     return NULL;
195   return head->api;
196 }
197
198
199 /**
200  * Obtain the plugin API based on a the stripped plugin name after the underscore.
201  *
202  * Example: GST_plugins_printer_find (http_client) will return all plugins
203  * starting with the prefix "http":
204  * http_client or server if loaded
205  *
206  * @param name name of the plugin
207  * @return the plugin's API, NULL if the plugin is not loaded
208  */
209 struct GNUNET_TRANSPORT_PluginFunctions *
210 GST_plugins_printer_find (const char *name)
211 {
212   struct TransportPlugin *head = plugins_head;
213
214   char *stripped = GNUNET_strdup (name);
215   char *sep = strchr (stripped, '_');
216   if (NULL != sep)
217     sep[0] = '\0';
218
219   while (head != NULL)
220   {
221     if (head->short_name == strstr (head->short_name, stripped))
222         break;
223     head = head->next;
224   }
225   GNUNET_free (stripped);
226   if (NULL == head)
227     return NULL;
228   return head->api;
229 }
230
231
232 /**
233  * Convert a given address to a human-readable format.  Note that the
234  * return value will be overwritten on the next call to this function.
235  *
236  * @param address the address to convert
237  * @return statically allocated (!) human-readable address
238  */
239 const char *
240 GST_plugins_a2s (const struct GNUNET_HELLO_Address *address)
241 {
242   struct GNUNET_TRANSPORT_PluginFunctions *api;
243   static char unable_to_show[1024];
244
245   if (address == NULL)
246     return "<inbound>";
247   api = GST_plugins_printer_find (address->transport_name);
248   if (NULL == api)
249     return "<plugin unknown>";
250   if (0 == address->address_length)
251   {
252     GNUNET_snprintf (unable_to_show, sizeof (unable_to_show),
253                      "<unable to stringify %u-byte long address of %s transport>",
254                      (unsigned int) address->address_length,
255                      address->transport_name);
256     return unable_to_show;
257   }
258   return api->address_to_string (NULL, address->address,
259                                  address->address_length);
260 }
261
262
263 /* end of file gnunet-service-transport_plugins.c */