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