get_address_latency also does not use session
[oweals/gnunet.git] / src / transport / gnunet-service-transport_plugins.c
1 /*
2   This file is part of GNUnet.
3   (C) 2010-2014 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  * Load and initialize all plugins.  The respective functions will be
83  * invoked by the plugins when the respective events happen.  The
84  * closure will be set to a 'const char*' containing the name of the
85  * plugin that caused the call.
86  *
87  * @param recv_cb function to call when data is received
88  * @param register_quota_cb function to call to register a quota callback
89  * @param unregister_quota_cb function to call to unregister a quota callback
90  * @param address_cb function to call when our public addresses changed
91  * @param session_start_cb function to call when a session was created
92  * @param session_end_cb function to call when a session was terminated
93  * @param address_type_cb function to call when a address type is requested
94  * @param metric_update_cb function to call when address metrics change
95  */
96 void
97 GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
98                   GNUNET_TRANSPORT_RegisterQuotaNotification register_quota_cb,
99                   GNUNET_TRANSPORT_UnregisterQuotaNotification unregister_quota_cb,
100                   GNUNET_TRANSPORT_AddressNotification address_cb,
101                   GNUNET_TRANSPORT_SessionStart session_start_cb,
102                   GNUNET_TRANSPORT_SessionEnd session_end_cb,
103                   GNUNET_TRANSPORT_AddressToType address_type_cb,
104                   GNUNET_TRANSPORT_UpdateAddressMetrics metric_update_cb)
105 {
106   struct TransportPlugin *plug;
107   struct TransportPlugin *next;
108   unsigned long long tneigh;
109   char *libname;
110   char *plugs;
111   char *pos;
112   int fail;
113
114   if (GNUNET_OK !=
115       GNUNET_CONFIGURATION_get_value_number (GST_cfg, "TRANSPORT",
116                                              "NEIGHBOUR_LIMIT", &tneigh))
117   {
118     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
119                 _("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
120     return;
121   }
122   if (GNUNET_OK !=
123       GNUNET_CONFIGURATION_get_value_string (GST_cfg, "TRANSPORT", "PLUGINS",
124                                              &plugs))
125     return;
126   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
127               _("Starting transport plugins `%s'\n"),
128               plugs);
129   for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
130   {
131     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
132                 _("Loading `%s' transport plugin\n"),
133                 pos);
134     GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos);
135     plug = GNUNET_new (struct TransportPlugin);
136     plug->short_name = GNUNET_strdup (pos);
137     plug->lib_name = libname;
138     plug->env.cfg = GST_cfg;
139     plug->env.my_identity = &GST_my_identity;
140     plug->env.get_our_hello = &GST_hello_get;
141     plug->env.cls = plug->short_name;
142     plug->env.receive = recv_cb;
143     plug->env.notify_address = address_cb;
144     plug->env.session_start = session_start_cb;
145     plug->env.session_end = session_end_cb;
146     plug->env.get_address_type = address_type_cb;
147     plug->env.update_address_metrics = metric_update_cb;
148     plug->env.register_quota_notification = register_quota_cb;
149     plug->env.unregister_quota_notification = unregister_quota_cb;
150     plug->env.max_connections = tneigh;
151     plug->env.stats = GST_stats;
152     GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug);
153   }
154   GNUNET_free (plugs);
155   next = plugins_head;
156   while (next != NULL)
157   {
158     plug = next;
159     next = plug->next;
160     plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env);
161     if (NULL == plug->api)
162     {
163       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
164                   _("Failed to load transport plugin for `%s'\n"),
165                   plug->lib_name);
166       GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
167       GNUNET_free (plug->short_name);
168       GNUNET_free (plug->lib_name);
169       GNUNET_free (plug);
170       continue;
171     }
172     fail = GNUNET_NO;
173     if (NULL == plug->api->address_pretty_printer)
174     {
175         fail = GNUNET_YES;
176       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
177                   _("Missing function `%s' in transport plugin for `%s'\n"),
178                   "address_pretty_printer",
179                   plug->lib_name);
180     }
181     if (NULL == plug->api->address_to_string)
182     {
183         fail = GNUNET_YES;
184       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
185                   _("Missing function `%s' in transport plugin for `%s'\n"),
186                   "address_to_string",
187                   plug->lib_name);
188     }
189     if (NULL == plug->api->string_to_address)
190     {
191         fail = GNUNET_YES;
192       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
193                   _("Missing function `%s' in transport plugin for `%s'\n"),
194                   "string_to_address",
195                   plug->lib_name);
196     }
197     if (NULL == plug->api->check_address)
198     {
199       fail = GNUNET_YES;
200       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
201                   _("Missing function `%s' in transport plugin for `%s'\n"),
202                   "check_address",
203                   plug->lib_name);
204     }
205     if (NULL == plug->api->get_session)
206     {
207       fail = GNUNET_YES;
208       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
209                   _("Missing function `%s' in transport plugin for `%s'\n"),
210                   "get_session",
211                   plug->lib_name);
212     }
213     if (NULL == plug->api->get_network)
214     {
215       fail = GNUNET_YES;
216       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
217                   _("Missing function `%s' in transport plugin for `%s'\n"),
218                   "get_network",
219                   plug->lib_name);
220     }
221     if (NULL == plug->api->send)
222     {
223       fail = GNUNET_YES;
224       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225                   _("Missing function `%s' in transport plugin for `%s'\n"),
226                   "send",
227                   plug->lib_name);
228     }
229     if (NULL == plug->api->disconnect_peer)
230     {
231         fail = GNUNET_YES;
232       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
233                   _("Missing function `%s' in transport plugin for `%s'\n"),
234                   "disconnect_peer",
235                   plug->lib_name);
236     }
237     if (NULL == plug->api->disconnect_session)
238     {
239         fail = GNUNET_YES;
240       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241                   _("Missing function `%s' in transport plugin for `%s'\n"),
242                   "disconnect_session",
243                   plug->lib_name);
244     }
245     if (NULL == plug->api->query_keepalive_factor)
246     {
247       fail = GNUNET_YES;
248       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249                   _("Missing function `%s' in transport plugin for `%s'\n"),
250                   "query_keepalive_factor",
251                   plug->lib_name);
252     }
253     if (NULL == plug->api->update_session_timeout)
254     {
255         fail = GNUNET_YES;
256       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257                   _("Missing function `%s' in transport plugin for `%s'\n"),
258                   "update_session_timeout",
259                   plug->lib_name);
260     }
261     if (GNUNET_YES == fail)
262     {
263       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
264                   _("Did not load plugin `%s' due to missing functions\n"),
265                   plug->lib_name);
266       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
267       GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
268       GNUNET_free (plug->short_name);
269       GNUNET_free (plug->lib_name);
270       GNUNET_free (plug);
271     }
272   }
273 }
274
275
276 /**
277  * Unload all plugins
278  */
279 void
280 GST_plugins_unload ()
281 {
282   struct TransportPlugin *plug;
283
284   while (NULL != (plug = plugins_head))
285   {
286     GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
287     GNUNET_free (plug->lib_name);
288     GNUNET_free (plug->short_name);
289     GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
290     GNUNET_free (plug);
291   }
292 }
293
294
295 /**
296  * Obtain the plugin API based on a plugin name.
297  *
298  * @param name name of the plugin
299  * @return the plugin's API, NULL if the plugin is not loaded
300  */
301 struct GNUNET_TRANSPORT_PluginFunctions *
302 GST_plugins_find (const char *name)
303 {
304   struct TransportPlugin *pos;
305
306   for (pos = plugins_head; NULL != pos; pos = pos->next)
307     if (0 == strcmp (name, pos->short_name))
308       break;
309   if (NULL == pos)
310     return NULL;
311   return pos->api;
312 }
313
314
315 /**
316  * Obtain the plugin API based on a the stripped plugin name after the underscore.
317  *
318  * Example: GST_plugins_printer_find (http_client) will return all plugins
319  * starting with the prefix "http":
320  * http_client or server if loaded
321  *
322  * @param name name of the plugin
323  * @return the plugin's API, NULL if the plugin is not loaded
324  */
325 struct GNUNET_TRANSPORT_PluginFunctions *
326 GST_plugins_printer_find (const char *name)
327 {
328   struct TransportPlugin *pos;
329   char *stripped = GNUNET_strdup (name);
330   char *sep = strchr (stripped, '_');
331
332   if (NULL != sep)
333     sep[0] = '\0';
334   for (pos = plugins_head; NULL != pos; pos = pos->next)
335     if (pos->short_name == strstr (pos->short_name, stripped))
336         break;
337   GNUNET_free (stripped);
338   if (NULL == pos)
339     return NULL;
340   return pos->api;
341 }
342
343
344 /**
345  * Convert a given address to a human-readable format.  Note that the
346  * return value will be overwritten on the next call to this function.
347  *
348  * @param address the address to convert
349  * @return statically allocated (!) human-readable address
350  */
351 const char *
352 GST_plugins_a2s (const struct GNUNET_HELLO_Address *address)
353 {
354   struct GNUNET_TRANSPORT_PluginFunctions *api;
355   static char unable_to_show[1024];
356   static const char *s;
357
358   if (NULL == address)
359     return "<NULL>";
360   if (0 == address->address_length)
361     return TRANSPORT_SESSION_INBOUND_STRING; /* Addresse with length 0 are inbound, address->address itself may be NULL */
362   api = GST_plugins_printer_find (address->transport_name);
363   if (NULL == api)
364     return "<plugin unknown>";
365   if (0 == address->address_length)
366   {
367     GNUNET_snprintf (unable_to_show, sizeof (unable_to_show),
368                      "<unable to stringify %u-byte long address of %s transport>",
369                      (unsigned int) address->address_length,
370                      address->transport_name);
371     return unable_to_show;
372   }
373   return (NULL != (s = api->address_to_string (NULL, address->address,
374                                  address->address_length)) ? s : "<invalid>");
375 }
376
377
378 /**
379  * Register callback with all plugins to monitor their status.
380  *
381  * @param cb callback to register, NULL to unsubscribe
382  * @param cb_cls closure for @a cb
383  */
384 void
385 GST_plugins_monitor_subscribe (GNUNET_TRANSPORT_SessionInfoCallback cb,
386                                void *cb_cls)
387 {
388   struct TransportPlugin *pos;
389
390   for (pos = plugins_head; NULL != pos; pos = pos->next)
391     if (NULL == pos->api->setup_monitor)
392       GNUNET_break (0);
393     else
394       pos->api->setup_monitor (pos->api->cls,
395                                cb, cb_cls);
396 }
397
398
399 /* end of file gnunet-service-transport_plugins.c */