stuff
[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 traffic_cb function to call for flow control
91  * @param session_end_cb function to call when a session was terminated
92  * @param cost_cb function to call about ATS cost changes
93  */
94 void 
95 GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
96                   GNUNET_TRANSPORT_AddressNotification address_cb,
97                   GNUNET_TRANSPORT_TrafficReport traffic_cb,
98                   GNUNET_TRANSPORT_SessionEnd session_end_cb,
99                   GNUNET_TRANSPORT_CostReport cost_cb)
100 {
101   struct TransportPlugin *plug;
102   unsigned long long tneigh;
103   char *libname;
104   char *plugs;
105   char *pos;
106
107   if (GNUNET_OK !=
108       GNUNET_CONFIGURATION_get_value_number (GST_cfg,
109                                              "TRANSPORT",
110                                              "NEIGHBOUR_LIMIT",
111                                              &tneigh))
112     {
113       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114                   _("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
115       return;
116     }
117   if (GNUNET_OK !=
118       GNUNET_CONFIGURATION_get_value_string (GST_cfg,
119                                              "TRANSPORT", "PLUGINS", &plugs))
120     return;
121   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
122               _("Starting transport plugins `%s'\n"),
123               plugs);
124   for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
125     {     
126       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
127                   _("Loading `%s' transport plugin\n"), pos);
128       GNUNET_asprintf (&libname, 
129                        "libgnunet_plugin_transport_%s",
130                        pos);
131       plug = GNUNET_malloc (sizeof (struct TransportPlugin));
132       plug->short_name = GNUNET_strdup (pos);
133       plug->lib_name = libname;
134       plug->env.cfg = GST_cfg;
135       plug->env.my_identity = &GST_my_identity;
136       plug->env.get_our_hello = &GST_hello_get;
137       plug->env.cls = plug->short_name;
138       plug->env.receive = recv_cb;
139       plug->env.notify_address = address_cb;
140       plug->env.session_end = session_end_cb;
141       plug->env.max_connections = tneigh;
142       plug->env.stats = GST_stats;
143       GNUNET_CONTAINER_DLL_insert (plugins_head,
144                                    plugins_tail,
145                                    plug);
146       plug->api = GNUNET_PLUGIN_load (libname, &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                       pos);
152           GNUNET_CONTAINER_DLL_remove (plugins_head,
153                                        plugins_tail,
154                                        plug);
155           GNUNET_free (plug->short_name);
156           GNUNET_free (plug->lib_name);
157           GNUNET_free (plug);
158         }
159     }
160   GNUNET_free (plugs);
161 }
162
163
164 /**
165  * Unload all plugins
166  */
167 void
168 GST_plugins_unload ()
169 {
170   struct TransportPlugin *plug;
171
172   while (NULL != (plug = plugins_head))
173     {
174       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
175       GNUNET_free (plug->lib_name);
176       GNUNET_free (plug->short_name);
177       GNUNET_CONTAINER_DLL_remove (plugins_head,
178                                    plugins_tail,
179                                    plug);
180       GNUNET_free (plug);
181     }
182 }
183
184
185 /**
186  * Obtain the plugin API based on a plugin name.
187  *
188  * @param name name of the plugin
189  * @return the plugin's API, NULL if the plugin is not loaded
190  */
191 struct GNUNET_TRANSPORT_PluginFunctions *
192 GST_plugins_find (const char *name)
193 {
194   struct TransportPlugin *head = plugins_head;
195
196   while ((head != NULL) && (0 != strcmp (name, head->short_name)))
197     head = head->next;
198   if (NULL == head)
199     return NULL;
200   return head->api;
201 }
202
203
204 /**
205  * Convert a given address to a human-readable format.  Note that the
206  * return value will be overwritten on the next call to this function.
207  * 
208  * @param name plugin name
209  * @param addr binary address in plugin-specific format
210  * @param addrlen number of bytes in 'addr'
211  * @return statically allocated (!) human-readable address
212  */
213 const char *
214 GST_plugins_a2s (const char *name,
215                  const void *addr,
216                  size_t addrlen)
217 {
218   struct GNUNET_TRANSPORT_PluginFunctions *api;
219
220   if (name == NULL)
221     return NULL;
222   api = GST_plugins_find (name);
223   if ( (api == NULL) || (addrlen == 0) || (addr == NULL) )
224     return NULL;
225   return api->address_to_string (NULL,
226                                  addr,
227                                  addrlen);
228 }
229
230
231 /* end of file gnunet-service-transport_plugins.c */