stuff
[oweals/gnunet.git] / src / transport / gnunet-service-transport_hello.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_hello.c
23  * @brief hello management implementation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_hello_lib.h"
28 #include "gnunet_peerinfo_service.h"
29 #include "gnunet_statistics_service.h"
30 #include "gnunet-service-transport_hello.h"
31 #include "gnunet-service-transport.h"
32 #include "gnunet-service-transport_plugins.h"
33
34 /**
35  * After how long do we expire an address in a HELLO that we just
36  * validated?  This value is also used for our own addresses when we
37  * create a HELLO.
38  */
39 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
40
41 /**
42  * How often do we refresh our HELLO (due to expiration concerns)?
43  */
44 #define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
45
46
47 /**
48  * Entry in linked list of network addresses for ourselves.  Also
49  * includes a cached signature for 'struct TransportPongMessage's.
50  */
51 struct OwnAddressList
52 {
53   /**
54    * This is a doubly-linked list.
55    */
56   struct OwnAddressList *next;
57
58   /**
59    * This is a doubly-linked list.
60    */
61   struct OwnAddressList *prev;
62
63   /**
64    * Name of the plugin.
65    */
66   char *plugin_name;
67
68   /**
69    * How long until the current signature expires? (ZERO if the
70    * signature was never created).
71    */
72   struct GNUNET_TIME_Absolute pong_sig_expires;
73
74   /**
75    * Signature for a 'struct TransportPongMessage' for this address.
76    */
77   struct GNUNET_CRYPTO_RsaSignature pong_signature;
78
79   /**
80    * Length of addr.
81    */
82   size_t addrlen;
83
84 };
85
86
87 /**
88  * Our HELLO message.
89  */
90 static struct GNUNET_HELLO_Message *our_hello;
91
92 /**
93  * Function to call on HELLO changes.
94  */
95 static GST_HelloCallback hello_cb;
96
97 /**
98  * Closure for 'hello_cb'.
99  */ 
100 static void *hello_cb_cls;
101
102 /**
103  * Head of my addresses.
104  */
105 struct OwnAddressList *oal_head;
106
107 /**
108  * Tail of my addresses.
109  */
110 struct OwnAddressList *oal_tail;
111
112 /**
113  * Identifier of 'refresh_hello' task.
114  */
115 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
116
117
118 /**
119  * Closure for 'address_generator'.
120  */
121 struct GeneratorContext
122 {
123   /**
124    * Where are we in the DLL?
125    */
126   struct OwnAddressList *addr_pos;
127   
128   /**
129    * When do addresses expire?
130    */
131   struct GNUNET_TIME_Absolute expiration;
132 };
133
134
135 /**
136  * Add an address from the 'OwnAddressList' to the buffer.
137  * 
138  * @param cls the 'struct GeneratorContext'
139  * @param max maximum number of bytes left
140  * @param buf where to write the address
141  */
142 static size_t
143 address_generator (void *cls, size_t max, void *buf)
144 {
145   struct GeneratorContext *gc = cls;
146   size_t ret;
147
148   if (NULL == gc->addr_pos)
149       return 0;    
150   ret = GNUNET_HELLO_add_address (gc->addr_pos->plugin_name,
151                                   gc->expiration,
152                                   &gc->addr_pos[1],
153                                   gc->addr_pos->addrlen,
154                                   buf, max);
155   gc->addr_pos = gc->addr_pos->next;
156   return ret;
157 }
158
159
160 /**
161  * Construct our HELLO message from all of the addresses of
162  * all of the transports.
163  *
164  * @param cls unused
165  * @param tc scheduler context
166  */
167 static void
168 refresh_hello_task (void *cls,
169                     const struct GNUNET_SCHEDULER_TaskContext *tc)
170 {
171   struct GeneratorContext gc;
172
173   hello_task = GNUNET_SCHEDULER_NO_TASK;
174   gc.addr_pos = oal_head;
175   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
176   GNUNET_free (our_hello);
177   our_hello = GNUNET_HELLO_create (&GST_my_public_key, 
178                                    &address_generator, 
179                                    &gc);
180 #if DEBUG_TRANSPORT
181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
182               "Refreshed my `%s', new size is %d\n", "HELLO", 
183               GNUNET_HELLO_size(our_hello));
184 #endif
185   GNUNET_STATISTICS_update (GST_stats,
186                             gettext_noop ("# refreshed my HELLO"),
187                             1,
188                             GNUNET_NO);
189   if (NULL != hello_cb)
190     hello_cb (hello_cb_cls, GST_hello_get());
191   GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello);
192   hello_task
193     = GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD,
194                                     &refresh_hello_task,
195                                     NULL);
196
197 }
198
199
200 /**
201  * Schedule task to refresh hello (unless such a
202  * task exists already).
203  */
204 static void
205 refresh_hello ()
206 {
207   if (hello_task != GNUNET_SCHEDULER_NO_TASK)
208     GNUNET_SCHEDULER_cancel (hello_task);
209   hello_task
210     = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
211                                 NULL);  
212 }
213
214
215 /**
216  * Initialize the HELLO module.
217  *
218  * @param cb function to call whenever our HELLO changes
219  * @param cb_cls closure for cb
220  */
221 void 
222 GST_hello_start (GST_HelloCallback cb,
223                  void *cb_cls)
224 {
225   hello_cb = cb;
226   hello_cb_cls = cb_cls;
227   our_hello = GNUNET_HELLO_create (&GST_my_public_key, 
228                                    NULL, NULL);
229   refresh_hello ();
230 }
231
232
233 /**
234  * Shutdown the HELLO module.
235  */
236 void
237 GST_hello_stop ()
238 {
239   hello_cb = NULL;
240   hello_cb_cls = NULL;
241   if (GNUNET_SCHEDULER_NO_TASK != hello_task)
242     {
243       GNUNET_SCHEDULER_cancel (hello_task);
244       hello_task = GNUNET_SCHEDULER_NO_TASK;
245     }
246   if (NULL != our_hello)
247     {
248       GNUNET_free (our_hello);
249       our_hello = NULL;
250     }
251 }
252
253
254 /**
255  * Obtain this peers HELLO message.
256  *
257  * @return our HELLO message
258  */
259 const struct GNUNET_MessageHeader *
260 GST_hello_get ()
261 {
262   return (struct GNUNET_MessageHeader*) our_hello;
263 }
264
265
266 /**
267  * Add or remove an address from this peer's HELLO message.
268  *
269  * @param addremove GNUNET_YES to add, GNUNET_NO to remove
270  * @param plugin_name name of the plugin for which this is an address
271  * @param plugin_address address in a plugin-specific format
272  * @param plugin_address_len number of bytes in plugin_address
273  */
274 void
275 GST_hello_modify_addresses (int addremove,
276                             const char *plugin_name,
277                             const void *plugin_address,
278                             size_t plugin_address_len)
279 {
280   struct OwnAddressList *al;
281
282 #if DEBUG_TRANSPORT
283   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284               (add_remove == GNUNET_YES)
285               ? "Adding `%s':%s to the set of our addresses\n"
286               : "Removing `%s':%s from the set of our addresses\n",
287               GST_plugins_a2s (plugin_name,
288                                addr, addrlen),
289               p->short_name);
290 #endif
291   GNUNET_assert (plugin_address != NULL);
292   if (GNUNET_NO == addremove)
293     {
294       for (al = oal_head; al != NULL; al = al->next)
295         if ( (plugin_address_len == al->addrlen) &&
296              (0 == strcmp (al->plugin_name, plugin_name)) &&
297              (0 == memcmp (plugin_address, &al[1], plugin_address_len)) )
298           {
299             GNUNET_CONTAINER_DLL_remove (oal_head,
300                                          oal_tail,
301                                          al);
302             GNUNET_free (al->plugin_name);
303             GNUNET_free (al);
304             refresh_hello ();
305             return;         
306           }
307       /* address to be removed not found!? */
308       GNUNET_break (0);
309       return;
310     }
311   al = GNUNET_malloc (sizeof (struct OwnAddressList) + plugin_address_len);
312   GNUNET_CONTAINER_DLL_insert (oal_head,
313                                oal_tail,
314                                al);
315   al->plugin_name = GNUNET_strdup (plugin_name);
316   al->addrlen = plugin_address_len;
317   memcpy (&al[1], plugin_address, plugin_address_len);
318   refresh_hello ();
319 }
320
321
322 /**
323  * Test if a particular address is one of ours.
324  *
325  * @param plugin_name name of the plugin for which this is an address
326  * @param plugin_address address in a plugin-specific format
327  * @param plugin_address_len number of bytes in plugin_address
328  * @param sig location where to cache PONG signatures for this address [set]
329  * @param sig_expiration how long until the current 'sig' expires?
330  *            (ZERO if sig was never created) [set]
331  * @return GNUNET_YES if this is one of our addresses,
332  *         GNUNET_NO if not
333  */
334 int
335 GST_hello_test_address (const char *plugin_name,
336                         const void *plugin_address,
337                         size_t plugin_address_len,
338                         struct GNUNET_CRYPTO_RsaSignature **sig,
339                         struct GNUNET_TIME_Absolute **sig_expiration)
340 {
341   struct OwnAddressList *al;
342
343   for (al = oal_head; al != NULL; al = al->next)
344     if ( (plugin_address_len == al->addrlen) &&
345          (0 == strcmp (al->plugin_name, plugin_name)) &&
346          (0 == memcmp (plugin_address, &al[1], plugin_address_len)) )
347       {
348         *sig = &al->pong_signature;
349         *sig_expiration = &al->pong_sig_expires;
350         return GNUNET_YES;
351       }
352   *sig = NULL;
353   *sig_expiration = NULL;
354   return GNUNET_NO;
355 }
356
357
358 /* end of file gnunet-service-transport_hello.c */