replace printf() with GNUNET_log()
[oweals/gnunet.git] / src / transport / gnunet-service-transport_hello.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010,2011 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_constants.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_peerinfo_service.h"
30 #include "gnunet_statistics_service.h"
31 #include "gnunet-service-transport_hello.h"
32 #include "gnunet-service-transport.h"
33 #include "gnunet-service-transport_plugins.h"
34
35
36 /**
37  * How often do we refresh our HELLO (due to expiration concerns)?
38  */
39 #define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply ( \
40     GNUNET_TIME_UNIT_HOURS, 6)
41
42 /**
43  * Hello address expiration
44  */
45 extern struct GNUNET_TIME_Relative hello_expiration;
46
47
48 /**
49  * Entry in linked list of network addresses for ourselves.  Also
50  * includes a cached signature for 'struct TransportPongMessage's.
51  */
52 struct OwnAddressList
53 {
54   /**
55    * This is a doubly-linked list.
56    */
57   struct OwnAddressList *next;
58
59   /**
60    * This is a doubly-linked list.
61    */
62   struct OwnAddressList *prev;
63
64   /**
65    * The address.
66    */
67   struct GNUNET_HELLO_Address *address;
68
69   /**
70    * How long until the current signature expires? (ZERO if the
71    * signature was never created).
72    */
73   struct GNUNET_TIME_Absolute pong_sig_expires;
74
75   /**
76    * Signature for a 'struct TransportPongMessage' for this address.
77    */
78   struct GNUNET_CRYPTO_EddsaSignature pong_signature;
79
80   /**
81    * How often has this address been added/removed? Used as
82    * some plugins may learn the same external address from
83    * multiple origins.
84    */
85   unsigned int rc;
86 };
87
88
89 /**
90  * Our HELLO message.
91  */
92 static struct GNUNET_HELLO_Message *our_hello;
93
94 /**
95  * Function to call on HELLO changes.
96  */
97 static GST_HelloCallback hello_cb;
98
99 /**
100  * Closure for #hello_cb.
101  */
102 static void *hello_cb_cls;
103
104 /**
105  * Head of my addresses.
106  */
107 static struct OwnAddressList *oal_head;
108
109 /**
110  * Tail of my addresses.
111  */
112 static struct OwnAddressList *oal_tail;
113
114 /**
115  * Should we use a friend-only HELLO?
116  */
117 static int friend_option;
118
119 /**
120  * Identifier of #refresh_hello_task().
121  */
122 static struct GNUNET_SCHEDULER_Task *hello_task;
123
124
125 /**
126  * Closure for #address_generator().
127  */
128 struct GeneratorContext
129 {
130   /**
131    * Where are we in the DLL?
132    */
133   struct OwnAddressList *addr_pos;
134
135   /**
136    * When do addresses expire?
137    */
138   struct GNUNET_TIME_Absolute expiration;
139 };
140
141
142 /**
143  * Add an address from the `struct OwnAddressList` to the buffer.
144  *
145  * @param cls the `struct GeneratorContext`
146  * @param max maximum number of bytes left
147  * @param buf where to write the address
148  * @return bytes written or #GNUNET_SYSERR to signal the
149  *         end of the iteration.
150  */
151 static ssize_t
152 address_generator (void *cls,
153                    size_t max,
154                    void *buf)
155 {
156   struct GeneratorContext *gc = cls;
157   ssize_t ret;
158
159   if (NULL == gc->addr_pos)
160     return GNUNET_SYSERR; /* Done */
161   ret = GNUNET_HELLO_add_address (gc->addr_pos->address,
162                                   gc->expiration,
163                                   buf,
164                                   max);
165   gc->addr_pos = gc->addr_pos->next;
166   return ret;
167 }
168
169
170 /**
171  * Construct our HELLO message from all of the addresses of
172  * all of the transports.
173  *
174  * @param cls unused
175  */
176 static void
177 refresh_hello_task (void *cls)
178 {
179   struct GeneratorContext gc;
180
181   hello_task = NULL;
182   gc.addr_pos = oal_head;
183   gc.expiration = GNUNET_TIME_relative_to_absolute (hello_expiration);
184
185   GNUNET_free_non_null (our_hello);
186   our_hello = GNUNET_HELLO_create (&GST_my_identity.public_key,
187                                    &address_generator,
188                                    &gc,
189                                    friend_option);
190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191               "Refreshed my %s HELLO, new size is %d\n",
192               (GNUNET_YES == friend_option) ? "friend-only" : "public",
193               GNUNET_HELLO_size (our_hello));
194   GNUNET_STATISTICS_update (GST_stats,
195                             gettext_noop ("# refreshed my HELLO"),
196                             1,
197                             GNUNET_NO);
198   if (NULL != hello_cb)
199     hello_cb (hello_cb_cls,
200               GST_hello_get ());
201   GNUNET_PEERINFO_add_peer (GST_peerinfo,
202                             our_hello,
203                             NULL,
204                             NULL);
205   hello_task =
206     GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD,
207                                   &refresh_hello_task,
208                                   NULL);
209 }
210
211
212 /**
213  * Schedule task to refresh hello (but only if such a
214  * task exists already, as otherwise the module might
215  * have been shutdown).
216  */
217 static void
218 refresh_hello ()
219 {
220   if (NULL != hello_task)
221   {
222     GNUNET_SCHEDULER_cancel (hello_task);
223     hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
224                                            NULL);
225   }
226 }
227
228
229 /**
230  * Initialize the HELLO module.
231  *
232  * @param friend_only use a friend only hello
233  * @param cb function to call whenever our HELLO changes
234  * @param cb_cls closure for @a cb
235  */
236 void
237 GST_hello_start (int friend_only,
238                  GST_HelloCallback cb,
239                  void *cb_cls)
240 {
241   hello_cb = cb;
242   hello_cb_cls = cb_cls;
243   friend_option = friend_only;
244   refresh_hello_task (NULL);
245 }
246
247
248 /**
249  * Shutdown the HELLO module.
250  */
251 void
252 GST_hello_stop ()
253 {
254   hello_cb = NULL;
255   hello_cb_cls = NULL;
256   if (NULL != hello_task)
257   {
258     GNUNET_SCHEDULER_cancel (hello_task);
259     hello_task = NULL;
260   }
261   if (NULL != our_hello)
262   {
263     GNUNET_free (our_hello);
264     our_hello = NULL;
265   }
266 }
267
268
269 /**
270  * Obtain this peers HELLO message.
271  *
272  * @return our HELLO message
273  */
274 const struct GNUNET_MessageHeader *
275 GST_hello_get ()
276 {
277   return (const struct GNUNET_MessageHeader *) our_hello;
278 }
279
280
281 /**
282  * Add or remove an address from this peer's HELLO message.
283  *
284  * @param addremove #GNUNET_YES to add, #GNUNET_NO to remove
285  * @param address address to add or remove
286  */
287 void
288 GST_hello_modify_addresses (int addremove,
289                             const struct GNUNET_HELLO_Address *address)
290 {
291   struct OwnAddressList *al;
292
293   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294               (GNUNET_YES == addremove)
295               ? "Adding `%s' to the set of our addresses\n"
296               : "Removing `%s' from the set of our addresses\n",
297               GST_plugins_a2s (address));
298   GNUNET_assert (NULL != address);
299   for (al = oal_head; al != NULL; al = al->next)
300     if (0 == GNUNET_HELLO_address_cmp (address, al->address))
301       break;
302   if (GNUNET_NO == addremove)
303   {
304     if (NULL == al)
305     {
306       /* address to be removed not found!? */
307       GNUNET_break (0);
308       return;
309     }
310     al->rc--;
311     if (0 != al->rc)
312       return;   /* RC not yet zero */
313     GNUNET_CONTAINER_DLL_remove (oal_head,
314                                  oal_tail,
315                                  al);
316     GNUNET_HELLO_address_free (al->address);
317     GNUNET_free (al);
318     refresh_hello ();
319     return;
320   }
321   if (NULL != al)
322   {
323     /* address added twice or more */
324     al->rc++;
325     return;
326   }
327   al = GNUNET_new (struct OwnAddressList);
328   al->rc = 1;
329   GNUNET_CONTAINER_DLL_insert (oal_head,
330                                oal_tail,
331                                al);
332   al->address = GNUNET_HELLO_address_copy (address);
333   refresh_hello ();
334 }
335
336
337 /**
338  * Test if a particular address is one of ours.
339  *
340  * @param address address to test
341  * @param sig location where to cache PONG signatures for this address [set]
342  * @param sig_expiration how long until the current 'sig' expires?
343  *            (ZERO if sig was never created) [set]
344  * @return #GNUNET_YES if this is one of our addresses,
345  *         #GNUNET_NO if not
346  */
347 int
348 GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
349                         struct GNUNET_CRYPTO_EddsaSignature **sig,
350                         struct GNUNET_TIME_Absolute **sig_expiration)
351 {
352   struct OwnAddressList *al;
353
354   for (al = oal_head; al != NULL; al = al->next)
355     if (0 == GNUNET_HELLO_address_cmp (address,
356                                        al->address))
357     {
358       *sig = &al->pong_signature;
359       *sig_expiration = &al->pong_sig_expires;
360       return GNUNET_YES;
361     }
362   *sig = NULL;
363   *sig_expiration = NULL;
364   return GNUNET_NO;
365 }
366
367
368 /* end of file gnunet-service-transport_hello.c */