aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/defaults.conf2
-rw-r--r--src/ats/gnunet-service-transport_ats.c (renamed from src/transport/gnunet-service-transport_ats.c)0
-rw-r--r--src/ats/gnunet-service-transport_ats.h (renamed from src/transport/gnunet-service-transport_ats.h)0
-rw-r--r--src/transport/Makefile.am16
-rw-r--r--src/transport/gnunet-service-transport-new.c492
-rw-r--r--src/transport/gnunet-service-transport.c6573
6 files changed, 269 insertions, 6814 deletions
diff --git a/contrib/defaults.conf b/contrib/defaults.conf
index 6ae6df9cf..bb4193433 100644
--- a/contrib/defaults.conf
+++ b/contrib/defaults.conf
@@ -216,7 +216,7 @@ PORT = 2091
216HOSTNAME = localhost 216HOSTNAME = localhost
217HOME = $SERVICEHOME 217HOME = $SERVICEHOME
218CONFIG = $DEFAULTCONFIG 218CONFIG = $DEFAULTCONFIG
219BINARY = gnunet-service-transport-new 219BINARY = gnunet-service-transport
220#PREFIX = valgrind 220#PREFIX = valgrind
221NEIGHBOUR_LIMIT = 50 221NEIGHBOUR_LIMIT = 50
222ACCEPT_FROM = 127.0.0.1; 222ACCEPT_FROM = 127.0.0.1;
diff --git a/src/transport/gnunet-service-transport_ats.c b/src/ats/gnunet-service-transport_ats.c
index 220fe522b..220fe522b 100644
--- a/src/transport/gnunet-service-transport_ats.c
+++ b/src/ats/gnunet-service-transport_ats.c
diff --git a/src/transport/gnunet-service-transport_ats.h b/src/ats/gnunet-service-transport_ats.h
index 550f218a9..550f218a9 100644
--- a/src/transport/gnunet-service-transport_ats.h
+++ b/src/ats/gnunet-service-transport_ats.h
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index f59a000ab..3fac2a213 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -87,7 +87,6 @@ bin_PROGRAMS = \
87 gnunet-transport \ 87 gnunet-transport \
88 $(WLAN_BIN) \ 88 $(WLAN_BIN) \
89 gnunet-service-transport \ 89 gnunet-service-transport \
90 gnunet-service-transport-new \
91 gnunet-transport-list-connections \ 90 gnunet-transport-list-connections \
92 gnunet-transport-certificate-creation 91 gnunet-transport-certificate-creation
93 92
@@ -137,25 +136,14 @@ gnunet_transport_DEPENDENCIES = \
137 libgnunettransport.la 136 libgnunettransport.la
138 137
139gnunet_service_transport_SOURCES = \ 138gnunet_service_transport_SOURCES = \
140 gnunet-service-transport.c 139 gnunet-service-transport.c gnunet-service-transport.h \
141gnunet_service_transport_LDADD = \
142 $(top_builddir)/src/ats/libgnunetats.la \
143 $(top_builddir)/src/hello/libgnunethello.la \
144 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
145 $(top_builddir)/src/statistics/libgnunetstatistics.la \
146 $(top_builddir)/src/util/libgnunetutil.la \
147 $(GN_GLPK) \
148 $(GN_LIBINTL)
149
150gnunet_service_transport_new_SOURCES = \
151 gnunet-service-transport-new.c gnunet-service-transport.h \
152 gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ 140 gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \
153 gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ 141 gnunet-service-transport_clients.h gnunet-service-transport_clients.c \
154 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ 142 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
155 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ 143 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
156 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ 144 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
157 gnunet-service-transport_validation.h gnunet-service-transport_validation.c 145 gnunet-service-transport_validation.h gnunet-service-transport_validation.c
158gnunet_service_transport_new_LDADD = \ 146gnunet_service_transport_LDADD = \
159 $(top_builddir)/src/ats/libgnunetats.la \ 147 $(top_builddir)/src/ats/libgnunetats.la \
160 $(top_builddir)/src/hello/libgnunethello.la \ 148 $(top_builddir)/src/hello/libgnunethello.la \
161 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ 149 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
diff --git a/src/transport/gnunet-service-transport-new.c b/src/transport/gnunet-service-transport-new.c
deleted file mode 100644
index d1ef887fd..000000000
--- a/src/transport/gnunet-service-transport-new.c
+++ /dev/null
@@ -1,492 +0,0 @@
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-new.c
23 * @brief
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_statistics_service.h"
29#include "gnunet_transport_service.h"
30#include "gnunet_peerinfo_service.h"
31#include "gnunet_ats_service.h"
32#include "gnunet-service-transport.h"
33#include "gnunet-service-transport_blacklist.h"
34#include "gnunet-service-transport_clients.h"
35#include "gnunet-service-transport_hello.h"
36#include "gnunet-service-transport_neighbours.h"
37#include "gnunet-service-transport_plugins.h"
38#include "gnunet-service-transport_validation.h"
39#include "transport.h"
40
41/* globals */
42
43/**
44 * Statistics handle.
45 */
46struct GNUNET_STATISTICS_Handle *GST_stats;
47
48/**
49 * Configuration handle.
50 */
51const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
52
53/**
54 * Configuration handle.
55 */
56struct GNUNET_PeerIdentity GST_my_identity;
57
58/**
59 * Handle to peerinfo service.
60 */
61struct GNUNET_PEERINFO_Handle *GST_peerinfo;
62
63/**
64 * Our public key.
65 */
66struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
67
68/**
69 * Our private key.
70 */
71struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
72
73/**
74 * ATS handle.
75 */
76struct GNUNET_ATS_Handle *GST_ats;
77
78
79/**
80 * Transmit our HELLO message to the given (connected) neighbour.
81 *
82 * @param cls the 'HELLO' message
83 * @param target a connected neighbour
84 * @param ats performance information (unused)
85 * @param ats_count number of records in ats (unused)
86 */
87static void
88transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target,
89 const struct GNUNET_TRANSPORT_ATS_Information *ats,
90 uint32_t ats_count)
91{
92 const struct GNUNET_MessageHeader *hello = cls;
93
94 GST_neighbours_send (target, (const char *) hello, ntohs (hello->size),
95 GST_HELLO_ADDRESS_EXPIRATION, NULL, NULL);
96}
97
98
99/**
100 * My HELLO has changed. Tell everyone who should know.
101 *
102 * @param cls unused
103 * @param hello new HELLO
104 */
105static void
106process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
107{
108 GST_clients_broadcast (hello, GNUNET_NO);
109 GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
110}
111
112
113/**
114 * Try to initiate a connection to the given peer if the blacklist
115 * allowed it.
116 *
117 * @param cls closure (unused, NULL)
118 * @param peer identity of peer that was tested
119 * @param result GNUNET_OK if the connection is allowed,
120 * GNUNET_NO if not
121 */
122static void
123try_connect_if_allowed (void *cls, const struct GNUNET_PeerIdentity *peer,
124 int result)
125{
126 if (GNUNET_OK != result)
127 return; /* not allowed */
128 GST_neighbours_try_connect (peer);
129}
130
131
132/**
133 * Function called by the transport for each received message.
134 * This function should also be called with "NULL" for the
135 * message to signal that the other peer disconnected.
136 *
137 * @param cls closure, const char* with the name of the plugin we received the message from
138 * @param peer (claimed) identity of the other peer
139 * @param message the message, NULL if we only care about
140 * learning about the delay until we should receive again -- FIXME!
141 * @param ats performance information
142 * @param ats_count number of records in ats
143 * @param session identifier used for this session (NULL for plugins
144 * that do not offer bi-directional communication to the sender
145 * using the same "connection")
146 * @param sender_address binary address of the sender (if we established the
147 * connection or are otherwise sure of it; should be NULL
148 * for inbound TCP/UDP connections since it it not clear
149 * that we could establish ourselves a connection to that
150 * IP address and get the same system)
151 * @param sender_address_len number of bytes in sender_address
152 * @return how long the plugin should wait until receiving more data
153 * (plugins that do not support this, can ignore the return value)
154 */
155static struct GNUNET_TIME_Relative
156plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
157 const struct GNUNET_MessageHeader *message,
158 const struct GNUNET_TRANSPORT_ATS_Information *ats,
159 uint32_t ats_count, struct Session *session,
160 const char *sender_address,
161 uint16_t sender_address_len)
162{
163 const char *plugin_name = cls;
164 int do_forward;
165 struct GNUNET_TIME_Relative ret;
166 uint16_t type;
167
168 ret = GNUNET_TIME_UNIT_ZERO;
169 if (NULL != message)
170 {
171 type = ntohs (message->type);
172 switch (type)
173 {
174 case GNUNET_MESSAGE_TYPE_HELLO:
175 GST_validation_handle_hello (message);
176 break;
177 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
178#if DEBUG_TRANSPORT
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
180 "Processing `%s' from `%s'\n", "PING",
181 (sender_address != NULL) ? GST_plugins_a2s (plugin_name,
182 sender_address,
183 sender_address_len)
184 : "<inbound>");
185#endif
186 GST_validation_handle_ping (peer, message, plugin_name, session,
187 sender_address, sender_address_len);
188 break;
189 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
190#if DEBUG_TRANSPORT
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
192 "Processing `%s' from `%s'\n", "PONG",
193 (sender_address != NULL) ? GST_plugins_a2s (plugin_name,
194 sender_address,
195 sender_address_len)
196 : "<inbound>");
197#endif
198 GST_validation_handle_pong (peer, message);
199 break;
200 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT:
201 (void) GST_blacklist_test_allowed (peer, NULL, &try_connect_if_allowed,
202 NULL);
203 /* TODO: if 'session != NULL', and timestamp more recent than the
204 * previous one, maybe notify ATS that this is now the preferred
205 * * way to communicate with this peer (other peer switched transport) */
206 break;
207 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
208 /* TODO: do some validation to prevent an attacker from sending
209 * a fake disconnect message... */
210 GST_neighbours_force_disconnect (peer);
211 break;
212 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
213 GST_neighbours_keepalive (peer);
214 break;
215 default:
216 /* should be payload */
217 do_forward = GNUNET_SYSERR;
218 ret =
219 GST_neighbours_calculate_receive_delay (peer,
220 (message ==
221 NULL) ? 0 :
222 ntohs (message->size),
223 &do_forward);
224 if (do_forward == GNUNET_YES)
225 {
226 struct InboundMessage *im;
227 size_t size = sizeof (struct InboundMessage) + ntohs (message->size);
228
229 im = GNUNET_malloc (size);
230 im->header.size = htons (size);
231 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
232 im->ats_count = htonl (0);
233 memcpy (&(im->peer), peer, sizeof (struct GNUNET_PeerIdentity));
234 memcpy (&im[1], message, ntohs (message->size));
235
236 GST_clients_broadcast ((const struct GNUNET_MessageHeader *) im,
237 GNUNET_YES);
238
239 GNUNET_free (im);
240 }
241 break;
242 }
243 }
244
245 GNUNET_assert ((ats_count > 0) && (ats != NULL));
246
247 GNUNET_ATS_address_update (GST_ats, peer, GNUNET_TIME_absolute_get (), /* valid at least until right now... */
248 plugin_name, session, sender_address,
249 sender_address_len, ats, ats_count);
250
251 return ret;
252}
253
254
255/**
256 * Function that will be called for each address the transport
257 * is aware that it might be reachable under. Update our HELLO.
258 *
259 * @param cls name of the plugin (const char*)
260 * @param add_remove should the address added (YES) or removed (NO) from the
261 * set of valid addresses?
262 * @param addr one of the addresses of the host
263 * the specific address format depends on the transport
264 * @param addrlen length of the address
265 */
266static void
267plugin_env_address_change_notification (void *cls, int add_remove,
268 const void *addr, size_t addrlen)
269{
270 const char *plugin_name = cls;
271
272 GST_hello_modify_addresses (add_remove, plugin_name, addr, addrlen);
273}
274
275
276/**
277 * Function that will be called whenever the plugin internally
278 * cleans up a session pointer and hence the service needs to
279 * discard all of those sessions as well. Plugins that do not
280 * use sessions can simply omit calling this function and always
281 * use NULL wherever a session pointer is needed. This function
282 * should be called BEFORE a potential "TransmitContinuation"
283 * from the "TransmitFunction".
284 *
285 * @param cls closure
286 * @param peer which peer was the session for
287 * @param session which session is being destoyed
288 */
289static void
290plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
291 struct Session *session)
292{
293 GST_neighbours_session_terminated (peer, session);
294}
295
296
297/**
298 * Function called by ATS to notify the callee that the
299 * assigned bandwidth or address for a given peer was changed. If the
300 * callback is called with address/bandwidth assignments of zero, the
301 * ATS disconnect function will still be called once the disconnect
302 * actually happened.
303 *
304 * @param cls closure
305 * @param peer identity of the peer
306 * @param plugin_name name of the transport plugin, NULL to disconnect
307 * @param session session to use (if available)
308 * @param plugin_addr address to use (if available)
309 * @param plugin_addr_len number of bytes in addr
310 * @param bandwidth assigned outbound bandwidth for the connection
311 */
312static void
313ats_request_address_change (void *cls, const struct GNUNET_PeerIdentity *peer,
314 const char *plugin_name, struct Session *session,
315 const void *plugin_addr, size_t plugin_addr_len,
316 struct GNUNET_BANDWIDTH_Value32NBO bandwidth)
317{
318 GST_neighbours_switch_to_address (peer, plugin_name, plugin_addr,
319 plugin_addr_len, session, NULL, 0);
320 GST_neighbours_set_incoming_quota (peer, bandwidth);
321}
322
323
324/**
325 * Function called to notify transport users that another
326 * peer connected to us.
327 *
328 * @param cls closure
329 * @param peer the peer that connected
330 * @param ats performance data
331 * @param ats_count number of entries in ats (excluding 0-termination)
332 */
333static void
334neighbours_connect_notification (void *cls,
335 const struct GNUNET_PeerIdentity *peer,
336 const struct GNUNET_TRANSPORT_ATS_Information
337 *ats, uint32_t ats_count)
338{
339 char buf[sizeof (struct ConnectInfoMessage) +
340 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)];
341 struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
342 struct GNUNET_TRANSPORT_ATS_Information *atsm = &connect_msg->ats;
343
344 connect_msg->header.size = htons (sizeof (buf));
345 connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
346 connect_msg->ats_count = htonl (ats_count);
347 connect_msg->id = *peer;
348 memcpy (&connect_msg->ats, ats,
349 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
350 atsm[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
351 atsm[ats_count].value = htonl (0);
352 GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
353}
354
355
356/**
357 * Function called to notify transport users that another
358 * peer disconnected from us.
359 *
360 * @param cls closure
361 * @param peer the peer that disconnected
362 */
363static void
364neighbours_disconnect_notification (void *cls,
365 const struct GNUNET_PeerIdentity *peer)
366{
367 struct DisconnectInfoMessage disconnect_msg;
368
369 disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage));
370 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
371 disconnect_msg.reserved = htonl (0);
372 disconnect_msg.peer = *peer;
373 GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
374}
375
376
377/**
378 * Function called when the service shuts down. Unloads our plugins
379 * and cancels pending validations.
380 *
381 * @param cls closure, unused
382 * @param tc task context (unused)
383 */
384static void
385shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
386{
387 GST_validation_stop ();
388 GST_plugins_unload ();
389 GST_neighbours_stop ();
390 GNUNET_ATS_shutdown (GST_ats);
391 GST_ats = NULL;
392 GST_clients_stop ();
393 GST_blacklist_stop ();
394 GST_hello_stop ();
395
396 if (GST_peerinfo != NULL)
397 {
398 GNUNET_PEERINFO_disconnect (GST_peerinfo);
399 GST_peerinfo = NULL;
400 }
401 if (GST_stats != NULL)
402 {
403 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
404 GST_stats = NULL;
405 }
406 if (GST_my_private_key != NULL)
407 {
408 GNUNET_CRYPTO_rsa_key_free (GST_my_private_key);
409 GST_my_private_key = NULL;
410 }
411}
412
413
414/**
415 * Initiate transport service.
416 *
417 * @param cls closure
418 * @param server the initialized server
419 * @param c configuration to use
420 */
421static void
422run (void *cls, struct GNUNET_SERVER_Handle *server,
423 const struct GNUNET_CONFIGURATION_Handle *c)
424{
425 char *keyfile;
426
427 /* setup globals */
428 GST_cfg = c;
429 if (GNUNET_OK !=
430 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
431 &keyfile))
432 {
433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
434 _
435 ("Transport service is lacking key configuration settings. Exiting.\n"));
436 GNUNET_SCHEDULER_shutdown ();
437 return;
438 }
439 GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
440 GNUNET_free (keyfile);
441 if (GST_my_private_key == NULL)
442 {
443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 _("Transport service could not access hostkey. Exiting.\n"));
445 GNUNET_SCHEDULER_shutdown ();
446 return;
447 }
448 GST_stats = GNUNET_STATISTICS_create ("transport", c);
449 GST_peerinfo = GNUNET_PEERINFO_connect (c);
450 GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key);
451 GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key),
452 &GST_my_identity.hashPubKey);
453 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
454 NULL);
455 if (GST_peerinfo == NULL)
456 {
457 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
458 _("Could not access PEERINFO service. Exiting.\n"));
459 GNUNET_SCHEDULER_shutdown ();
460 return;
461 }
462
463 /* start subsystems */
464 GST_hello_start (&process_hello_update, NULL);
465 GST_blacklist_start (server);
466 GST_plugins_load (&plugin_env_receive_callback,
467 &plugin_env_address_change_notification,
468 &plugin_env_session_end);
469 GST_ats = GNUNET_ATS_init (GST_cfg, &ats_request_address_change, NULL);
470 GST_neighbours_start (NULL, &neighbours_connect_notification,
471 &neighbours_disconnect_notification);
472 GST_clients_start (server);
473 GST_validation_start ();
474}
475
476
477/**
478 * The main function for the transport service.
479 *
480 * @param argc number of arguments from the command line
481 * @param argv command line arguments
482 * @return 0 ok, 1 on error
483 */
484int
485main (int argc, char *const *argv)
486{
487 return (GNUNET_OK ==
488 GNUNET_SERVICE_run (argc, argv, "transport",
489 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
490}
491
492/* end of file gnunet-service-transport-new.c */
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
index 07e9a0d89..d1ef887fd 100644
--- a/src/transport/gnunet-service-transport.c
+++ b/src/transport/gnunet-service-transport.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors) 3 (C) 2010,2011 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -19,2302 +19,257 @@
19*/ 19*/
20 20
21/** 21/**
22 * @file transport/gnunet-service-transport.c 22 * @file transport/gnunet-service-transport-new.c
23 * @brief low-level P2P messaging 23 * @brief
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 */ 25 */
27#include "platform.h" 26#include "platform.h"
28#include "gnunet_client_lib.h" 27#include "gnunet_util_lib.h"
29#include "gnunet_container_lib.h" 28#include "gnunet_statistics_service.h"
30#include "gnunet_constants.h" 29#include "gnunet_transport_service.h"
31#include "gnunet_getopt_lib.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_os_lib.h"
34#include "gnunet_peerinfo_service.h" 30#include "gnunet_peerinfo_service.h"
35#include "gnunet_plugin_lib.h" 31#include "gnunet_ats_service.h"
36#include "gnunet_protocols.h" 32#include "gnunet-service-transport.h"
37#include "gnunet_service_lib.h" 33#include "gnunet-service-transport_blacklist.h"
38#include "gnunet_signatures.h" 34#include "gnunet-service-transport_clients.h"
39#include "gnunet_transport_plugin.h" 35#include "gnunet-service-transport_hello.h"
40#include "gnunet-service-transport_ats.h" 36#include "gnunet-service-transport_neighbours.h"
37#include "gnunet-service-transport_plugins.h"
38#include "gnunet-service-transport_validation.h"
41#include "transport.h" 39#include "transport.h"
42 40
43 41/* globals */
44
45#define DEBUG_BLACKLIST GNUNET_NO
46
47#define DEBUG_PING_PONG GNUNET_NO
48
49#define DEBUG_TRANSPORT_HELLO GNUNET_NO
50
51#define DEBUG_INBOUND GNUNET_NO
52
53/**
54 * Should we do some additional checks (to validate behavior
55 * of clients)?
56 */
57#define EXTRA_CHECKS GNUNET_YES
58
59/**
60 * How many messages can we have pending for a given client process
61 * before we start to drop incoming messages? We typically should
62 * have only one client and so this would be the primary buffer for
63 * messages, so the number should be chosen rather generously.
64 *
65 * The expectation here is that most of the time the queue is large
66 * enough so that a drop is virtually never required. Note that
67 * this value must be about as large as 'TOTAL_MSGS' in the
68 * 'test_transport_api_reliability.c', otherwise that testcase may
69 * fail.
70 */
71#define MAX_PENDING (128 * 1024)
72
73/**
74 * Size of the per-transport blacklist hash maps.
75 */
76#define TRANSPORT_BLACKLIST_HT_SIZE 16
77
78/**
79 * How often should we try to reconnect to a peer using a particular
80 * transport plugin before giving up? Note that the plugin may be
81 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
82 */
83#define MAX_CONNECT_RETRY 3
84
85/**
86 * Limit on the number of ready-to-run tasks when validating
87 * HELLOs. If more tasks are ready to run, we will drop
88 * HELLOs instead of validating them.
89 */
90#define MAX_HELLO_LOAD 4
91
92/**
93 * How often must a peer violate bandwidth quotas before we start
94 * to simply drop its messages?
95 */
96#define QUOTA_VIOLATION_DROP_THRESHOLD 10
97
98/**
99 * How long until a HELLO verification attempt should time out?
100 * Must be rather small, otherwise a partially successful HELLO
101 * validation (some addresses working) might not be available
102 * before a client's request for a connection fails for good.
103 * Besides, if a single request to an address takes a long time,
104 * then the peer is unlikely worthwhile anyway.
105 */
106#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
107
108/**
109 * How long is a PONG signature valid? We'll recycle a signature until
110 * 1/4 of this time is remaining. PONGs should expire so that if our
111 * external addresses change an adversary cannot replay them indefinitely.
112 * OTOH, we don't want to spend too much time generating PONG signatures,
113 * so they must have some lifetime to reduce our CPU usage.
114 */
115#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
116
117/**
118 * Priority to use for PONG messages.
119 */
120#define TRANSPORT_PONG_PRIORITY 4
121
122/**
123 * How often do we re-add (cheaper) plugins to our list of plugins
124 * to try for a given connected peer?
125 */
126#define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
127
128/**
129 * After how long do we expire an address in a HELLO that we just
130 * validated? This value is also used for our own addresses when we
131 * create a HELLO.
132 */
133#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
134
135
136/**
137 * How long before an existing address expires should we again try to
138 * validate it? Must be (significantly) smaller than
139 * HELLO_ADDRESS_EXPIRATION.
140 */
141#define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
142
143/**
144 * List of addresses of other peers
145 */
146struct ForeignAddressList
147{
148 /**
149 * This is a linked list.
150 */
151 struct ForeignAddressList *next;
152
153 /**
154 * Which ready list does this entry belong to.
155 */
156 struct ReadyList *ready_list;
157
158 /**
159 * How long until we auto-expire this address (unless it is
160 * re-confirmed by the transport)?
161 */
162 struct GNUNET_TIME_Absolute expires;
163
164 /**
165 * Task used to re-validate addresses, updates latencies and
166 * verifies liveness.
167 */
168 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
169
170 /**
171 * The address.
172 */
173 const void *addr;
174
175 /**
176 * Session (or NULL if no valid session currently exists or if the
177 * plugin does not use sessions).
178 */
179 struct Session *session;
180
181 struct ATS_ressource_entry *ressources;
182
183 struct ATS_quality_entry *quality;
184
185 /**
186 * What was the last latency observed for this address, plugin and peer?
187 */
188 struct GNUNET_TIME_Relative latency;
189
190 /**
191 * If we did not successfully transmit a message to the given peer
192 * via this connection during the specified time, we should consider
193 * the connection to be dead. This is used in the case that a TCP
194 * transport simply stalls writing to the stream but does not
195 * formerly get a signal that the other peer died.
196 */
197 struct GNUNET_TIME_Absolute timeout;
198
199 /**
200 * How often have we tried to connect using this plugin? Used to
201 * discriminate against addresses that do not work well.
202 * FIXME: not yet used, but should be!
203 */
204 unsigned int connect_attempts;
205
206 /**
207 * DV distance to this peer (1 if no DV is used).
208 * FIXME: need to set this from transport plugins!
209 */
210 uint32_t distance;
211
212 /**
213 * Length of addr.
214 */
215 uint16_t addrlen;
216
217 /**
218 * Have we ever estimated the latency of this address? Used to
219 * ensure that the first time we add an address, we immediately
220 * probe its latency.
221 */
222 int8_t estimated;
223
224 /**
225 * Are we currently connected via this address? The first time we
226 * successfully transmit or receive data to a peer via a particular
227 * address, we set this to GNUNET_YES. If we later get an error
228 * (disconnect notification, transmission failure, timeout), we set
229 * it back to GNUNET_NO.
230 */
231 int8_t connected;
232
233 /**
234 * Is this plugin currently busy transmitting to the specific target?
235 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
236 * messages do not count as 'in transmit'.
237 */
238 int8_t in_transmit;
239
240 /**
241 * Has this address been validated yet?
242 */
243 int8_t validated;
244
245};
246
247
248/**
249 * Entry in linked list of network addresses for ourselves. Also
250 * includes a cached signature for 'struct TransportPongMessage's.
251 */
252struct OwnAddressList
253{
254 /**
255 * This is a linked list.
256 */
257 struct OwnAddressList *next;
258
259 /**
260 * How long until the current signature expires? (ZERO if the
261 * signature was never created).
262 */
263 struct GNUNET_TIME_Absolute pong_sig_expires;
264
265 /**
266 * Signature for a 'struct TransportPongMessage' for this address.
267 */
268 struct GNUNET_CRYPTO_RsaSignature pong_signature;
269
270 /**
271 * Length of addr.
272 */
273 uint32_t addrlen;
274
275};
276
277 42
278/** 43/**
279 * Entry in linked list of all of our plugins. 44 * Statistics handle.
280 */ 45 */
281struct TransportPlugin 46struct GNUNET_STATISTICS_Handle *GST_stats;
282{
283 /**
284 * This is a linked list.
285 */
286 struct TransportPlugin *next;
287
288 /**
289 * API of the transport as returned by the plugin's
290 * initialization function.
291 */
292 struct GNUNET_TRANSPORT_PluginFunctions *api;
293
294 /**
295 * Short name for the plugin (i.e. "tcp").
296 */
297 char *short_name;
298
299 /**
300 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
301 */
302 char *lib_name;
303
304 /**
305 * List of our known addresses for this transport.
306 */
307 struct OwnAddressList *addresses;
308
309 /**
310 * Environment this transport service is using
311 * for this plugin.
312 */
313 struct GNUNET_TRANSPORT_PluginEnvironment env;
314
315 /**
316 * ID of task that is used to clean up expired addresses.
317 */
318 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
319
320 /**
321 * Set to GNUNET_YES if we need to scrap the existing list of
322 * "addresses" and start fresh when we receive the next address
323 * update from a transport. Set to GNUNET_NO if we should just add
324 * the new address to the list and wait for the commit call.
325 */
326 int rebuild;
327
328 struct ATS_plugin *rc;
329
330 /**
331 * Hashmap of blacklisted peers for this particular transport.
332 */
333 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
334};
335
336struct NeighbourMapEntry;
337 47
338/** 48/**
339 * For each neighbour we keep a list of messages 49 * Configuration handle.
340 * that we still want to transmit to the neighbour.
341 */ 50 */
342struct MessageQueue 51const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
343{
344
345 /**
346 * This is a doubly linked list.
347 */
348 struct MessageQueue *next;
349
350 /**
351 * This is a doubly linked list.
352 */
353 struct MessageQueue *prev;
354
355 /**
356 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
357 * stuck together in memory. Allocated at the end of this struct.
358 */
359 const char *message_buf;
360
361 /**
362 * Size of the message buf
363 */
364 size_t message_buf_size;
365
366 /**
367 * Client responsible for queueing the message;
368 * used to check that a client has no two messages
369 * pending for the same target. Can be NULL.
370 */
371 struct TransportClient *client;
372
373 /**
374 * Using which specific address should we send this message?
375 */
376 struct ForeignAddressList *specific_address;
377
378 /**
379 * Peer ID of the Neighbour this entry belongs to.
380 */
381 struct GNUNET_PeerIdentity neighbour_id;
382
383 /**
384 * Plugin that we used for the transmission.
385 * NULL until we scheduled a transmission.
386 */
387 struct TransportPlugin *plugin;
388
389 /**
390 * At what time should we fail?
391 */
392 struct GNUNET_TIME_Absolute timeout;
393
394 /**
395 * Internal message of the transport system that should not be
396 * included in the usual SEND-SEND_OK transmission confirmation
397 * traffic management scheme. Typically, "internal_msg" will
398 * be set whenever "client" is NULL (but it is not strictly
399 * required).
400 */
401 int internal_msg;
402
403 /**
404 * How important is the message?
405 */
406 unsigned int priority;
407
408};
409
410 52
411/** 53/**
412 * For a given Neighbour, which plugins are available 54 * Configuration handle.
413 * to talk to this peer and what are their costs?
414 */ 55 */
415struct ReadyList 56struct GNUNET_PeerIdentity GST_my_identity;
416{
417 /**
418 * This is a linked list.
419 */
420 struct ReadyList *next;
421
422 /**
423 * Which of our transport plugins does this entry
424 * represent?
425 */
426 struct TransportPlugin *plugin;
427
428 /**
429 * Transport addresses, latency, and readiness for
430 * this particular plugin.
431 */
432 struct ForeignAddressList *addresses;
433
434 /**
435 * To which neighbour does this ready list belong to?
436 */
437 struct NeighbourMapEntry *neighbour;
438};
439
440 57
441/** 58/**
442 * Entry in neighbours. 59 * Handle to peerinfo service.
443 */
444struct NeighbourMapEntry
445{
446
447 /**
448 * Which of our transports is connected to this peer
449 * and what is their status?
450 */
451 struct ReadyList *plugins;
452
453 /**
454 * Head of list of messages we would like to send to this peer;
455 * must contain at most one message per client.
456 */
457 struct MessageQueue *messages_head;
458
459 /**
460 * Tail of list of messages we would like to send to this peer; must
461 * contain at most one message per client.
462 */
463 struct MessageQueue *messages_tail;
464
465 /**
466 * Head of list of messages of messages we expected the continuation
467 * to be called to destroy the message
468 */
469 struct MessageQueue *cont_head;
470
471 /**
472 * Tail of list of messages of messages we expected the continuation
473 * to be called to destroy the message
474 */
475 struct MessageQueue *cont_tail;
476
477 /**
478 * Buffer for at most one payload message used when we receive
479 * payload data before our PING-PONG has succeeded. We then
480 * store such messages in this intermediary buffer until the
481 * connection is fully up.
482 */
483 struct GNUNET_MessageHeader *pre_connect_message_buffer;
484
485 /**
486 * Context for peerinfo iteration.
487 * NULL after we are done processing peerinfo's information.
488 */
489 struct GNUNET_PEERINFO_IteratorContext *piter;
490
491 /**
492 * Public key for this peer. Valid only if the respective flag is set below.
493 */
494 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
495
496 /**
497 * Identity of this neighbour.
498 */
499 struct GNUNET_PeerIdentity id;
500
501 /**
502 * ID of task scheduled to run when this peer is about to
503 * time out (will free resources associated with the peer).
504 */
505 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
506
507 /**
508 * ID of task scheduled to run when we should retry transmitting
509 * the head of the message queue. Actually triggered when the
510 * transmission is timing out (we trigger instantly when we have
511 * a chance of success).
512 */
513 GNUNET_SCHEDULER_TaskIdentifier retry_task;
514
515 /**
516 * How long until we should consider this peer dead
517 * (if we don't receive another message in the
518 * meantime)?
519 */
520 struct GNUNET_TIME_Absolute peer_timeout;
521
522 /**
523 * Tracker for inbound bandwidth.
524 */
525 struct GNUNET_BANDWIDTH_Tracker in_tracker;
526
527 /**
528 * The latency we have seen for this particular address for
529 * this particular peer. This latency may have been calculated
530 * over multiple transports. This value reflects how long it took
531 * us to receive a response when SENDING via this particular
532 * transport/neighbour/address combination!
533 *
534 * FIXME: we need to periodically send PINGs to update this
535 * latency (at least more often than the current "huge" (11h?)
536 * update interval).
537 */
538 struct GNUNET_TIME_Relative latency;
539
540 /**
541 * How often has the other peer (recently) violated the
542 * inbound traffic limit? Incremented by 10 per violation,
543 * decremented by 1 per non-violation (for each
544 * time interval).
545 */
546 unsigned int quota_violation_count;
547
548 /**
549 * DV distance to this peer (1 if no DV is used).
550 */
551 uint32_t distance;
552
553 /**
554 * Have we seen an PONG from this neighbour in the past (and
555 * not had a disconnect since)?
556 */
557 int received_pong;
558
559 /**
560 * Do we have a valid public key for this neighbour?
561 */
562 int public_key_valid;
563
564 /**
565 * Are we already in the process of disconnecting this neighbour?
566 */
567 int in_disconnect;
568
569 /**
570 * Performance data for the peer.
571 */
572 struct GNUNET_TRANSPORT_ATS_Information *ats;
573};
574
575/**
576 * Message used to ask a peer to validate receipt (to check an address
577 * from a HELLO). Followed by the address we are trying to validate,
578 * or an empty address if we are just sending a PING to confirm that a
579 * connection which the receiver (of the PING) initiated is still valid.
580 */
581struct TransportPingMessage
582{
583
584 /**
585 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
586 */
587 struct GNUNET_MessageHeader header;
588
589 /**
590 * Challenge code (to ensure fresh reply).
591 */
592 uint32_t challenge GNUNET_PACKED;
593
594 /**
595 * Who is the intended recipient?
596 */
597 struct GNUNET_PeerIdentity target;
598
599};
600
601
602/**
603 * Message used to validate a HELLO. The challenge is included in the
604 * confirmation to make matching of replies to requests possible. The
605 * signature signs our public key, an expiration time and our address.<p>
606 *
607 * This message is followed by our transport address that the PING tried
608 * to confirm (if we liked it). The address can be empty (zero bytes)
609 * if the PING had not address either (and we received the request via
610 * a connection that we initiated).
611 */
612struct TransportPongMessage
613{
614
615 /**
616 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
617 */
618 struct GNUNET_MessageHeader header;
619
620 /**
621 * Challenge code from PING (showing freshness). Not part of what
622 * is signed so that we can re-use signatures.
623 */
624 uint32_t challenge GNUNET_PACKED;
625
626 /**
627 * Signature.
628 */
629 struct GNUNET_CRYPTO_RsaSignature signature;
630
631 /**
632 * What are we signing and why? Two possible reason codes can be here:
633 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
634 * plausible address for this peer (pid is set to identity of signer); or
635 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
636 * an address we used to connect to the peer with the given pid.
637 */
638 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
639
640 /**
641 * When does this signature expire?
642 */
643 struct GNUNET_TIME_AbsoluteNBO expiration;
644
645 /**
646 * Either the identity of the peer Who signed this message, or the
647 * identity of the peer that we're connected to using the given
648 * address (depending on purpose.type).
649 */
650 struct GNUNET_PeerIdentity pid;
651
652 /**
653 * Size of address appended to this message (part of what is
654 * being signed, hence not redundant).
655 */
656 uint32_t addrlen;
657
658};
659
660
661/**
662 * Linked list of messages to be transmitted to the client. Each
663 * entry is followed by the actual message.
664 */
665struct ClientMessageQueueEntry
666{
667 /**
668 * This is a doubly-linked list.
669 */
670 struct ClientMessageQueueEntry *next;
671
672 /**
673 * This is a doubly-linked list.
674 */
675 struct ClientMessageQueueEntry *prev;
676};
677
678
679/**
680 * Client connected to the transport service.
681 */
682struct TransportClient
683{
684
685 /**
686 * This is a linked list.
687 */
688 struct TransportClient *next;
689
690 /**
691 * Handle to the client.
692 */
693 struct GNUNET_SERVER_Client *client;
694
695 /**
696 * Linked list of messages yet to be transmitted to
697 * the client.
698 */
699 struct ClientMessageQueueEntry *message_queue_head;
700
701 /**
702 * Tail of linked list of messages yet to be transmitted to the
703 * client.
704 */
705 struct ClientMessageQueueEntry *message_queue_tail;
706
707 /**
708 * Current transmit request handle.
709 */
710 struct GNUNET_CONNECTION_TransmitHandle *th;
711
712 /**
713 * Is a call to "transmit_send_continuation" pending? If so, we
714 * must not free this struct (even if the corresponding client
715 * disconnects) and instead only remove it from the linked list and
716 * set the "client" field to NULL.
717 */
718 int tcs_pending;
719
720 /**
721 * Length of the list of messages pending for this client.
722 */
723 unsigned int message_count;
724
725};
726
727
728/**
729 * Context of currently active requests to peerinfo
730 * for validation of HELLOs.
731 */
732struct CheckHelloValidatedContext;
733
734
735/**
736 * Entry in map of all HELLOs awaiting validation.
737 */
738struct ValidationEntry
739{
740
741 /**
742 * NULL if this entry is not part of a larger HELLO validation.
743 */
744 struct CheckHelloValidatedContext *chvc;
745
746 /**
747 * The address, actually a pointer to the end
748 * of this struct. Do not free!
749 */
750 const void *addr;
751
752 /**
753 * Name of the transport.
754 */
755 char *transport_name;
756
757 /**
758 * The public key of the peer.
759 */
760 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
761
762 /**
763 * ID of task that will clean up this entry if we don't succeed
764 * with the validation first.
765 */
766 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
767
768 /**
769 * At what time did we send this validation?
770 */
771 struct GNUNET_TIME_Absolute send_time;
772
773 /**
774 * Session being validated (or NULL for none).
775 */
776 struct Session *session;
777
778 /**
779 * Challenge number we used.
780 */
781 uint32_t challenge;
782
783 /**
784 * Length of addr.
785 */
786 uint16_t addrlen;
787
788};
789
790
791/**
792 * Context of currently active requests to peerinfo
793 * for validation of HELLOs.
794 */
795struct CheckHelloValidatedContext
796{
797
798 /**
799 * This is a doubly-linked list.
800 */
801 struct CheckHelloValidatedContext *next;
802
803 /**
804 * This is a doubly-linked list.
805 */
806 struct CheckHelloValidatedContext *prev;
807
808 /**
809 * Hello that we are validating.
810 */
811 const struct GNUNET_HELLO_Message *hello;
812
813 /**
814 * Context for peerinfo iteration.
815 * NULL after we are done processing peerinfo's information.
816 */
817 struct GNUNET_PEERINFO_IteratorContext *piter;
818
819 /**
820 * Was a HELLO known for this peer to peerinfo?
821 */
822 int hello_known;
823
824 /**
825 * Number of validation entries currently referring to this
826 * CHVC.
827 */
828 unsigned int ve_count;
829};
830
831
832/**
833 * All zero hash for comparison.
834 */
835static GNUNET_HashCode null_hash;
836
837/**
838 * Our HELLO message.
839 */ 60 */
840static struct GNUNET_HELLO_Message *our_hello; 61struct GNUNET_PEERINFO_Handle *GST_peerinfo;
841 62
842/** 63/**
843 * Our public key. 64 * Our public key.
844 */ 65 */
845static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; 66struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
846
847/**
848 * Our identity.
849 */
850static struct GNUNET_PeerIdentity my_identity;
851 67
852/** 68/**
853 * Our private key. 69 * Our private key.
854 */ 70 */
855static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; 71struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
856
857/**
858 * Our configuration.
859 */
860const struct GNUNET_CONFIGURATION_Handle *cfg;
861
862/**
863 * Linked list of all clients to this service.
864 */
865static struct TransportClient *clients;
866
867/**
868 * All loaded plugins.
869 */
870static struct TransportPlugin *plugins;
871
872/**
873 * Handle to peerinfo service.
874 */
875static struct GNUNET_PEERINFO_Handle *peerinfo;
876
877/**
878 * All known neighbours and their HELLOs.
879 */
880static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
881
882/**
883 * Number of neighbours we'd like to have.
884 */
885static uint32_t max_connect_per_transport;
886
887/**
888 * Head of linked list.
889 */
890static struct CheckHelloValidatedContext *chvc_head;
891
892/**
893 * Tail of linked list.
894 */
895static struct CheckHelloValidatedContext *chvc_tail;
896
897/**
898 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
899 * of the given peer that we are currently validating).
900 */
901static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
902
903/**
904 * Handle for reporting statistics.
905 */
906static struct GNUNET_STATISTICS_Handle *stats;
907 72
908/** 73/**
909 * Identifier of 'refresh_hello' task. 74 * ATS handle.
910 */ 75 */
911static GNUNET_SCHEDULER_TaskIdentifier hello_task; 76struct GNUNET_ATS_Handle *GST_ats;
912 77
913/**
914 * Identifier of ats scheduler task.
915 */
916static GNUNET_SCHEDULER_TaskIdentifier ats_task;
917
918/**
919 * Is transport service shutting down ?
920 */
921static int shutdown_in_progress;
922
923/**
924 * Handle for ats information
925 */
926static struct ATS_Handle *ats;
927
928/**
929 * Time of last ats execution
930 */
931struct GNUNET_TIME_Absolute last_ats_execution;
932
933/**
934 * Minimum interval between two ATS executions
935 */
936struct GNUNET_TIME_Relative ats_minimum_interval;
937
938/**
939 * Regular interval when ATS execution is triggered
940 */
941struct GNUNET_TIME_Relative ats_regular_interval;
942
943/**
944 * The peer specified by the given neighbour has timed-out or a plugin
945 * has disconnected. We may either need to do nothing (other plugins
946 * still up), or trigger a full disconnect and clean up. This
947 * function updates our state and do the necessary notifications.
948 * Also notifies our clients that the neighbour is now officially
949 * gone.
950 *
951 * @param n the neighbour list entry for the peer
952 * @param check should we just check if all plugins
953 * disconnected or must we ask all plugins to
954 * disconnect?
955 */
956static void
957disconnect_neighbour (struct NeighbourMapEntry *n, int check);
958 78
959/** 79/**
960 * Check the ready list for the given neighbour and if a plugin is 80 * Transmit our HELLO message to the given (connected) neighbour.
961 * ready for transmission (and if we have a message), do so!
962 * 81 *
963 * @param nexi target peer for which to transmit 82 * @param cls the 'HELLO' message
83 * @param target a connected neighbour
84 * @param ats performance information (unused)
85 * @param ats_count number of records in ats (unused)
964 */ 86 */
965static void 87static void
966try_transmission_to_peer (struct NeighbourMapEntry *n); 88transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target,
967 89 const struct GNUNET_TRANSPORT_ATS_Information *ats,
968struct ForeignAddressList * 90 uint32_t ats_count)
969get_preferred_ats_address (struct NeighbourMapEntry *n);
970
971/**
972 * Find an entry in the neighbour list for a particular peer.
973 *
974 * @return NULL if not found.
975 */
976static struct NeighbourMapEntry *
977find_neighbour (const struct GNUNET_PeerIdentity *key)
978{
979 return GNUNET_CONTAINER_multihashmap_get (neighbours, &key->hashPubKey);
980}
981
982static int
983update_addr_value (struct ForeignAddressList *fal, uint32_t value,
984 int ats_index)
985{ 91{
986 int c; 92 const struct GNUNET_MessageHeader *hello = cls;
987 int set = GNUNET_NO;
988 93
989 for (c = 0; c < available_quality_metrics; c++) 94 GST_neighbours_send (target, (const char *) hello, ntohs (hello->size),
990 { 95 GST_HELLO_ADDRESS_EXPIRATION, NULL, NULL);
991 if (ats_index == qm[c].atis_index)
992 {
993 fal->quality[c].values[0] = fal->quality[c].values[1];
994 fal->quality[c].values[1] = fal->quality[c].values[2];
995 fal->quality[c].values[2] = value;
996 set = GNUNET_YES;
997#if HAVE_LIBGLPK
998 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
999#endif
1000 }
1001 }
1002 if (set == GNUNET_NO)
1003 {
1004 for (c = 0; c < available_ressources; c++)
1005 {
1006 if (ats_index == ressources[c].atis_index)
1007 {
1008 fal->ressources[c].c = value;
1009 set = GNUNET_YES;
1010#if HAVE_LIBGLPK
1011 ats_modify_problem_state (ats, ATS_COST_UPDATED);
1012#endif
1013 }
1014 }
1015 }
1016 return set;
1017}
1018
1019static int
1020update_addr_ats (struct ForeignAddressList *fal,
1021 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
1022 int ats_count)
1023{
1024 int c1, set;
1025
1026 set = GNUNET_NO;
1027 for (c1 = 0; c1 < ats_count; c1++)
1028 {
1029 set =
1030 update_addr_value (fal, ntohl (ats_data[c1].value),
1031 ntohl (ats_data[c1].type));
1032 }
1033 return set;
1034} 96}
1035 97
1036/**
1037 * Find an entry in the transport list for a particular transport.
1038 *
1039 * @return NULL if not found.
1040 */
1041static struct TransportPlugin *
1042find_transport (const char *short_name)
1043{
1044 struct TransportPlugin *head = plugins;
1045
1046 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1047 head = head->next;
1048 return head;
1049}
1050 98
1051/** 99/**
1052 * Is a particular peer blacklisted for a particular transport? 100 * My HELLO has changed. Tell everyone who should know.
1053 *
1054 * @param peer the peer to check for
1055 * @param plugin the plugin used to connect to the peer
1056 * 101 *
1057 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not 102 * @param cls unused
103 * @param hello new HELLO
1058 */ 104 */
1059static int
1060is_blacklisted (const struct GNUNET_PeerIdentity *peer,
1061 struct TransportPlugin *plugin)
1062{
1063
1064 if (plugin->blacklist != NULL)
1065 {
1066 if (GNUNET_CONTAINER_multihashmap_contains
1067 (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1068 {
1069#if DEBUG_BLACKLIST
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s:%s' is blacklisted!\n",
1071 plugin->short_name, GNUNET_i2s (peer));
1072#endif
1073 if (stats != NULL)
1074 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1,
1075 GNUNET_NO);
1076 return GNUNET_YES;
1077 }
1078 }
1079
1080 return GNUNET_NO;
1081}
1082
1083
1084static void 105static void
1085add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name) 106process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
1086{ 107{
1087 struct TransportPlugin *plugin; 108 GST_clients_broadcast (hello, GNUNET_NO);
1088 109 GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
1089 plugin = find_transport (transport_name);
1090 if (plugin == NULL) /* Nothing to do */
1091 return;
1092#if DEBUG_TRANSPORT
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "Adding peer `%s' with plugin `%s' to blacklist\n",
1095 GNUNET_i2s (peer), transport_name);
1096#endif
1097 if (plugin->blacklist == NULL)
1098 plugin->blacklist =
1099 GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE);
1100 GNUNET_assert (plugin->blacklist != NULL);
1101 GNUNET_CONTAINER_multihashmap_put (plugin->blacklist, &peer->hashPubKey, NULL,
1102 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1103} 110}
1104 111
1105 112
1106/** 113/**
1107 * Read the blacklist file, containing transport:peer entries. 114 * Try to initiate a connection to the given peer if the blacklist
1108 * Provided the transport is loaded, set up hashmap with these 115 * allowed it.
1109 * entries to blacklist peers by transport.
1110 * 116 *
117 * @param cls closure (unused, NULL)
118 * @param peer identity of peer that was tested
119 * @param result GNUNET_OK if the connection is allowed,
120 * GNUNET_NO if not
1111 */ 121 */
1112static void 122static void
1113read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg) 123try_connect_if_allowed (void *cls, const struct GNUNET_PeerIdentity *peer,
124 int result)
1114{ 125{
1115 char *fn; 126 if (GNUNET_OK != result)
1116 char *data; 127 return; /* not allowed */
1117 size_t pos; 128 GST_neighbours_try_connect (peer);
1118 size_t colon_pos;
1119 int tsize;
1120 struct GNUNET_PeerIdentity pid;
1121 struct stat frstat;
1122 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1123 unsigned int entries_found;
1124 char *transport_name;
1125
1126 if (GNUNET_OK !=
1127 GNUNET_CONFIGURATION_get_value_filename (cfg, "TRANSPORT",
1128 "BLACKLIST_FILE", &fn))
1129 {
1130#if DEBUG_TRANSPORT
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Option `%s' in section `%s' not specified!\n",
1133 "BLACKLIST_FILE", "TRANSPORT");
1134#endif
1135 return;
1136 }
1137 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1138 GNUNET_DISK_fn_write (fn, NULL, 0,
1139 GNUNET_DISK_PERM_USER_READ |
1140 GNUNET_DISK_PERM_USER_WRITE);
1141 if (0 != STAT (fn, &frstat))
1142 {
1143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144 _("Could not read blacklist file `%s'\n"), fn);
1145 GNUNET_free (fn);
1146 return;
1147 }
1148 if (frstat.st_size == 0)
1149 {
1150#if DEBUG_TRANSPORT
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"),
1152 fn);
1153#endif
1154 GNUNET_free (fn);
1155 return;
1156 }
1157 /* FIXME: use mmap */
1158 data = GNUNET_malloc_large (frstat.st_size);
1159 GNUNET_assert (data != NULL);
1160 if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1161 {
1162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163 _("Failed to read blacklist from `%s'\n"), fn);
1164 GNUNET_free (fn);
1165 GNUNET_free (data);
1166 return;
1167 }
1168 entries_found = 0;
1169 pos = 0;
1170 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1171 pos++;
1172 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1173 (pos <=
1174 frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1175 {
1176 colon_pos = pos;
1177 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') &&
1178 !isspace ((unsigned char) data[colon_pos]))
1179 colon_pos++;
1180
1181 if (colon_pos >= frstat.st_size)
1182 {
1183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1184 _
1185 ("Syntax error in blacklist file at offset %llu, giving up!\n"),
1186 (unsigned long long) colon_pos);
1187 GNUNET_free (fn);
1188 GNUNET_free (data);
1189 return;
1190 }
1191
1192 if (isspace ((unsigned char) data[colon_pos]))
1193 {
1194 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1195 _
1196 ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1197 (unsigned long long) colon_pos);
1198 pos = colon_pos;
1199 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1200 pos++;
1201 continue;
1202 }
1203 tsize = colon_pos - pos;
1204 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) ||
1205 (tsize == 0))
1206 {
1207 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1208 _
1209 ("Syntax error in blacklist file at offset %llu, giving up!\n"),
1210 (unsigned long long) colon_pos);
1211 GNUNET_free (fn);
1212 GNUNET_free (data);
1213 return;
1214 }
1215
1216 if (tsize < 1)
1217 continue;
1218
1219 transport_name = GNUNET_malloc (tsize + 1);
1220 memcpy (transport_name, &data[pos], tsize);
1221 pos = colon_pos + 1;
1222#if DEBUG_TRANSPORT
1223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224 "Read transport name %s in blacklist file.\n", transport_name);
1225#endif
1226 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1227 if (!isspace
1228 ((unsigned char)
1229 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1230 {
1231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1232 _
1233 ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1234 (unsigned long long) pos);
1235 pos++;
1236 while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos])))
1237 pos++;
1238 GNUNET_free_non_null (transport_name);
1239 continue;
1240 }
1241 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1242 if (GNUNET_OK !=
1243 GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1244 {
1245 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1246 _
1247 ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1248 (unsigned long long) pos, &enc);
1249 }
1250 else
1251 {
1252 if (0 != memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1253 {
1254 entries_found++;
1255 add_peer_to_blacklist (&pid, transport_name);
1256 }
1257 else
1258 {
1259 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1260 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1261 GNUNET_i2s (&pid));
1262 }
1263 }
1264 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1265 GNUNET_free_non_null (transport_name);
1266 while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
1267 pos++;
1268 }
1269 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted",
1270 entries_found, GNUNET_NO);
1271 GNUNET_free (data);
1272 GNUNET_free (fn);
1273} 129}
1274 130
1275 131
1276/** 132/**
1277 * Function called to notify a client about the socket being ready to 133 * Function called by the transport for each received message.
1278 * queue more data. "buf" will be NULL and "size" zero if the socket 134 * This function should also be called with "NULL" for the
1279 * was closed for writing in the meantime. 135 * message to signal that the other peer disconnected.
1280 * 136 *
1281 * @param cls closure 137 * @param cls closure, const char* with the name of the plugin we received the message from
1282 * @param size number of bytes available in buf 138 * @param peer (claimed) identity of the other peer
1283 * @param buf where the callee should write the message 139 * @param message the message, NULL if we only care about
1284 * @return number of bytes written to buf 140 * learning about the delay until we should receive again -- FIXME!
141 * @param ats performance information
142 * @param ats_count number of records in ats
143 * @param session identifier used for this session (NULL for plugins
144 * that do not offer bi-directional communication to the sender
145 * using the same "connection")
146 * @param sender_address binary address of the sender (if we established the
147 * connection or are otherwise sure of it; should be NULL
148 * for inbound TCP/UDP connections since it it not clear
149 * that we could establish ourselves a connection to that
150 * IP address and get the same system)
151 * @param sender_address_len number of bytes in sender_address
152 * @return how long the plugin should wait until receiving more data
153 * (plugins that do not support this, can ignore the return value)
1285 */ 154 */
1286static size_t 155static struct GNUNET_TIME_Relative
1287transmit_to_client_callback (void *cls, size_t size, void *buf) 156plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
1288{ 157 const struct GNUNET_MessageHeader *message,
1289 struct TransportClient *client = cls; 158 const struct GNUNET_TRANSPORT_ATS_Information *ats,
1290 struct ClientMessageQueueEntry *q; 159 uint32_t ats_count, struct Session *session,
1291 uint16_t msize; 160 const char *sender_address,
1292 size_t tsize; 161 uint16_t sender_address_len)
1293 const struct GNUNET_MessageHeader *msg; 162{
1294 char *cbuf; 163 const char *plugin_name = cls;
164 int do_forward;
165 struct GNUNET_TIME_Relative ret;
166 uint16_t type;
1295 167
1296 client->th = NULL; 168 ret = GNUNET_TIME_UNIT_ZERO;
1297 if (buf == NULL) 169 if (NULL != message)
1298 { 170 {
1299#if DEBUG_TRANSPORT 171 type = ntohs (message->type);
1300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 172 switch (type)
1301 "Transmission to client failed, closing connection.\n");
1302#endif
1303 /* fatal error with client, free message queue! */
1304 while (NULL != (q = client->message_queue_head))
1305 { 173 {
1306 GNUNET_STATISTICS_update (stats, 174 case GNUNET_MESSAGE_TYPE_HELLO:
1307 gettext_noop 175 GST_validation_handle_hello (message);
1308 ("# bytes discarded (could not transmit to client)"),
1309 ntohs (((const struct GNUNET_MessageHeader *)
1310 &q[1])->size), GNUNET_NO);
1311 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1312 client->message_queue_tail, q);
1313 GNUNET_free (q);
1314 }
1315 client->message_count = 0;
1316 return 0;
1317 }
1318 cbuf = buf;
1319 tsize = 0;
1320 while (NULL != (q = client->message_queue_head))
1321 {
1322 msg = (const struct GNUNET_MessageHeader *) &q[1];
1323 msize = ntohs (msg->size);
1324 if (msize + tsize > size)
1325 break; 176 break;
177 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
1326#if DEBUG_TRANSPORT 178#if DEBUG_TRANSPORT
1327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1328 "Transmitting message of type %u to client.\n", 180 "Processing `%s' from `%s'\n", "PING",
1329 ntohs (msg->type)); 181 (sender_address != NULL) ? GST_plugins_a2s (plugin_name,
1330#endif 182 sender_address,
1331 GNUNET_CONTAINER_DLL_remove (client->message_queue_head, 183 sender_address_len)
1332 client->message_queue_tail, q); 184 : "<inbound>");
1333 memcpy (&cbuf[tsize], msg, msize);
1334 tsize += msize;
1335 GNUNET_free (q);
1336 client->message_count--;
1337 }
1338 if (NULL != q)
1339 {
1340 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1341 client->th =
1342 GNUNET_SERVER_notify_transmit_ready (client->client, msize,
1343 GNUNET_TIME_UNIT_FOREVER_REL,
1344 &transmit_to_client_callback,
1345 client);
1346 GNUNET_assert (client->th != NULL);
1347 }
1348 return tsize;
1349}
1350
1351
1352/**
1353 * Convert an address to a string.
1354 *
1355 * @param plugin name of the plugin responsible for the address
1356 * @param addr binary address
1357 * @param addr_len number of bytes in addr
1358 * @return NULL on error, otherwise address string
1359 */
1360static const char *
1361a2s (const char *plugin, const void *addr, uint16_t addr_len)
1362{
1363 struct TransportPlugin *p;
1364
1365 if (plugin == NULL)
1366 return NULL;
1367 p = find_transport (plugin);
1368 if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1369 return NULL;
1370 return p->api->address_to_string (NULL, addr, addr_len);
1371}
1372
1373
1374
1375
1376/**
1377 * Iterator to free entries in the validation_map.
1378 *
1379 * @param cls closure (unused)
1380 * @param key current key code
1381 * @param value value in the hash map (validation to abort)
1382 * @return GNUNET_YES (always)
1383 */
1384static int
1385abort_validation (void *cls, const GNUNET_HashCode * key, void *value)
1386{
1387 struct ValidationEntry *va = value;
1388
1389 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1390 GNUNET_SCHEDULER_cancel (va->timeout_task);
1391 GNUNET_free (va->transport_name);
1392 if (va->chvc != NULL)
1393 {
1394 va->chvc->ve_count--;
1395 if (va->chvc->ve_count == 0)
1396 {
1397 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, va->chvc);
1398 GNUNET_free (va->chvc);
1399 }
1400 va->chvc = NULL;
1401 }
1402 GNUNET_free (va);
1403 return GNUNET_YES;
1404}
1405
1406
1407/**
1408 * HELLO validation cleanup task (validation failed).
1409 *
1410 * @param cls the 'struct ValidationEntry' that failed
1411 * @param tc scheduler context (unused)
1412 */
1413static void
1414timeout_hello_validation (void *cls,
1415 const struct GNUNET_SCHEDULER_TaskContext *tc)
1416{
1417 struct ValidationEntry *va = cls;
1418 struct GNUNET_PeerIdentity pid;
1419
1420 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1421 GNUNET_STATISTICS_update (stats,
1422 gettext_noop ("# address validation timeouts"), 1,
1423 GNUNET_NO);
1424 GNUNET_CRYPTO_hash (&va->publicKey,
1425 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1426 &pid.hashPubKey);
1427 GNUNET_break (GNUNET_OK ==
1428 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1429 &pid.hashPubKey, va));
1430 abort_validation (NULL, NULL, va);
1431}
1432
1433
1434
1435/**
1436 * Send the specified message to the specified client. Since multiple
1437 * messages may be pending for the same client at a time, this code
1438 * makes sure that no message is lost.
1439 *
1440 * @param client client to transmit the message to
1441 * @param msg the message to send
1442 * @param may_drop can this message be dropped if the
1443 * message queue for this client is getting far too large?
1444 */
1445static void
1446transmit_to_client (struct TransportClient *client,
1447 const struct GNUNET_MessageHeader *msg, int may_drop)
1448{
1449 struct ClientMessageQueueEntry *q;
1450 uint16_t msize;
1451
1452 /* Client==NULL when GNUNET_SERVER_Client disconnected and was
1453 * freed in client_disconnect_notification
1454 */
1455 if (client->client == NULL)
1456 {
1457 GNUNET_break (0);
1458 return;
1459 }
1460
1461 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1462 {
1463 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1464 _
1465 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1466 ntohs (msg->type), ntohs (msg->size), client->message_count,
1467 MAX_PENDING);
1468 GNUNET_STATISTICS_update (stats,
1469 gettext_noop
1470 ("# messages dropped due to slow client"), 1,
1471 GNUNET_NO);
1472 return;
1473 }
1474 msize = ntohs (msg->size);
1475 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1476 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1477 memcpy (&q[1], msg, msize);
1478 GNUNET_CONTAINER_DLL_insert_tail (client->message_queue_head,
1479 client->message_queue_tail, q);
1480 client->message_count++;
1481 if (client->th == NULL)
1482 {
1483 client->th =
1484 GNUNET_SERVER_notify_transmit_ready (client->client, msize,
1485 GNUNET_TIME_UNIT_FOREVER_REL,
1486 &transmit_to_client_callback,
1487 client);
1488 GNUNET_assert (client->th != NULL);
1489 }
1490}
1491
1492
1493/**
1494 * Transmit a 'SEND_OK' notification to the given client for the
1495 * given neighbour.
1496 *
1497 * @param client who to notify
1498 * @param n neighbour to notify about, can be NULL (on failure)
1499 * @param target target of the transmission
1500 * @param result status code for the transmission request
1501 */
1502static void
1503transmit_send_ok (struct TransportClient *client, struct NeighbourMapEntry *n,
1504 const struct GNUNET_PeerIdentity *target, int result)
1505{
1506 struct SendOkMessage send_ok_msg;
1507
1508 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1509 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1510 send_ok_msg.success = htonl (result);
1511 if (n != NULL)
1512 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1513 else
1514 send_ok_msg.latency =
1515 GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1516 send_ok_msg.peer = *target;
1517 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1518}
1519
1520
1521/**
1522 * Mark the given FAL entry as 'connected' (and hence preferred for
1523 * sending); also mark all others for the same peer as 'not connected'
1524 * (since only one can be preferred).
1525 *
1526 * @param fal address to set to 'connected'
1527 */
1528static void
1529mark_address_connected (struct ForeignAddressList *fal);
1530
1531
1532
1533/**
1534 * We should re-try transmitting to the given peer,
1535 * hopefully we've learned something in the meantime.
1536 */
1537static void
1538retry_transmission_task (void *cls,
1539 const struct GNUNET_SCHEDULER_TaskContext *tc)
1540{
1541 struct NeighbourMapEntry *n = cls;
1542
1543 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1544 try_transmission_to_peer (n);
1545}
1546
1547
1548/**
1549 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1550 * upon "completion" of a send request. This tells the API
1551 * that it is now legal to send another message to the given
1552 * peer.
1553 *
1554 * @param cls closure, identifies the entry on the
1555 * message queue that was transmitted and the
1556 * client responsible for queuing the message
1557 * @param target the peer receiving the message
1558 * @param result GNUNET_OK on success, if the transmission
1559 * failed, we should not tell the client to transmit
1560 * more messages
1561 */
1562static void
1563transmit_send_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
1564 int result)
1565{
1566 struct MessageQueue *mq = cls;
1567 struct NeighbourMapEntry *n;
1568
1569 GNUNET_STATISTICS_update (stats,
1570 gettext_noop ("# bytes pending with plugins"),
1571 -(int64_t) mq->message_buf_size, GNUNET_NO);
1572 if (result == GNUNET_OK)
1573 {
1574 GNUNET_STATISTICS_update (stats,
1575 gettext_noop
1576 ("# bytes successfully transmitted by plugins"),
1577 mq->message_buf_size, GNUNET_NO);
1578 }
1579 else
1580 {
1581 GNUNET_STATISTICS_update (stats,
1582 gettext_noop
1583 ("# bytes with transmission failure by plugins"),
1584 mq->message_buf_size, GNUNET_NO);
1585 }
1586 if (mq->specific_address != NULL)
1587 {
1588 if (result == GNUNET_OK)
1589 {
1590 mq->specific_address->timeout =
1591 GNUNET_TIME_relative_to_absolute
1592 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1593 if (mq->specific_address->validated == GNUNET_YES)
1594 mark_address_connected (mq->specific_address);
1595 }
1596 else
1597 {
1598 if (mq->specific_address->connected == GNUNET_YES)
1599 {
1600#if DEBUG_TRANSPORT
1601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1602 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1603 a2s (mq->specific_address->ready_list->plugin->short_name,
1604 mq->specific_address->addr,
1605 mq->specific_address->addrlen));
1606#endif
1607 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1608 -1, GNUNET_NO);
1609 mq->specific_address->connected = GNUNET_NO;
1610 }
1611 }
1612 if (!mq->internal_msg)
1613 mq->specific_address->in_transmit = GNUNET_NO;
1614 }
1615 n = find_neighbour (&mq->neighbour_id);
1616 if (n != NULL)
1617 {
1618 if (mq->client != NULL)
1619 transmit_send_ok (mq->client, n, target, result);
1620 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
1621 if (result == GNUNET_OK)
1622 try_transmission_to_peer (n);
1623 else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1624 n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task, n);
1625 }
1626 else
1627 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "transmit_send_continuation",
1628 "Neighbour `%s' no longer exists\n",
1629 GNUNET_i2s (&mq->neighbour_id));
1630 GNUNET_free (mq);
1631}
1632
1633
1634/**
1635 * Check the ready list for the given neighbour and if a plugin is
1636 * ready for transmission (and if we have a message), do so!
1637 *
1638 * @param neighbour target peer for which to transmit
1639 */
1640static void
1641try_transmission_to_peer (struct NeighbourMapEntry *n)
1642{
1643 struct ReadyList *rl;
1644 struct MessageQueue *mq;
1645 struct GNUNET_TIME_Relative timeout;
1646 ssize_t ret;
1647 int force_address;
1648
1649 if (n->messages_head == NULL)
1650 {
1651#if DEBUG_TRANSPORT
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Transmission queue for `%4s' is empty\n", GNUNET_i2s (&n->id));
1654#endif
1655 return; /* nothing to do */
1656 }
1657 rl = NULL;
1658 mq = n->messages_head;
1659 force_address = GNUNET_YES;
1660 if (mq->specific_address == NULL)
1661 {
1662 /* TODO: ADD ATS */
1663 mq->specific_address = get_preferred_ats_address (n);
1664 GNUNET_STATISTICS_update (stats,
1665 gettext_noop
1666 ("# transport selected peer address freely"), 1,
1667 GNUNET_NO);
1668 force_address = GNUNET_NO;
1669 }
1670 if (mq->specific_address == NULL)
1671 {
1672 GNUNET_STATISTICS_update (stats,
1673 gettext_noop
1674 ("# transport failed to selected peer address"),
1675 1, GNUNET_NO);
1676 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1677 if (timeout.rel_value == 0)
1678 {
1679#if DEBUG_TRANSPORT
1680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1681 "No destination address available to transmit message of size %u to peer `%4s'\n",
1682 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id));
1683#endif
1684 GNUNET_STATISTICS_update (stats,
1685 gettext_noop
1686 ("# bytes in message queue for other peers"),
1687 -(int64_t) mq->message_buf_size, GNUNET_NO);
1688 GNUNET_STATISTICS_update (stats,
1689 gettext_noop
1690 ("# bytes discarded (no destination address available)"),
1691 mq->message_buf_size, GNUNET_NO);
1692 if (mq->client != NULL)
1693 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1694 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1695 GNUNET_free (mq);
1696 return; /* nobody ready */
1697 }
1698 GNUNET_STATISTICS_update (stats,
1699 gettext_noop
1700 ("# message delivery deferred (no address)"), 1,
1701 GNUNET_NO);
1702 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1703 GNUNET_SCHEDULER_cancel (n->retry_task);
1704 n->retry_task =
1705 GNUNET_SCHEDULER_add_delayed (timeout, &retry_transmission_task, n);
1706#if DEBUG_TRANSPORT
1707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1708 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1709 mq->message_buf_size, GNUNET_i2s (&mq->neighbour_id),
1710 timeout.rel_value);
1711#endif 185#endif
1712 /* FIXME: might want to trigger peerinfo lookup here 186 GST_validation_handle_ping (peer, message, plugin_name, session,
1713 * (unless that's already pending...) */ 187 sender_address, sender_address_len);
1714 return; 188 break;
1715 } 189 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
1716 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
1717 if (mq->specific_address->connected == GNUNET_NO)
1718 mq->specific_address->connect_attempts++;
1719 rl = mq->specific_address->ready_list;
1720 mq->plugin = rl->plugin;
1721 if (!mq->internal_msg)
1722 mq->specific_address->in_transmit = GNUNET_YES;
1723#if DEBUG_TRANSPORT 190#if DEBUG_TRANSPORT
1724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1725 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n", 192 "Processing `%s' from `%s'\n", "PONG",
1726 mq->message_buf_size, GNUNET_i2s (&n->id), 193 (sender_address != NULL) ? GST_plugins_a2s (plugin_name,
1727 (mq->specific_address->addr != 194 sender_address,
1728 NULL) ? a2s (mq->plugin->short_name, mq->specific_address->addr, 195 sender_address_len)
1729 mq->specific_address->addrlen) : "<inbound>", 196 : "<inbound>");
1730 rl->plugin->short_name);
1731#endif 197#endif
1732 GNUNET_STATISTICS_update (stats, 198 GST_validation_handle_pong (peer, message);
1733 gettext_noop 199 break;
1734 ("# bytes in message queue for other peers"), 200 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT:
1735 -(int64_t) mq->message_buf_size, GNUNET_NO); 201 (void) GST_blacklist_test_allowed (peer, NULL, &try_connect_if_allowed,
1736 GNUNET_STATISTICS_update (stats, 202 NULL);
1737 gettext_noop ("# bytes pending with plugins"), 203 /* TODO: if 'session != NULL', and timestamp more recent than the
1738 mq->message_buf_size, GNUNET_NO); 204 * previous one, maybe notify ATS that this is now the preferred
1739 205 * * way to communicate with this peer (other peer switched transport) */
1740 GNUNET_CONTAINER_DLL_insert (n->cont_head, n->cont_tail, mq); 206 break;
1741 207 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
1742 ret = 208 /* TODO: do some validation to prevent an attacker from sending
1743 rl->plugin->api->send (rl->plugin->api->cls, &mq->neighbour_id, 209 * a fake disconnect message... */
1744 mq->message_buf, mq->message_buf_size, 210 GST_neighbours_force_disconnect (peer);
1745 mq->priority, 211 break;
1746 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 212 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
1747 mq->specific_address->session, 213 GST_neighbours_keepalive (peer);
1748 mq->specific_address->addr, 214 break;
1749 mq->specific_address->addrlen, force_address, 215 default:
1750 &transmit_send_continuation, mq); 216 /* should be payload */
1751 if (ret == -1) 217 do_forward = GNUNET_SYSERR;
1752 { 218 ret =
1753 /* failure, but 'send' would not call continuation in this case, 219 GST_neighbours_calculate_receive_delay (peer,
1754 * so we need to do it here! */ 220 (message ==
1755 transmit_send_continuation (mq, &mq->neighbour_id, GNUNET_SYSERR); 221 NULL) ? 0 :
1756 } 222 ntohs (message->size),
1757} 223 &do_forward);
1758 224 if (do_forward == GNUNET_YES)
1759
1760/**
1761 * Send the specified message to the specified peer.
1762 *
1763 * @param client source of the transmission request (can be NULL)
1764 * @param peer_address ForeignAddressList where we should send this message
1765 * @param priority how important is the message
1766 * @param timeout how long do we have to transmit?
1767 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1768 * @param message_buf_size total size of all messages in message_buf
1769 * @param is_internal is this an internal message; these are pre-pended and
1770 * also do not count for plugins being "ready" to transmit
1771 * @param neighbour handle to the neighbour for transmission
1772 */
1773static void
1774transmit_to_peer (struct TransportClient *client,
1775 struct ForeignAddressList *peer_address,
1776 unsigned int priority, struct GNUNET_TIME_Relative timeout,
1777 const char *message_buf, size_t message_buf_size,
1778 int is_internal, struct NeighbourMapEntry *neighbour)
1779{
1780 struct MessageQueue *mq;
1781
1782#if EXTRA_CHECKS
1783 if (client != NULL)
1784 {
1785 /* check for duplicate submission */
1786 mq = neighbour->messages_head;
1787 while (NULL != mq)
1788 {
1789 if (mq->client == client)
1790 { 225 {
1791 /* client transmitted to same peer twice 226 struct InboundMessage *im;
1792 * before getting SEND_OK! */ 227 size_t size = sizeof (struct InboundMessage) + ntohs (message->size);
1793 GNUNET_break (0);
1794 return;
1795 }
1796 mq = mq->next;
1797 }
1798 }
1799#endif
1800 GNUNET_STATISTICS_update (stats,
1801 gettext_noop
1802 ("# bytes in message queue for other peers"),
1803 message_buf_size, GNUNET_NO);
1804 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1805 mq->specific_address = peer_address;
1806 mq->client = client;
1807 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1808 memcpy (&mq[1], message_buf, message_buf_size);
1809 mq->message_buf = (const char *) &mq[1];
1810 mq->message_buf_size = message_buf_size;
1811 memcpy (&mq->neighbour_id, &neighbour->id,
1812 sizeof (struct GNUNET_PeerIdentity));
1813 mq->internal_msg = is_internal;
1814 mq->priority = priority;
1815 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1816 if (is_internal)
1817 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1818 neighbour->messages_tail, mq);
1819 else
1820 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1821 neighbour->messages_tail,
1822 neighbour->messages_tail, mq);
1823 try_transmission_to_peer (neighbour);
1824}
1825
1826
1827/**
1828 * Send a plain PING (without address or our HELLO) to the given
1829 * foreign address to try to establish a connection (and validate
1830 * that the other peer is really who he claimed he is).
1831 *
1832 * @param n neighbour to PING
1833 */
1834static void
1835transmit_plain_ping (struct NeighbourMapEntry *n)
1836{
1837 struct ValidationEntry *ve;
1838 struct TransportPingMessage ping;
1839 struct ReadyList *rl;
1840 struct TransportPlugin *plugin;
1841 struct ForeignAddressList *fal;
1842
1843 if (!n->public_key_valid)
1844 {
1845 /* This should not happen since the other peer
1846 * should send us a HELLO prior to sending his
1847 * PING */
1848 GNUNET_break_op (0);
1849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1850 "Could not transmit plain PING to `%s': public key not known\n",
1851 GNUNET_i2s (&n->id));
1852 return;
1853 }
1854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1855 "Looking for addresses to transmit plain PING to `%s'\n",
1856 GNUNET_i2s (&n->id));
1857 for (rl = n->plugins; rl != NULL; rl = rl->next)
1858 {
1859 plugin = rl->plugin;
1860 for (fal = rl->addresses; fal != NULL; fal = fal->next)
1861 {
1862 if (!fal->connected)
1863 continue;
1864 ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1865 ve->transport_name = GNUNET_strdup (plugin->short_name);
1866 ve->challenge =
1867 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
1868 ve->send_time = GNUNET_TIME_absolute_get ();
1869 ve->session = fal->session;
1870 memcpy (&ve->publicKey, &n->publicKey,
1871 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1872 ve->timeout_task =
1873 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1874 &timeout_hello_validation, ve);
1875 GNUNET_CONTAINER_multihashmap_put (validation_map, &n->id.hashPubKey, ve,
1876 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1877 ping.header.size = htons (sizeof (struct TransportPingMessage));
1878 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1879 ping.challenge = htonl (ve->challenge);
1880 memcpy (&ping.target, &n->id, sizeof (struct GNUNET_PeerIdentity));
1881 GNUNET_STATISTICS_update (stats,
1882 gettext_noop
1883 ("# PING without HELLO messages sent"), 1,
1884 GNUNET_NO);
1885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s'\n",
1886 GNUNET_i2s (&n->id));
1887 transmit_to_peer (NULL, fal, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1888 HELLO_VERIFICATION_TIMEOUT, (const char *) &ping,
1889 sizeof (ping), GNUNET_YES, n);
1890 }
1891 }
1892}
1893
1894
1895/**
1896 * Mark the given FAL entry as 'connected' (and hence preferred for
1897 * sending); also mark all others for the same peer as 'not connected'
1898 * (since only one can be preferred).
1899 *
1900 * @param fal address to set to 'connected'
1901 */
1902static void
1903mark_address_connected (struct ForeignAddressList *fal)
1904{
1905 struct ForeignAddressList *pos;
1906 struct ForeignAddressList *inbound;
1907 struct ForeignAddressList *outbound;
1908
1909 GNUNET_assert (GNUNET_YES == fal->validated);
1910 if (fal->connected == GNUNET_YES)
1911 return; /* nothing to do */
1912 inbound = NULL;
1913 outbound = NULL;
1914
1915 pos = fal->ready_list->addresses;
1916 while (pos != NULL)
1917 {
1918 /* Already have inbound address, and this is also an inbound address, don't switch!! */
1919 if ((GNUNET_YES == pos->connected) && (0 == pos->addrlen) &&
1920 (0 == fal->addrlen))
1921 return;
1922 if ((0 == pos->addrlen) && (GNUNET_YES == pos->connected))
1923 inbound = pos;
1924 pos = pos->next;
1925 }
1926
1927 pos = fal->ready_list->addresses;
1928 while (pos != NULL)
1929 {
1930 /* Already have outbound address, and this is also an outbound address, don't switch!! */
1931 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen) &&
1932 (0 < fal->addrlen))
1933 return;
1934 if ((0 < pos->addrlen) && (GNUNET_YES == pos->connected))
1935 outbound = pos;
1936 pos = pos->next;
1937 }
1938
1939#if DEBUG_INBOUND
1940 if (inbound != NULL)
1941 fprintf (stderr, "Peer: %s, have inbound connection.\n",
1942 GNUNET_i2s (&my_identity));
1943 if (outbound != NULL)
1944 fprintf (stderr, "Peer: %s, have outbound connection.\n",
1945 GNUNET_i2s (&my_identity));
1946#endif
1947
1948 /* Have an inbound connection to this peer which is valid; our id is lower, ignore outbound connection! */
1949 if ((inbound != NULL) && (0 != fal->addrlen) &&
1950 (1 ==
1951 GNUNET_CRYPTO_hash_xorcmp (&inbound->ready_list->neighbour->id.
1952 hashPubKey, &my_identity.hashPubKey,
1953 &null_hash)))
1954 {
1955#if DEBUG_INBOUND
1956 fprintf (stderr, "Peer: %s, had inbound connection, ignoring outbound!\n",
1957 GNUNET_i2s (&my_identity));
1958#endif
1959 return;
1960 }
1961 else if ((outbound != NULL) && (0 == fal->addrlen) &&
1962 ((-1 ==
1963 GNUNET_CRYPTO_hash_xorcmp (&outbound->ready_list->neighbour->
1964 id.hashPubKey, &my_identity.hashPubKey,
1965 &null_hash))))
1966 {
1967#if DEBUG_INBOUND
1968 fprintf (stderr, "Peer: %s, have outbound connection, ignoring inbound!\n",
1969 GNUNET_i2s (&my_identity));
1970#endif
1971 return;
1972 }
1973
1974 pos = fal->ready_list->addresses;
1975 while (pos != NULL)
1976 {
1977 if ((GNUNET_YES == pos->connected) && (0 < pos->addrlen))
1978 {
1979#if DEBUG_TRANSPORT
1980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1981 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1982 a2s (pos->ready_list->plugin->short_name, pos->addr,
1983 pos->addrlen));
1984#endif
1985#if DEBUG_INBOUND
1986 fprintf (stderr, "Peer: %s, setting %s connection to disconnected.\n",
1987 GNUNET_i2s (&my_identity),
1988 (0 == pos->addrlen) ? "INBOUND" : "OUTBOUND");
1989#endif
1990 pos->connected = GNUNET_NO;
1991 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
1992 -1, GNUNET_NO);
1993 }
1994 pos = pos->next;
1995 }
1996 GNUNET_assert (GNUNET_NO == fal->connected);
1997 fal->connected = GNUNET_YES;
1998 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), 1,
1999 GNUNET_NO);
2000}
2001 228
229 im = GNUNET_malloc (size);
230 im->header.size = htons (size);
231 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
232 im->ats_count = htonl (0);
233 memcpy (&(im->peer), peer, sizeof (struct GNUNET_PeerIdentity));
234 memcpy (&im[1], message, ntohs (message->size));
2002 235
2003/** 236 GST_clients_broadcast ((const struct GNUNET_MessageHeader *) im,
2004 * Find an address in any of the available transports for 237 GNUNET_YES);
2005 * the given neighbour that would be good for message
2006 * transmission. This is essentially the transport selection
2007 * routine.
2008 *
2009 * @param neighbour for whom to select an address
2010 * @return selected address, NULL if we have none
2011 */
2012struct ForeignAddressList *
2013find_ready_address (struct NeighbourMapEntry *neighbour)
2014{
2015 struct ReadyList *head = neighbour->plugins;
2016 struct ForeignAddressList *addresses;
2017 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
2018 struct ForeignAddressList *best_address;
2019
2020 /* Hack to prefer unix domain sockets */
2021 struct ForeignAddressList *unix_address = NULL;
2022
2023 best_address = NULL;
2024 while (head != NULL)
2025 {
2026 addresses = head->addresses;
2027 while (addresses != NULL)
2028 {
2029 if ((addresses->timeout.abs_value < now.abs_value) &&
2030 (addresses->connected == GNUNET_YES))
2031 {
2032#if DEBUG_TRANSPORT
2033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2034 "Marking long-time inactive connection to `%4s' as down.\n",
2035 GNUNET_i2s (&neighbour->id));
2036#endif
2037 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
2038 -1, GNUNET_NO);
2039 addresses->connected = GNUNET_NO;
2040 }
2041 addresses = addresses->next;
2042 }
2043 238
2044 addresses = head->addresses; 239 GNUNET_free (im);
2045 while (addresses != NULL)
2046 {
2047#if DEBUG_TRANSPORT
2048 if (addresses->addr != NULL)
2049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2050 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2051 a2s (head->plugin->short_name, addresses->addr,
2052 addresses->addrlen), GNUNET_i2s (&neighbour->id),
2053 addresses->connected, addresses->in_transmit,
2054 addresses->validated, addresses->connect_attempts,
2055 (unsigned long long) addresses->timeout.abs_value,
2056 (unsigned int) addresses->distance);
2057#endif
2058 if (0 == strcmp (head->plugin->short_name, "unix"))
2059 {
2060 if ((unix_address == NULL) ||
2061 ((unix_address != NULL) &&
2062 (addresses->latency.rel_value < unix_address->latency.rel_value)))
2063 unix_address = addresses;
2064 } 240 }
2065 if (((best_address == NULL) || (addresses->connected == GNUNET_YES) ||
2066 (best_address->connected == GNUNET_NO)) &&
2067 (addresses->in_transmit == GNUNET_NO) && ((best_address == NULL) ||
2068 (addresses->
2069 latency.rel_value <
2070 best_address->
2071 latency.rel_value)))
2072 best_address = addresses;
2073 /* FIXME: also give lower-latency addresses that are not
2074 * connected a chance some times... */
2075 addresses = addresses->next;
2076 }
2077 if (unix_address != NULL)
2078 break; 241 break;
2079 head = head->next; 242 }
2080 }
2081 if (unix_address != NULL)
2082 {
2083 best_address = unix_address;
2084#if DEBUG_TRANSPORT
2085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2086 "Found UNIX address, forced this address\n");
2087#endif
2088 }
2089 if (best_address != NULL)
2090 {
2091#if DEBUG_TRANSPORT
2092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2093 "Best address found (`%s') has latency of %llu ms.\n",
2094 (best_address->addrlen >
2095 0) ? a2s (best_address->ready_list->plugin->short_name,
2096 best_address->addr,
2097 best_address->addrlen) : "<inbound>",
2098 best_address->latency.rel_value);
2099#endif
2100 }
2101 else
2102 {
2103 GNUNET_STATISTICS_update (stats,
2104 gettext_noop
2105 ("# transmission attempts failed (no address)"),
2106 1, GNUNET_NO);
2107 } 243 }
2108 244
2109 return best_address; 245 GNUNET_assert ((ats_count > 0) && (ats != NULL));
2110}
2111
2112
2113/**
2114 * FIXME: document.
2115 */
2116struct GeneratorContext
2117{
2118 struct TransportPlugin *plug_pos;
2119 struct OwnAddressList *addr_pos;
2120 struct GNUNET_TIME_Absolute expiration;
2121};
2122
2123
2124/**
2125 * FIXME: document.
2126 */
2127static size_t
2128address_generator (void *cls, size_t max, void *buf)
2129{
2130 struct GeneratorContext *gc = cls;
2131 size_t ret;
2132 246
2133 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL)) 247 GNUNET_ATS_address_update (GST_ats, peer, GNUNET_TIME_absolute_get (), /* valid at least until right now... */
2134 { 248 plugin_name, session, sender_address,
2135 gc->plug_pos = gc->plug_pos->next; 249 sender_address_len, ats, ats_count);
2136 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2137 }
2138 if (NULL == gc->plug_pos)
2139 {
2140 250
2141 return 0;
2142 }
2143 ret =
2144 GNUNET_HELLO_add_address (gc->plug_pos->short_name, gc->expiration,
2145 &gc->addr_pos[1], gc->addr_pos->addrlen, buf,
2146 max);
2147 gc->addr_pos = gc->addr_pos->next;
2148 return ret; 251 return ret;
2149} 252}
2150 253
2151 254
2152
2153static int
2154transmit_our_hello_if_pong (void *cls, const GNUNET_HashCode * key, void *value)
2155{
2156 struct NeighbourMapEntry *npos = value;
2157
2158 if (GNUNET_YES != npos->received_pong)
2159 return GNUNET_OK;
2160#if DEBUG_TRANSPORT
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2162 "Transmitting updated `%s' to neighbour `%4s'\n", "HELLO",
2163 GNUNET_i2s (&npos->id));
2164#endif
2165 GNUNET_STATISTICS_update (stats,
2166 gettext_noop
2167 ("# transmitted my HELLO to other peers"), 1,
2168 GNUNET_NO);
2169 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
2170 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
2171 GNUNET_NO, npos);
2172 return GNUNET_OK;
2173}
2174
2175
2176/**
2177 * Construct our HELLO message from all of the addresses of
2178 * all of the transports.
2179 *
2180 * @param cls unused
2181 * @param tc scheduler context
2182 */
2183static void
2184refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2185{
2186 struct GNUNET_HELLO_Message *hello;
2187 struct TransportClient *cpos;
2188 struct GeneratorContext gc;
2189
2190 hello_task = GNUNET_SCHEDULER_NO_TASK;
2191 gc.plug_pos = plugins;
2192 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2193 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2194 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2195#if DEBUG_TRANSPORT
2196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2197 "Refreshed my `%s', new size is %d\n", "HELLO",
2198 GNUNET_HELLO_size (hello));
2199#endif
2200 GNUNET_STATISTICS_update (stats, gettext_noop ("# refreshed my HELLO"), 1,
2201 GNUNET_NO);
2202 cpos = clients;
2203 while (cpos != NULL)
2204 {
2205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting my HELLO to client!\n");
2206 transmit_to_client (cpos, (const struct GNUNET_MessageHeader *) hello,
2207 GNUNET_NO);
2208 cpos = cpos->next;
2209 }
2210
2211 GNUNET_free_non_null (our_hello);
2212 our_hello = hello;
2213 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2214 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
2215 &transmit_our_hello_if_pong, NULL);
2216}
2217
2218
2219/**
2220 * Schedule task to refresh hello (unless such a
2221 * task exists already).
2222 */
2223static void
2224refresh_hello ()
2225{
2226#if DEBUG_TRANSPORT_HELLO
2227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "refresh_hello() called!\n");
2228#endif
2229 if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2230 return;
2231 hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
2232}
2233
2234
2235/**
2236 * Iterator over hash map entries that NULLs the session of validation
2237 * entries that match the given session.
2238 *
2239 * @param cls closure (the 'struct Session*' to match against)
2240 * @param key current key code (peer ID, not used)
2241 * @param value value in the hash map ('struct ValidationEntry*')
2242 * @return GNUNET_YES (we should continue to iterate)
2243 */
2244static int
2245remove_session_validations (void *cls, const GNUNET_HashCode * key, void *value)
2246{
2247 struct Session *session = cls;
2248 struct ValidationEntry *ve = value;
2249
2250 if (session == ve->session)
2251 ve->session = NULL;
2252 return GNUNET_YES;
2253}
2254
2255
2256/** 255/**
2257 * We've been disconnected from the other peer (for some 256 * Function that will be called for each address the transport
2258 * connection-oriented transport). Either quickly 257 * is aware that it might be reachable under. Update our HELLO.
2259 * re-establish the connection or signal the disconnect
2260 * to the CORE.
2261 * 258 *
2262 * Only signal CORE level disconnect if ALL addresses 259 * @param cls name of the plugin (const char*)
2263 * for the peer are exhausted. 260 * @param add_remove should the address added (YES) or removed (NO) from the
2264 * 261 * set of valid addresses?
2265 * @param p overall plugin context 262 * @param addr one of the addresses of the host
2266 * @param nl neighbour that was disconnected 263 * the specific address format depends on the transport
264 * @param addrlen length of the address
2267 */ 265 */
2268static void 266static void
2269try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl) 267plugin_env_address_change_notification (void *cls, int add_remove,
268 const void *addr, size_t addrlen)
2270{ 269{
2271 /* FIXME-MW: fast reconnect / transport switching not implemented... */ 270 const char *plugin_name = cls;
2272 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "try_fast_reconnect not implemented!\n");
2273 /* Note: the idea here is to hide problems with transports (or
2274 * switching between plugins) from the core to eliminate the need to
2275 * re-negotiate session keys and the like; OTOH, we should tell core
2276 * quickly (much faster than timeout) `if a connection was lost and
2277 * could not be re-established (i.e. other peer went down or is
2278 * unable / refuses to communicate);
2279 *
2280 * So we should consider:
2281 * 1) ideally: our own willingness / need to connect
2282 * 2) prior failures to connect to this peer (by plugin)
2283 * 3) ideally: reasons why other peer terminated (as far as knowable)
2284 *
2285 * Most importantly, it must be POSSIBLE for another peer to terminate
2286 * a connection for a while (without us instantly re-establishing it).
2287 * Similarly, if another peer is gone we should quickly notify CORE.
2288 * OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2289 * on the other end), we should reconnect in such a way that BOTH CORE
2290 * services never even notice.
2291 * Furthermore, the same mechanism (or small variation) could be used
2292 * to switch to a better-performing plugin (ATS).
2293 *
2294 * Finally, this needs to be tested throughly... */
2295
2296 /*
2297 * GNUNET_NO in the call below makes transport disconnect the peer,
2298 * even if only a single address (out of say, six) went away. This
2299 * function must be careful to ONLY disconnect if the peer is gone,
2300 * not just a specific address.
2301 *
2302 * More specifically, half the places it was used had it WRONG.
2303 */
2304 271
2305 /* No reconnect, signal disconnect instead! */ 272 GST_hello_modify_addresses (add_remove, plugin_name, addr, addrlen);
2306#if DEBUG_TRANSPORT
2307#endif
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2309 GNUNET_i2s (&nl->id), "try_fast_reconnect");
2310
2311 GNUNET_STATISTICS_update (stats,
2312 gettext_noop
2313 ("# disconnects due to try_fast_reconnect"), 1,
2314 GNUNET_NO);
2315#if DISCONNECT || 1
2316 disconnect_neighbour (nl, GNUNET_YES);
2317#endif
2318} 273}
2319 274
2320 275
@@ -2323,7 +278,9 @@ try_fast_reconnect (struct TransportPlugin *p, struct NeighbourMapEntry *nl)
2323 * cleans up a session pointer and hence the service needs to 278 * cleans up a session pointer and hence the service needs to
2324 * discard all of those sessions as well. Plugins that do not 279 * discard all of those sessions as well. Plugins that do not
2325 * use sessions can simply omit calling this function and always 280 * use sessions can simply omit calling this function and always
2326 * use NULL wherever a session pointer is needed. 281 * use NULL wherever a session pointer is needed. This function
282 * should be called BEFORE a potential "TransmitContinuation"
283 * from the "TransmitFunction".
2327 * 284 *
2328 * @param cls closure 285 * @param cls closure
2329 * @param peer which peer was the session for 286 * @param peer which peer was the session for
@@ -2333,3683 +290,87 @@ static void
2333plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer, 290plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
2334 struct Session *session) 291 struct Session *session)
2335{ 292{
2336 struct TransportPlugin *p = cls; 293 GST_neighbours_session_terminated (peer, session);
2337 struct NeighbourMapEntry *nl;
2338 struct ReadyList *rl;
2339 struct ForeignAddressList *pos;
2340 struct ForeignAddressList *prev;
2341
2342#if DEBUG_TRANSPORT
2343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session ended with peer `%4s', %s\n",
2344 GNUNET_i2s (peer), "plugin_env_session_end");
2345#endif
2346 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2347 &remove_session_validations, session);
2348 nl = find_neighbour (peer);
2349 if (nl == NULL)
2350 {
2351#if DEBUG_TRANSPORT
2352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353 "No neighbour record found for peer `%4s'\n",
2354 GNUNET_i2s (peer));
2355#endif
2356 return; /* was never marked as connected */
2357 }
2358 rl = nl->plugins;
2359 while (rl != NULL)
2360 {
2361 if (rl->plugin == p)
2362 break;
2363 rl = rl->next;
2364 }
2365 if (rl == NULL)
2366 {
2367#if DEBUG_TRANSPORT
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Plugin was associated with peer `%4s'\n", GNUNET_i2s (peer));
2370#endif
2371 GNUNET_STATISTICS_update (stats,
2372 gettext_noop ("# disconnects due to session end"),
2373 1, GNUNET_NO);
2374 disconnect_neighbour (nl, GNUNET_YES);
2375 return;
2376 }
2377 prev = NULL;
2378 pos = rl->addresses;
2379 while ((pos != NULL) && (pos->session != session))
2380 {
2381 prev = pos;
2382 pos = pos->next;
2383 }
2384 if (pos == NULL)
2385 {
2386#if DEBUG_TRANSPORT
2387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388 "Session was never marked as ready for peer `%4s'\n",
2389 GNUNET_i2s (peer));
2390#endif
2391
2392 int validations_pending =
2393 GNUNET_CONTAINER_multihashmap_contains (validation_map,
2394 &peer->hashPubKey);
2395
2396 /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2397 if (validations_pending == GNUNET_YES)
2398 {
2399#if DEBUG_TRANSPORT
2400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401 "Not disconnecting from peer `%4s due to pending address validations\n",
2402 GNUNET_i2s (peer));
2403#endif
2404 return;
2405 }
2406
2407 //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2408 GNUNET_STATISTICS_update (stats,
2409 gettext_noop
2410 ("# disconnects due to unready session"), 1,
2411 GNUNET_NO);
2412
2413 disconnect_neighbour (nl, GNUNET_YES);
2414 return; /* was never marked as connected */
2415 }
2416 pos->session = NULL;
2417 if (GNUNET_YES == pos->connected)
2418 {
2419 pos->connected = GNUNET_NO;
2420 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2421 GNUNET_NO);
2422 }
2423 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2424 {
2425 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2426 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2427 }
2428
2429 if (pos->addrlen != 0)
2430 {
2431 if (nl->received_pong != GNUNET_NO)
2432 {
2433 GNUNET_STATISTICS_update (stats,
2434 gettext_noop
2435 ("# try_fast_reconnect thanks to plugin_env_session_end"),
2436 1, GNUNET_NO);
2437 if (GNUNET_YES == pos->connected)
2438 try_fast_reconnect (p, nl);
2439 }
2440 else
2441 {
2442 GNUNET_STATISTICS_update (stats,
2443 gettext_noop
2444 ("# disconnects due to missing pong"), 1,
2445 GNUNET_NO);
2446 /* FIXME this is never true?! See: line 2416 */
2447 if (GNUNET_YES == pos->connected)
2448 disconnect_neighbour (nl, GNUNET_YES);
2449 }
2450 return;
2451 }
2452
2453 /* was inbound connection, free 'pos' */
2454 if (prev == NULL)
2455 rl->addresses = pos->next;
2456 else
2457 prev->next = pos->next;
2458 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2459 {
2460 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2461 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2462 }
2463 GNUNET_free_non_null (pos->ressources);
2464 GNUNET_free_non_null (pos->quality);
2465#if HAVE_LIBGLPK
2466 ats_modify_problem_state (ats, ATS_MODIFIED);
2467#endif
2468 if (GNUNET_YES != pos->connected)
2469 {
2470 /* nothing else to do, connection was never up... */
2471 GNUNET_free (pos);
2472 return;
2473 }
2474 pos->connected = GNUNET_NO;
2475 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"), -1,
2476 GNUNET_NO);
2477 GNUNET_free (pos);
2478
2479 if (nl->received_pong == GNUNET_NO)
2480 {
2481 GNUNET_STATISTICS_update (stats,
2482 gettext_noop ("# disconnects due to NO pong"), 1,
2483 GNUNET_NO);
2484 disconnect_neighbour (nl, GNUNET_YES);
2485 return; /* nothing to do, never connected... */
2486 }
2487 /* check if we have any validated addresses left */
2488 pos = rl->addresses;
2489 while (pos != NULL)
2490 {
2491 if (GNUNET_YES == pos->validated)
2492 {
2493 GNUNET_STATISTICS_update (stats,
2494 gettext_noop
2495 ("# try_fast_reconnect thanks to validated_address"),
2496 1, GNUNET_NO);
2497 try_fast_reconnect (p, nl);
2498 return;
2499 }
2500 pos = pos->next;
2501 }
2502 /* no valid addresses left, signal disconnect! */
2503
2504#if DEBUG_TRANSPORT
2505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
2506 GNUNET_i2s (peer), "plugin_env_session_end");
2507#endif
2508 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2509 * it means there aren't any left for this PLUGIN/PEER combination! So
2510 * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2511 * when it isn't necessary. Using GNUNET_YES at least checks to see
2512 * if there are any addresses that work first, so as not to overdo it.
2513 * --NE
2514 */
2515 GNUNET_STATISTICS_update (stats,
2516 gettext_noop
2517 ("# disconnects due to plugin_env_session_end"), 1,
2518 GNUNET_NO);
2519 disconnect_neighbour (nl, GNUNET_YES);
2520}
2521
2522
2523/**
2524 * Function that must be called by each plugin to notify the
2525 * transport service about the addresses under which the transport
2526 * provided by the plugin can be reached.
2527 *
2528 * @param cls closure
2529 * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2530 * @param addr one of the addresses of the host, NULL for the last address
2531 * the specific address format depends on the transport
2532 * @param addrlen length of the address
2533 */
2534static void
2535plugin_env_notify_address (void *cls, int add_remove, const void *addr,
2536 size_t addrlen)
2537{
2538 struct TransportPlugin *p = cls;
2539 struct OwnAddressList *al;
2540 struct OwnAddressList *prev;
2541
2542 GNUNET_assert (p->api != NULL);
2543#if DEBUG_TRANSPORT
2544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2545 (add_remove ==
2546 GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" :
2547 "Removing `%s':%s from the set of our addresses\n",
2548 a2s (p->short_name, addr, addrlen), p->short_name);
2549#endif
2550 GNUNET_assert (addr != NULL);
2551 if (GNUNET_NO == add_remove)
2552 {
2553 prev = NULL;
2554 al = p->addresses;
2555 while (al != NULL)
2556 {
2557 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2558 {
2559 if (prev == NULL)
2560 p->addresses = al->next;
2561 else
2562 prev->next = al->next;
2563 GNUNET_free (al);
2564 refresh_hello ();
2565 return;
2566 }
2567 prev = al;
2568 al = al->next;
2569 }
2570 GNUNET_break (0);
2571 return;
2572 }
2573 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2574 al->next = p->addresses;
2575 p->addresses = al;
2576 al->addrlen = addrlen;
2577 memcpy (&al[1], addr, addrlen);
2578 refresh_hello ();
2579}
2580
2581
2582/**
2583 * Notify all of our clients about a peer connecting.
2584 */
2585static void
2586notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2587 struct GNUNET_TIME_Relative latency, uint32_t distance)
2588{
2589 struct ConnectInfoMessage *cim;
2590 struct TransportClient *cpos;
2591 uint32_t ats_count;
2592 size_t size;
2593
2594 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2595 {
2596 GNUNET_break (0);
2597 return;
2598 }
2599#if DEBUG_TRANSPORT
2600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2601 "Notifying clients about connection with `%s'\n",
2602 GNUNET_i2s (peer));
2603#endif
2604 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), 1,
2605 GNUNET_NO);
2606
2607 ats_count = 2;
2608 size =
2609 sizeof (struct ConnectInfoMessage) +
2610 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2611 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
2612 cim = GNUNET_malloc (size);
2613 cim->header.size = htons (size);
2614 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2615 cim->ats_count = htonl (2);
2616 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2617 (&cim->ats)[0].value = htonl (distance);
2618 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2619 (&cim->ats)[1].value = htonl ((uint32_t) latency.rel_value);
2620 (&cim->ats)[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2621 (&cim->ats)[2].value = htonl (0);
2622 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2623
2624 /* notify ats about connecting peer */
2625 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2626 {
2627#if HAVE_LIBGLPK
2628 ats_modify_problem_state (ats, ATS_MODIFIED);
2629 ats_calculate_bandwidth_distribution (ats);
2630#endif
2631 }
2632 cpos = clients;
2633 while (cpos != NULL)
2634 {
2635 transmit_to_client (cpos, &cim->header, GNUNET_NO);
2636 cpos = cpos->next;
2637 }
2638 GNUNET_free (cim);
2639}
2640
2641
2642/**
2643 * Notify all of our clients about a peer disconnecting.
2644 */
2645static void
2646notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2647{
2648 struct DisconnectInfoMessage dim;
2649 struct TransportClient *cpos;
2650
2651 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
2652 {
2653 GNUNET_break (0);
2654 return;
2655 }
2656#if DEBUG_TRANSPORT
2657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2658 "Notifying clients about lost connection to `%s'\n",
2659 GNUNET_i2s (peer));
2660#endif
2661 GNUNET_STATISTICS_update (stats, gettext_noop ("# peers connected"), -1,
2662 GNUNET_NO);
2663 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2664 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2665 dim.reserved = htonl (0);
2666 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2667
2668 /* notify ats about connecting peer */
2669 if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2670 {
2671#if HAVE_LIBGLPK
2672 ats_modify_problem_state (ats, ATS_MODIFIED);
2673 ats_calculate_bandwidth_distribution (ats);
2674#endif
2675 }
2676
2677 cpos = clients;
2678 while (cpos != NULL)
2679 {
2680 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2681 cpos = cpos->next;
2682 }
2683}
2684
2685
2686/**
2687 * Find a ForeignAddressList entry for the given neighbour
2688 * that matches the given address and transport.
2689 *
2690 * @param neighbour which peer we care about
2691 * @param tname name of the transport plugin
2692 * @param session session to look for, NULL for 'any'; otherwise
2693 * can be used for the service to "learn" this session ID
2694 * if 'addr' matches
2695 * @param addr binary address
2696 * @param addrlen length of addr
2697 * @return NULL if no such entry exists
2698 */
2699static struct ForeignAddressList *
2700find_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2701 struct Session *session, const char *addr, uint16_t addrlen)
2702{
2703 struct ReadyList *head;
2704 struct ForeignAddressList *pos;
2705
2706 head = neighbour->plugins;
2707 while (head != NULL)
2708 {
2709 if (0 == strcmp (tname, head->plugin->short_name))
2710 break;
2711 head = head->next;
2712 }
2713 if (head == NULL)
2714 return NULL;
2715 pos = head->addresses;
2716 while ((pos != NULL) &&
2717 ((pos->addrlen != addrlen) ||
2718 (memcmp (pos->addr, addr, addrlen) != 0)))
2719 {
2720 if ((session != NULL) && (pos->session == session))
2721 return pos;
2722 pos = pos->next;
2723 }
2724 if ((session != NULL) && (pos != NULL))
2725 pos->session = session; /* learn it! */
2726 return pos;
2727}
2728
2729
2730/**
2731 * Get the peer address struct for the given neighbour and
2732 * address. If it doesn't yet exist, create it.
2733 *
2734 * @param neighbour which peer we care about
2735 * @param tname name of the transport plugin
2736 * @param session session of the plugin, or NULL for none
2737 * @param addr binary address
2738 * @param addrlen length of addr
2739 * @return NULL if we do not have a transport plugin for 'tname'
2740 */
2741static struct ForeignAddressList *
2742add_peer_address (struct NeighbourMapEntry *neighbour, const char *tname,
2743 struct Session *session, const char *addr, uint16_t addrlen)
2744{
2745 struct ReadyList *head;
2746 struct ForeignAddressList *ret;
2747 int c;
2748
2749 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2750 if (ret != NULL)
2751 return ret;
2752 head = neighbour->plugins;
2753
2754 while (head != NULL)
2755 {
2756 if (0 == strcmp (tname, head->plugin->short_name))
2757 break;
2758 head = head->next;
2759 }
2760 if (head == NULL)
2761 return NULL;
2762 ret = GNUNET_malloc (sizeof (struct ForeignAddressList) + addrlen);
2763 ret->session = session;
2764 if ((addrlen > 0) && (addr != NULL))
2765 {
2766 ret->addr = (const char *) &ret[1];
2767 memcpy (&ret[1], addr, addrlen);
2768 }
2769 else
2770 {
2771 ret->addr = NULL;
2772 }
2773
2774 ret->ressources =
2775 GNUNET_malloc (available_ressources *
2776 sizeof (struct ATS_ressource_entry));
2777 for (c = 0; c < available_ressources; c++)
2778 {
2779 struct ATS_ressource_entry *r = ret->ressources;
2780
2781 r[c].index = c;
2782 r[c].atis_index = ressources[c].atis_index;
2783 if (0 == strcmp (neighbour->plugins->plugin->short_name, "unix"))
2784 {
2785 r[c].c = ressources[c].c_unix;
2786 }
2787 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "udp"))
2788 {
2789 r[c].c = ressources[c].c_udp;
2790 }
2791 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "tcp"))
2792 {
2793 r[c].c = ressources[c].c_tcp;
2794 }
2795 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "http"))
2796 {
2797 r[c].c = ressources[c].c_http;
2798 }
2799 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "https"))
2800 {
2801 r[c].c = ressources[c].c_https;
2802 }
2803 else if (0 == strcmp (neighbour->plugins->plugin->short_name, "wlan"))
2804 {
2805 r[c].c = ressources[c].c_wlan;
2806 }
2807 else
2808 {
2809 r[c].c = ressources[c].c_default;
2810 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2811 "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2812 GNUNET_i2s (&neighbour->id),
2813 neighbour->plugins->plugin->short_name);
2814 }
2815 }
2816
2817 ret->quality =
2818 GNUNET_malloc (available_quality_metrics *
2819 sizeof (struct ATS_quality_entry));
2820 ret->addrlen = addrlen;
2821 ret->expires =
2822 GNUNET_TIME_relative_to_absolute
2823 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2824 ret->latency = GNUNET_TIME_relative_get_forever ();
2825 ret->distance = -1;
2826 ret->timeout =
2827 GNUNET_TIME_relative_to_absolute
2828 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2829 ret->ready_list = head;
2830 ret->next = head->addresses;
2831 head->addresses = ret;
2832 return ret;
2833}
2834
2835
2836/**
2837 * Closure for 'add_validated_address'.
2838 */
2839struct AddValidatedAddressContext
2840{
2841 /**
2842 * Entry that has been validated.
2843 */
2844 const struct ValidationEntry *ve;
2845
2846 /**
2847 * Flag set after we have added the address so
2848 * that we terminate the iteration next time.
2849 */
2850 int done;
2851};
2852
2853
2854/**
2855 * Callback function used to fill a buffer of max bytes with a list of
2856 * addresses in the format used by HELLOs. Should use
2857 * "GNUNET_HELLO_add_address" as a helper function.
2858 *
2859 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2860 * @param max maximum number of bytes that can be written to buf
2861 * @param buf where to write the address information
2862 * @return number of bytes written, 0 to signal the
2863 * end of the iteration.
2864 */
2865static size_t
2866add_validated_address (void *cls, size_t max, void *buf)
2867{
2868 struct AddValidatedAddressContext *avac = cls;
2869 const struct ValidationEntry *ve = avac->ve;
2870
2871 if (GNUNET_YES == avac->done)
2872 return 0;
2873 avac->done = GNUNET_YES;
2874 return GNUNET_HELLO_add_address (ve->transport_name,
2875 GNUNET_TIME_relative_to_absolute
2876 (HELLO_ADDRESS_EXPIRATION), ve->addr,
2877 ve->addrlen, buf, max);
2878}
2879
2880
2881
2882/**
2883 * Closure for 'check_address_exists'.
2884 */
2885struct CheckAddressExistsClosure
2886{
2887 /**
2888 * Address to check for.
2889 */
2890 const void *addr;
2891
2892 /**
2893 * Name of the transport.
2894 */
2895 const char *tname;
2896
2897 /**
2898 * Session, or NULL.
2899 */
2900 struct Session *session;
2901
2902 /**
2903 * Set to GNUNET_YES if the address exists.
2904 */
2905 int exists;
2906
2907 /**
2908 * Length of addr.
2909 */
2910 uint16_t addrlen;
2911
2912};
2913
2914
2915/**
2916 * Iterator over hash map entries. Checks if the given
2917 * validation entry is for the same address as what is given
2918 * in the closure.
2919 *
2920 * @param cls the 'struct CheckAddressExistsClosure*'
2921 * @param key current key code (ignored)
2922 * @param value value in the hash map ('struct ValidationEntry')
2923 * @return GNUNET_YES if we should continue to
2924 * iterate (mismatch), GNUNET_NO if not (entry matched)
2925 */
2926static int
2927check_address_exists (void *cls, const GNUNET_HashCode * key, void *value)
2928{
2929 struct CheckAddressExistsClosure *caec = cls;
2930 struct ValidationEntry *ve = value;
2931
2932 if ((0 == strcmp (caec->tname, ve->transport_name)) &&
2933 (caec->addrlen == ve->addrlen) &&
2934 (0 == memcmp (caec->addr, ve->addr, caec->addrlen)))
2935 {
2936 caec->exists = GNUNET_YES;
2937 return GNUNET_NO;
2938 }
2939 if ((ve->session != NULL) && (caec->session == ve->session))
2940 {
2941 caec->exists = GNUNET_YES;
2942 return GNUNET_NO;
2943 }
2944 return GNUNET_YES;
2945}
2946
2947
2948static void
2949neighbour_timeout_task (void *cls,
2950 const struct GNUNET_SCHEDULER_TaskContext *tc)
2951{
2952 struct NeighbourMapEntry *n = cls;
2953
2954#if DEBUG_TRANSPORT
2955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2956 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2957#endif
2958 GNUNET_STATISTICS_update (stats,
2959 gettext_noop ("# disconnects due to timeout"), 1,
2960 GNUNET_NO);
2961 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2962 disconnect_neighbour (n, GNUNET_NO);
2963}
2964
2965
2966/**
2967 * Schedule the job that will cause us to send a PING to the
2968 * foreign address to evaluate its validity and latency.
2969 *
2970 * @param fal address to PING
2971 */
2972static void
2973schedule_next_ping (struct ForeignAddressList *fal);
2974
2975
2976/**
2977 * Add the given address to the list of foreign addresses
2978 * available for the given peer (check for duplicates).
2979 *
2980 * @param cls the respective 'struct NeighbourMapEntry' to update
2981 * @param tname name of the transport
2982 * @param expiration expiration time
2983 * @param addr the address
2984 * @param addrlen length of the address
2985 * @return GNUNET_OK (always)
2986 */
2987static int
2988add_to_foreign_address_list (void *cls, const char *tname,
2989 struct GNUNET_TIME_Absolute expiration,
2990 const void *addr, uint16_t addrlen)
2991{
2992 struct NeighbourMapEntry *n = cls;
2993 struct ForeignAddressList *fal;
2994 int try;
2995
2996 GNUNET_STATISTICS_update (stats,
2997 gettext_noop
2998 ("# valid peer addresses returned by PEERINFO"), 1,
2999 GNUNET_NO);
3000 try = GNUNET_NO;
3001 fal = find_peer_address (n, tname, NULL, addr, addrlen);
3002 if (fal == NULL)
3003 {
3004#if DEBUG_TRANSPORT_HELLO
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3007 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&n->id),
3008 expiration.abs_value);
3009#endif
3010 fal = add_peer_address (n, tname, NULL, addr, addrlen);
3011 if (fal == NULL)
3012 {
3013 GNUNET_STATISTICS_update (stats,
3014 gettext_noop
3015 ("# previously validated addresses lacking transport"),
3016 1, GNUNET_NO);
3017 }
3018 else
3019 {
3020 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3021 schedule_next_ping (fal);
3022 }
3023 try = GNUNET_YES;
3024 }
3025 else
3026 {
3027 fal->expires = GNUNET_TIME_absolute_max (expiration, fal->expires);
3028 }
3029 if (fal == NULL)
3030 {
3031#if DEBUG_TRANSPORT
3032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3033 "Failed to add new address for `%4s'\n", GNUNET_i2s (&n->id));
3034#endif
3035 return GNUNET_OK;
3036 }
3037 if (fal->validated == GNUNET_NO)
3038 {
3039 fal->validated = GNUNET_YES;
3040 GNUNET_STATISTICS_update (stats,
3041 gettext_noop
3042 ("# peer addresses considered valid"), 1,
3043 GNUNET_NO);
3044 }
3045 if (try == GNUNET_YES)
3046 {
3047#if DEBUG_TRANSPORT
3048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049 "Have new addresses, will try to trigger transmissions.\n");
3050#endif
3051 try_transmission_to_peer (n);
3052 }
3053 return GNUNET_OK;
3054}
3055
3056
3057/**
3058 * Add addresses in validated HELLO "h" to the set of addresses
3059 * we have for this peer.
3060 *
3061 * @param cls closure ('struct NeighbourMapEntry*')
3062 * @param peer id of the peer, NULL for last call
3063 * @param h hello message for the peer (can be NULL)
3064 * @param err_msg NULL if successful, otherwise contains error message
3065 */
3066static void
3067add_hello_for_peer (void *cls, const struct GNUNET_PeerIdentity *peer,
3068 const struct GNUNET_HELLO_Message *h, const char *err_msg)
3069{
3070 struct NeighbourMapEntry *n = cls;
3071
3072 if (err_msg != NULL)
3073 {
3074#if DEBUG_TRANSPORT
3075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3076 _("Error in communication with PEERINFO service: %s\n"),
3077 err_msg);
3078#endif
3079 /* return; */
3080 }
3081 if (peer == NULL)
3082 {
3083 GNUNET_STATISTICS_update (stats,
3084 gettext_noop
3085 ("# outstanding peerinfo iterate requests"), -1,
3086 GNUNET_NO);
3087 n->piter = NULL;
3088 return;
3089 }
3090 if (h == NULL)
3091 return; /* no HELLO available */
3092#if DEBUG_TRANSPORT
3093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3094 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3095 "HELLO", GNUNET_i2s (peer));
3096#endif
3097 if (GNUNET_YES != n->public_key_valid)
3098 {
3099 GNUNET_HELLO_get_key (h, &n->publicKey);
3100 n->public_key_valid = GNUNET_YES;
3101 }
3102 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
3103 n);
3104}
3105
3106
3107/**
3108 * Create a fresh entry in our neighbour list for the given peer.
3109 * Will try to transmit our current HELLO to the new neighbour.
3110 * Do not call this function directly, use 'setup_peer_check_blacklist.
3111 *
3112 * @param peer the peer for which we create the entry
3113 * @param do_hello should we schedule transmitting a HELLO
3114 * @return the new neighbour list entry
3115 */
3116static struct NeighbourMapEntry *
3117setup_new_neighbour (const struct GNUNET_PeerIdentity *peer, int do_hello)
3118{
3119 struct NeighbourMapEntry *n;
3120 struct TransportPlugin *tp;
3121 struct ReadyList *rl;
3122
3123 GNUNET_assert (0 !=
3124 memcmp (peer, &my_identity,
3125 sizeof (struct GNUNET_PeerIdentity)));
3126#if DEBUG_TRANSPORT
3127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting up state for neighbour `%4s'\n",
3128 GNUNET_i2s (peer));
3129#endif
3130 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), 1,
3131 GNUNET_NO);
3132 n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
3133 n->id = *peer;
3134 n->peer_timeout =
3135 GNUNET_TIME_relative_to_absolute
3136 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3137 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3138 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3139 MAX_BANDWIDTH_CARRY_S);
3140 tp = plugins;
3141 while (tp != NULL)
3142 {
3143 if ((tp->api->send != NULL) && (!is_blacklisted (peer, tp)))
3144 {
3145 rl = GNUNET_malloc (sizeof (struct ReadyList));
3146 rl->neighbour = n;
3147 rl->next = n->plugins;
3148 n->plugins = rl;
3149 rl->plugin = tp;
3150 rl->addresses = NULL;
3151 }
3152 tp = tp->next;
3153 }
3154 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3155 n->distance = -1;
3156 n->timeout_task =
3157 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3158 &neighbour_timeout_task, n);
3159 GNUNET_CONTAINER_multihashmap_put (neighbours, &n->id.hashPubKey, n,
3160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
3161 if (do_hello)
3162 {
3163 GNUNET_STATISTICS_update (stats,
3164 gettext_noop
3165 ("# peerinfo new neighbor iterate requests"), 1,
3166 GNUNET_NO);
3167 GNUNET_STATISTICS_update (stats,
3168 gettext_noop
3169 ("# outstanding peerinfo iterate requests"), 1,
3170 GNUNET_NO);
3171 n->piter =
3172 GNUNET_PEERINFO_iterate (peerinfo, peer, GNUNET_TIME_UNIT_FOREVER_REL,
3173 &add_hello_for_peer, n);
3174
3175 GNUNET_STATISTICS_update (stats,
3176 gettext_noop ("# HELLO's sent to new neighbors"),
3177 1, GNUNET_NO);
3178 if (NULL != our_hello)
3179 transmit_to_peer (NULL, NULL, 0, HELLO_ADDRESS_EXPIRATION,
3180 (const char *) our_hello, GNUNET_HELLO_size (our_hello),
3181 GNUNET_NO, n);
3182 }
3183 return n;
3184}
3185
3186
3187/**
3188 * Function called after we have checked if communicating
3189 * with a given peer is acceptable.
3190 *
3191 * @param cls closure
3192 * @param n NULL if communication is not acceptable
3193 */
3194typedef void (*SetupContinuation) (void *cls, struct NeighbourMapEntry * n);
3195
3196
3197/**
3198 * Information kept for each client registered to perform
3199 * blacklisting.
3200 */
3201struct Blacklisters
3202{
3203 /**
3204 * This is a linked list.
3205 */
3206 struct Blacklisters *next;
3207
3208 /**
3209 * This is a linked list.
3210 */
3211 struct Blacklisters *prev;
3212
3213 /**
3214 * Client responsible for this entry.
3215 */
3216 struct GNUNET_SERVER_Client *client;
3217
3218 /**
3219 * Blacklist check that we're currently performing.
3220 */
3221 struct BlacklistCheck *bc;
3222
3223};
3224
3225
3226/**
3227 * Head of DLL of blacklisting clients.
3228 */
3229static struct Blacklisters *bl_head;
3230
3231/**
3232 * Tail of DLL of blacklisting clients.
3233 */
3234static struct Blacklisters *bl_tail;
3235
3236
3237/**
3238 * Context we use when performing a blacklist check.
3239 */
3240struct BlacklistCheck
3241{
3242
3243 /**
3244 * This is a linked list.
3245 */
3246 struct BlacklistCheck *next;
3247
3248 /**
3249 * This is a linked list.
3250 */
3251 struct BlacklistCheck *prev;
3252
3253 /**
3254 * Peer being checked.
3255 */
3256 struct GNUNET_PeerIdentity peer;
3257
3258 /**
3259 * Option for setup neighbour afterwards.
3260 */
3261 int do_hello;
3262
3263 /**
3264 * Continuation to call with the result.
3265 */
3266 SetupContinuation cont;
3267
3268 /**
3269 * Closure for cont.
3270 */
3271 void *cont_cls;
3272
3273 /**
3274 * Current transmission request handle for this client, or NULL if no
3275 * request is pending.
3276 */
3277 struct GNUNET_CONNECTION_TransmitHandle *th;
3278
3279 /**
3280 * Our current position in the blacklisters list.
3281 */
3282 struct Blacklisters *bl_pos;
3283
3284 /**
3285 * Current task performing the check.
3286 */
3287 GNUNET_SCHEDULER_TaskIdentifier task;
3288
3289};
3290
3291/**
3292 * Head of DLL of active blacklisting queries.
3293 */
3294static struct BlacklistCheck *bc_head;
3295
3296/**
3297 * Tail of DLL of active blacklisting queries.
3298 */
3299static struct BlacklistCheck *bc_tail;
3300
3301
3302/**
3303 * Perform next action in the blacklist check.
3304 *
3305 * @param cls the 'struct BlacklistCheck*'
3306 * @param tc unused
3307 */
3308static void
3309do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3310
3311/**
3312 * Transmit blacklist query to the client.
3313 *
3314 * @param cls the 'struct BlacklistCheck'
3315 * @param size number of bytes allowed
3316 * @param buf where to copy the message
3317 * @return number of bytes copied to buf
3318 */
3319static size_t
3320transmit_blacklist_message (void *cls, size_t size, void *buf)
3321{
3322 struct BlacklistCheck *bc = cls;
3323 struct Blacklisters *bl;
3324 struct BlacklistMessage bm;
3325
3326 bc->th = NULL;
3327 if (size == 0)
3328 {
3329 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3330 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3331 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3332 "Failed to send blacklist test for peer `%s' to client\n",
3333 GNUNET_i2s (&bc->peer));
3334 return 0;
3335 }
3336#if DEBUG_TRANSPORT
3337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3338 "Sending blacklist test for peer `%s' to client\n",
3339 GNUNET_i2s (&bc->peer));
3340#endif
3341 bl = bc->bl_pos;
3342 bm.header.size = htons (sizeof (struct BlacklistMessage));
3343 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3344 bm.is_allowed = htonl (0);
3345 bm.peer = bc->peer;
3346 memcpy (buf, &bm, sizeof (bm));
3347 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3348 return sizeof (bm);
3349}
3350
3351
3352/**
3353 * Perform next action in the blacklist check.
3354 *
3355 * @param cls the 'struct BlacklistCheck*'
3356 * @param tc unused
3357 */
3358static void
3359do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3360{
3361 struct BlacklistCheck *bc = cls;
3362 struct Blacklisters *bl;
3363
3364 bc->task = GNUNET_SCHEDULER_NO_TASK;
3365 bl = bc->bl_pos;
3366 if (bl == NULL)
3367 {
3368#if DEBUG_TRANSPORT
3369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3370 "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3371 GNUNET_i2s (&bc->peer));
3372#endif
3373 bc->cont (bc->cont_cls, setup_new_neighbour (&bc->peer, bc->do_hello));
3374 GNUNET_free (bc);
3375 return;
3376 }
3377 if (bl->bc == NULL)
3378 {
3379 bl->bc = bc;
3380 bc->th =
3381 GNUNET_SERVER_notify_transmit_ready (bl->client,
3382 sizeof (struct BlacklistMessage),
3383 GNUNET_TIME_UNIT_FOREVER_REL,
3384 &transmit_blacklist_message, bc);
3385 }
3386}
3387
3388
3389/**
3390 * Obtain a 'struct NeighbourMapEntry' for the given peer. If such an entry
3391 * does not yet exist, check the blacklist. If the blacklist says creating
3392 * one is acceptable, create one and call the continuation; otherwise
3393 * call the continuation with NULL.
3394 *
3395 * @param peer peer to setup or look up a struct NeighbourMapEntry for
3396 * @param do_hello should we also schedule sending our HELLO to the peer
3397 * if this is a new record
3398 * @param cont function to call with the 'struct NeigbhbourList*'
3399 * @param cont_cls closure for cont
3400 */
3401static void
3402setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3403 int do_hello, SetupContinuation cont,
3404 void *cont_cls)
3405{
3406 struct NeighbourMapEntry *n;
3407 struct BlacklistCheck *bc;
3408
3409 n = find_neighbour (peer);
3410 if (n != NULL)
3411 {
3412#if DEBUG_TRANSPORT
3413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3414 "Neighbour record exists for peer `%s'\n", GNUNET_i2s (peer));
3415#endif
3416 if (cont != NULL)
3417 cont (cont_cls, n);
3418 return;
3419 }
3420 if (bl_head == NULL)
3421 {
3422 if (cont != NULL)
3423 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3424 else
3425 setup_new_neighbour (peer, do_hello);
3426 return;
3427 }
3428 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3429 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3430 bc->peer = *peer;
3431 bc->do_hello = do_hello;
3432 bc->cont = cont;
3433 bc->cont_cls = cont_cls;
3434 bc->bl_pos = bl_head;
3435 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3436}
3437
3438
3439/**
3440 * Function called with the result of querying a new blacklister about
3441 * it being allowed (or not) to continue to talk to an existing neighbour.
3442 *
3443 * @param cls the original 'struct NeighbourMapEntry'
3444 * @param n NULL if we need to disconnect
3445 */
3446static void
3447confirm_or_drop_neighbour (void *cls, struct NeighbourMapEntry *n)
3448{
3449 struct NeighbourMapEntry *orig = cls;
3450
3451 if (n == NULL)
3452 {
3453#if DEBUG_TRANSPORT
3454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
3455 GNUNET_i2s (&orig->id), "confirm_or_drop_neighboUr");
3456#endif
3457 GNUNET_STATISTICS_update (stats,
3458 gettext_noop ("# disconnects due to blacklist"),
3459 1, GNUNET_NO);
3460 disconnect_neighbour (orig, GNUNET_NO);
3461 }
3462}
3463
3464
3465struct TestConnectionContext
3466{
3467 int first;
3468
3469 struct Blacklisters *bl;
3470};
3471
3472
3473static int
3474test_connection_ok (void *cls, const GNUNET_HashCode * key, void *value)
3475{
3476 struct TestConnectionContext *tcc = cls;
3477 struct NeighbourMapEntry *n = value;
3478 struct BlacklistCheck *bc;
3479
3480
3481 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3482 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3483 bc->peer = n->id;
3484 bc->do_hello = GNUNET_NO;
3485 bc->cont = &confirm_or_drop_neighbour;
3486 bc->cont_cls = n;
3487 bc->bl_pos = tcc->bl;
3488 if (GNUNET_YES == tcc->first)
3489 {
3490 /* all would wait for the same client, no need to
3491 * create more than just the first task right now */
3492 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3493 tcc->first = GNUNET_NO;
3494 }
3495 return GNUNET_OK;
3496}
3497
3498
3499/**
3500 * Handle a request to start a blacklist.
3501 *
3502 * @param cls closure (always NULL)
3503 * @param client identification of the client
3504 * @param message the actual message
3505 */
3506static void
3507handle_blacklist_init (void *cls, struct GNUNET_SERVER_Client *client,
3508 const struct GNUNET_MessageHeader *message)
3509{
3510 struct Blacklisters *bl;
3511 struct TestConnectionContext tcc;
3512
3513 bl = bl_head;
3514 while (bl != NULL)
3515 {
3516 if (bl->client == client)
3517 {
3518 GNUNET_break (0);
3519 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3520 return;
3521 }
3522 bl = bl->next;
3523 }
3524 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3525 bl->client = client;
3526 GNUNET_SERVER_client_keep (client);
3527 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3528 /* confirm that all existing connections are OK! */
3529 tcc.bl = bl;
3530 tcc.first = GNUNET_YES;
3531 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &test_connection_ok, &tcc);
3532}
3533
3534
3535/**
3536 * Handle a request to blacklist a peer.
3537 *
3538 * @param cls closure (always NULL)
3539 * @param client identification of the client
3540 * @param message the actual message
3541 */
3542static void
3543handle_blacklist_reply (void *cls, struct GNUNET_SERVER_Client *client,
3544 const struct GNUNET_MessageHeader *message)
3545{
3546 const struct BlacklistMessage *msg =
3547 (const struct BlacklistMessage *) message;
3548 struct Blacklisters *bl;
3549 struct BlacklistCheck *bc;
3550
3551 bl = bl_head;
3552 while ((bl != NULL) && (bl->client != client))
3553 bl = bl->next;
3554 if (bl == NULL)
3555 {
3556#if DEBUG_TRANSPORT
3557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
3558#endif
3559 /* FIXME: other error handling here!? */
3560 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3561 return;
3562 }
3563 bc = bl->bc;
3564 bl->bc = NULL;
3565 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3566 {
3567#if DEBUG_TRANSPORT
3568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3569 "Blacklist check failed, peer not allowed\n");
3570#endif
3571 bc->cont (bc->cont_cls, NULL);
3572 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3573 GNUNET_free (bc);
3574 }
3575 else
3576 {
3577#if DEBUG_TRANSPORT
3578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3579 "Blacklist check succeeded, continuing with checks\n");
3580#endif
3581 bc->bl_pos = bc->bl_pos->next;
3582 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3583 }
3584 /* check if any other bc's are waiting for this blacklister */
3585 bc = bc_head;
3586 while (bc != NULL)
3587 {
3588 if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
3589 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
3590 bc = bc->next;
3591 }
3592}
3593
3594
3595/**
3596 * Send periodic PING messages to a given foreign address.
3597 *
3598 * @param cls our 'struct PeriodicValidationContext*'
3599 * @param tc task context
3600 */
3601static void
3602send_periodic_ping (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3603{
3604 struct ForeignAddressList *peer_address = cls;
3605 struct TransportPlugin *tp;
3606 struct ValidationEntry *va;
3607 struct NeighbourMapEntry *neighbour;
3608 struct TransportPingMessage ping;
3609 struct CheckAddressExistsClosure caec;
3610 char *message_buf;
3611 uint16_t hello_size;
3612 size_t slen;
3613 size_t tsize;
3614
3615 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3616 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3617 return;
3618 GNUNET_assert (peer_address != NULL);
3619 tp = peer_address->ready_list->plugin;
3620 neighbour = peer_address->ready_list->neighbour;
3621 if (GNUNET_YES != neighbour->public_key_valid)
3622 {
3623 /* no public key yet, try again later */
3624 schedule_next_ping (peer_address);
3625 return;
3626 }
3627 caec.addr = peer_address->addr;
3628 caec.addrlen = peer_address->addrlen;
3629 caec.tname = tp->short_name;
3630 caec.session = peer_address->session;
3631 caec.exists = GNUNET_NO;
3632
3633 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
3634 &caec);
3635 if (caec.exists == GNUNET_YES)
3636 {
3637 /* During validation attempts we will likely trigger the other
3638 * peer trying to validate our address which in turn will cause
3639 * it to send us its HELLO, so we expect to hit this case rather
3640 * frequently. Only print something if we are very verbose. */
3641#if DEBUG_TRANSPORT > 1
3642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3643 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3644 (peer_address->addr != NULL) ? a2s (tp->short_name,
3645 peer_address->addr,
3646 peer_address->addrlen) :
3647 "<inbound>", tp->short_name, GNUNET_i2s (&neighbour->id));
3648#endif
3649 schedule_next_ping (peer_address);
3650 return;
3651 }
3652 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3653 va->transport_name = GNUNET_strdup (tp->short_name);
3654 va->challenge =
3655 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
3656 va->send_time = GNUNET_TIME_absolute_get ();
3657 va->session = peer_address->session;
3658 if (peer_address->addr != NULL)
3659 {
3660 va->addr = (const void *) &va[1];
3661 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3662 va->addrlen = peer_address->addrlen;
3663 }
3664 memcpy (&va->publicKey, &neighbour->publicKey,
3665 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3666
3667 va->timeout_task =
3668 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3669 &timeout_hello_validation, va);
3670 GNUNET_CONTAINER_multihashmap_put (validation_map, &neighbour->id.hashPubKey,
3671 va,
3672 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3673
3674 if (peer_address->validated != GNUNET_YES)
3675 hello_size = GNUNET_HELLO_size (our_hello);
3676 else
3677 hello_size = 0;
3678
3679 tsize = sizeof (struct TransportPingMessage) + hello_size;
3680
3681 if (peer_address->addr != NULL)
3682 {
3683 slen = strlen (tp->short_name) + 1;
3684 tsize += slen + peer_address->addrlen;
3685 }
3686 else
3687 {
3688 slen = 0; /* make gcc happy */
3689 }
3690 message_buf = GNUNET_malloc (tsize);
3691 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3692 ping.challenge = htonl (va->challenge);
3693 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
3694 if (peer_address->validated != GNUNET_YES)
3695 {
3696 memcpy (message_buf, our_hello, hello_size);
3697 }
3698
3699 if (peer_address->addr != NULL)
3700 {
3701 ping.header.size =
3702 htons (sizeof (struct TransportPingMessage) + peer_address->addrlen +
3703 slen);
3704 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3705 tp->short_name, slen);
3706 memcpy (&message_buf
3707 [hello_size + sizeof (struct TransportPingMessage) + slen],
3708 peer_address->addr, peer_address->addrlen);
3709 }
3710 else
3711 {
3712 ping.header.size = htons (sizeof (struct TransportPingMessage));
3713 }
3714
3715 memcpy (&message_buf[hello_size], &ping,
3716 sizeof (struct TransportPingMessage));
3717
3718#if DEBUG_TRANSPORT_REVALIDATION
3719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3720 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3721 (peer_address->addr !=
3722 NULL) ? a2s (peer_address->plugin->short_name,
3723 peer_address->addr,
3724 peer_address->addrlen) : "<inbound>",
3725 tp->short_name, GNUNET_i2s (&neighbour->id), "HELLO", hello_size,
3726 "PING");
3727#endif
3728 if (peer_address->validated != GNUNET_YES)
3729 GNUNET_STATISTICS_update (stats,
3730 gettext_noop ("# PING with HELLO messages sent"),
3731 1, GNUNET_NO);
3732 else
3733 GNUNET_STATISTICS_update (stats,
3734 gettext_noop
3735 ("# PING without HELLO messages sent"), 1,
3736 GNUNET_NO);
3737 GNUNET_STATISTICS_update (stats,
3738 gettext_noop
3739 ("# PING messages sent for re-validation"), 1,
3740 GNUNET_NO);
3741 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3742 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
3743 neighbour);
3744 GNUNET_free (message_buf);
3745 schedule_next_ping (peer_address);
3746}
3747
3748
3749/**
3750 * Schedule the job that will cause us to send a PING to the
3751 * foreign address to evaluate its validity and latency.
3752 *
3753 * @param fal address to PING
3754 */
3755static void
3756schedule_next_ping (struct ForeignAddressList *fal)
3757{
3758 struct GNUNET_TIME_Relative delay;
3759
3760 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3761 {
3762 GNUNET_SCHEDULER_cancel (fal->revalidate_task);
3763 fal->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3764 }
3765 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3766 delay.rel_value /= 2; /* do before expiration */
3767 delay = GNUNET_TIME_relative_min (delay, LATENCY_EVALUATION_MAX_DELAY);
3768 if (GNUNET_YES != fal->estimated)
3769 {
3770 delay = GNUNET_TIME_UNIT_ZERO;
3771 fal->estimated = GNUNET_YES;
3772 }
3773
3774 if (GNUNET_YES == fal->connected)
3775 {
3776 delay =
3777 GNUNET_TIME_relative_min (delay,
3778 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3779 }
3780 /* FIXME: also adjust delay based on how close the last
3781 * observed latency is to the latency of the best alternative */
3782 /* bound how fast we can go */
3783 delay = GNUNET_TIME_relative_max (delay, GNUNET_TIME_UNIT_SECONDS);
3784 /* randomize a bit (to avoid doing all at the same time) */
3785 delay.rel_value +=
3786 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3787
3788 GNUNET_assert (fal->revalidate_task == GNUNET_SCHEDULER_NO_TASK);
3789 fal->revalidate_task =
3790 GNUNET_SCHEDULER_add_delayed (delay, &send_periodic_ping, fal);
3791}
3792
3793
3794
3795
3796/**
3797 * Function that will be called if we receive some payload
3798 * from another peer.
3799 *
3800 * @param message the payload
3801 * @param n peer who claimed to be the sender
3802 */
3803static void
3804handle_payload_message (const struct GNUNET_MessageHeader *message,
3805 struct NeighbourMapEntry *n)
3806{
3807 struct InboundMessage *im;
3808 struct TransportClient *cpos;
3809 uint16_t msize;
3810
3811 msize = ntohs (message->size);
3812 if (n->received_pong == GNUNET_NO)
3813 {
3814#if DEBUG_TRANSPORT
3815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3816 "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3817 ntohs (message->type), ntohs (message->size),
3818 GNUNET_i2s (&n->id));
3819#endif
3820 GNUNET_free_non_null (n->pre_connect_message_buffer);
3821 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3822 memcpy (n->pre_connect_message_buffer, message, msize);
3823 return;
3824 }
3825
3826#if DEBUG_TRANSPORT
3827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3828 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3829 ntohs (message->type), ntohs (message->size),
3830 GNUNET_i2s (&n->id));
3831#endif
3832 if (GNUNET_YES ==
3833 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, (ssize_t) msize))
3834 {
3835 n->quota_violation_count++;
3836#if DEBUG_TRANSPORT
3837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3838 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3839 n->in_tracker.available_bytes_per_s__,
3840 n->quota_violation_count);
3841#endif
3842 /* Discount 32k per violation */
3843 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
3844 }
3845 else
3846 {
3847 if (n->quota_violation_count > 0)
3848 {
3849 /* try to add 32k back */
3850 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
3851 n->quota_violation_count--;
3852 }
3853 }
3854 GNUNET_STATISTICS_update (stats,
3855 gettext_noop
3856 ("# payload received from other peers"), msize,
3857 GNUNET_NO);
3858 /* transmit message to all clients */
3859 uint32_t ats_count = 2;
3860 size_t size =
3861 sizeof (struct InboundMessage) +
3862 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3863 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3864 GNUNET_break (0);
3865
3866 im = GNUNET_malloc (size);
3867 im->header.size = htons (size);
3868 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3869 im->peer = n->id;
3870 im->ats_count = htonl (ats_count);
3871 /* Setting ATS data */
3872 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3873 (&(im->ats))[0].value = htonl (n->distance);
3874 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3875 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3876 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3877 (&(im->ats))[ats_count].value = htonl (0);
3878
3879 memcpy (&((&(im->ats))[ats_count + 1]), message, msize);
3880 cpos = clients;
3881 while (cpos != NULL)
3882 {
3883 transmit_to_client (cpos, &im->header, GNUNET_YES);
3884 cpos = cpos->next;
3885 }
3886 GNUNET_free (im);
3887}
3888
3889
3890/**
3891 * Iterator over hash map entries. Checks if the given validation
3892 * entry is for the same challenge as what is given in the PONG.
3893 *
3894 * @param cls the 'struct TransportPongMessage*'
3895 * @param key peer identity
3896 * @param value value in the hash map ('struct ValidationEntry')
3897 * @return GNUNET_YES if we should continue to
3898 * iterate (mismatch), GNUNET_NO if not (entry matched)
3899 */
3900static int
3901check_pending_validation (void *cls, const GNUNET_HashCode * key, void *value)
3902{
3903 const struct TransportPongMessage *pong = cls;
3904 struct ValidationEntry *ve = value;
3905 struct AddValidatedAddressContext avac;
3906 unsigned int challenge = ntohl (pong->challenge);
3907 struct GNUNET_HELLO_Message *hello;
3908 struct GNUNET_PeerIdentity target;
3909 struct NeighbourMapEntry *n;
3910 struct ForeignAddressList *fal;
3911 struct OwnAddressList *oal;
3912 struct TransportPlugin *tp;
3913 struct GNUNET_MessageHeader *prem;
3914 uint16_t ps;
3915 const char *addr;
3916 size_t slen;
3917 size_t alen;
3918
3919 ps = ntohs (pong->header.size);
3920 if (ps < sizeof (struct TransportPongMessage))
3921 {
3922 GNUNET_break_op (0);
3923 return GNUNET_NO;
3924 }
3925 addr = (const char *) &pong[1];
3926 slen = strlen (ve->transport_name) + 1;
3927 if ((ps - sizeof (struct TransportPongMessage) < slen) ||
3928 (ve->challenge != challenge) || (addr[slen - 1] != '\0') ||
3929 (0 != strcmp (addr, ve->transport_name)) ||
3930 (ntohl (pong->purpose.size) !=
3931 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) +
3932 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3933 sizeof (struct GNUNET_PeerIdentity) + ps -
3934 sizeof (struct TransportPongMessage)))
3935 {
3936 return GNUNET_YES;
3937 }
3938
3939 alen = ps - sizeof (struct TransportPongMessage) - slen;
3940 switch (ntohl (pong->purpose.purpose))
3941 {
3942 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3943 if ((ve->addrlen + slen != ntohl (pong->addrlen)) ||
3944 (0 != memcmp (&addr[slen], ve->addr, ve->addrlen)))
3945 {
3946 return GNUNET_YES; /* different entry, keep trying! */
3947 }
3948 if (0 != memcmp (&pong->pid, key, sizeof (struct GNUNET_PeerIdentity)))
3949 {
3950 GNUNET_break_op (0);
3951 return GNUNET_NO;
3952 }
3953 if (GNUNET_OK !=
3954 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3955 &pong->purpose, &pong->signature,
3956 &ve->publicKey))
3957 {
3958 GNUNET_break_op (0);
3959 return GNUNET_NO;
3960 }
3961
3962#if DEBUG_TRANSPORT
3963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3964 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3965 GNUNET_h2s (key), a2s (ve->transport_name,
3966 (const struct sockaddr *) ve->addr,
3967 ve->addrlen), ve->transport_name);
3968#endif
3969 break;
3970 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3971 if (0 !=
3972 memcmp (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
3973 {
3974 char *peer;
3975
3976 GNUNET_asprintf (&peer, "%s", GNUNET_i2s (&pong->pid));
3977#if DEBUG_TRANSPORT
3978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3979 "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
3980 GNUNET_i2s (&my_identity), peer);
3981#endif
3982 GNUNET_free (peer);
3983 return GNUNET_NO;
3984 }
3985 if (ve->addrlen != 0)
3986 {
3987 /* must have been for a different validation entry */
3988 return GNUNET_YES;
3989 }
3990 tp = find_transport (ve->transport_name);
3991 if (tp == NULL)
3992 {
3993 GNUNET_break (0);
3994 return GNUNET_YES;
3995 }
3996 oal = tp->addresses;
3997 while (NULL != oal)
3998 {
3999 if ((oal->addrlen == alen) && (0 == memcmp (&oal[1], &addr[slen], alen)))
4000 break;
4001 oal = oal->next;
4002 }
4003 if (oal == NULL)
4004 {
4005 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4006 _
4007 ("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4008 GNUNET_i2s (&pong->pid), a2s (ve->transport_name, &addr[slen],
4009 alen));
4010 /* FIXME: since the sender of the PONG currently uses the
4011 * wrong address (see FIMXE there!), we cannot run a
4012 * proper check here... */
4013#if FIXME_URGENT
4014 return GNUNET_NO;
4015#endif
4016 }
4017 if (GNUNET_OK !=
4018 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4019 &pong->purpose, &pong->signature,
4020 &ve->publicKey))
4021 {
4022 GNUNET_break_op (0);
4023 return GNUNET_NO;
4024 }
4025
4026#if DEBUG_TRANSPORT
4027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4028 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4029 GNUNET_h2s (key), a2s (ve->transport_name, &addr[slen], alen),
4030 ve->transport_name);
4031#endif
4032 break;
4033 default:
4034 GNUNET_break_op (0);
4035 return GNUNET_NO;
4036 }
4037 if (GNUNET_TIME_absolute_get_remaining
4038 (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4039 {
4040 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4041 _("Received expired signature. Check system time.\n"));
4042 return GNUNET_NO;
4043 }
4044 GNUNET_STATISTICS_update (stats,
4045 gettext_noop ("# address validation successes"), 1,
4046 GNUNET_NO);
4047 /* create the updated HELLO */
4048 GNUNET_CRYPTO_hash (&ve->publicKey,
4049 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4050 &target.hashPubKey);
4051 if (ve->addr != NULL)
4052 {
4053 avac.done = GNUNET_NO;
4054 avac.ve = ve;
4055 hello = GNUNET_HELLO_create (&ve->publicKey, &add_validated_address, &avac);
4056 GNUNET_PEERINFO_add_peer (peerinfo, hello);
4057 GNUNET_free (hello);
4058 }
4059 n = find_neighbour (&target);
4060 if (n != NULL)
4061 {
4062 n->publicKey = ve->publicKey;
4063 n->public_key_valid = GNUNET_YES;
4064 fal =
4065 add_peer_address (n, ve->transport_name, ve->session, ve->addr,
4066 ve->addrlen);
4067 GNUNET_assert (fal != NULL);
4068 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4069 fal->validated = GNUNET_YES;
4070 mark_address_connected (fal);
4071 GNUNET_STATISTICS_update (stats,
4072 gettext_noop
4073 ("# peer addresses considered valid"), 1,
4074 GNUNET_NO);
4075 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4076 update_addr_value (fal,
4077 GNUNET_TIME_absolute_get_duration (ve->
4078 send_time).rel_value,
4079 GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4080
4081 schedule_next_ping (fal);
4082 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4083 n->latency = fal->latency;
4084 else
4085 n->latency.rel_value =
4086 (fal->latency.rel_value + n->latency.rel_value) / 2;
4087
4088 n->distance = fal->distance;
4089 if (GNUNET_NO == n->received_pong)
4090 {
4091 n->received_pong = GNUNET_YES;
4092 notify_clients_connect (&target, n->latency, n->distance);
4093 if (NULL != (prem = n->pre_connect_message_buffer))
4094 {
4095 n->pre_connect_message_buffer = NULL;
4096 handle_payload_message (prem, n);
4097 GNUNET_free (prem);
4098 }
4099 }
4100 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4101 {
4102 GNUNET_SCHEDULER_cancel (n->retry_task);
4103 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4104 try_transmission_to_peer (n);
4105 }
4106 }
4107
4108 /* clean up validation entry */
4109 GNUNET_assert (GNUNET_YES ==
4110 GNUNET_CONTAINER_multihashmap_remove (validation_map, key,
4111 ve));
4112 abort_validation (NULL, NULL, ve);
4113 return GNUNET_NO;
4114} 294}
4115 295
4116 296
4117/** 297/**
4118 * Function that will be called if we receive a validation 298 * Function called by ATS to notify the callee that the
4119 * of an address challenge that we transmitted to another 299 * assigned bandwidth or address for a given peer was changed. If the
4120 * peer. Note that the validation should only be considered 300 * callback is called with address/bandwidth assignments of zero, the
4121 * acceptable if the challenge matches AND if the sender 301 * ATS disconnect function will still be called once the disconnect
4122 * address is at least a plausible address for this peer 302 * actually happened.
4123 * (otherwise we may be seeing a MiM attack).
4124 * 303 *
4125 * @param cls closure 304 * @param cls closure
4126 * @param message the pong message 305 * @param peer identity of the peer
4127 * @param peer who responded to our challenge 306 * @param plugin_name name of the transport plugin, NULL to disconnect
4128 * @param sender_address string describing our sender address (as observed 307 * @param session session to use (if available)
4129 * by the other peer in binary format) 308 * @param plugin_addr address to use (if available)
4130 * @param sender_address_len number of bytes in 'sender_address' 309 * @param plugin_addr_len number of bytes in addr
4131 */ 310 * @param bandwidth assigned outbound bandwidth for the connection
4132static void
4133handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4134 const struct GNUNET_PeerIdentity *peer, const char *sender_address,
4135 size_t sender_address_len)
4136{
4137 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
4138 {
4139 /* PONG send to self, ignore */
4140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from myself\n",
4141 "PONG");
4142 return;
4143 }
4144#if DEBUG_TRANSPORT > 1
4145 /* we get tons of these that just get discarded, only log
4146 * if we are quite verbose */
4147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message from `%4s'.\n",
4148 "PONG", GNUNET_i2s (peer));
4149#endif
4150 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), 1,
4151 GNUNET_NO);
4152 if (GNUNET_SYSERR !=
4153 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4154 &peer->hashPubKey,
4155 &check_pending_validation,
4156 (void *) message))
4157 {
4158 /* This is *expected* to happen a lot since we send
4159 * PONGs to *all* known addresses of the sender of
4160 * the PING, so most likely we get multiple PONGs
4161 * per PING, and all but the first PONG will end up
4162 * here. So really we should not print anything here
4163 * unless we want to be very, very verbose... */
4164#if DEBUG_TRANSPORT > 2
4165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4166 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4167 "PONG", GNUNET_i2s (peer), "PING");
4168#endif
4169 return;
4170 }
4171
4172}
4173
4174
4175/**
4176 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4177 *
4178 * @param cls the 'struct ValidationEntry*'
4179 * @param neighbour neighbour to validate, NULL if validation failed
4180 */ 311 */
4181static void 312static void
4182transmit_hello_and_ping (void *cls, struct NeighbourMapEntry *neighbour) 313ats_request_address_change (void *cls, const struct GNUNET_PeerIdentity *peer,
4183{ 314 const char *plugin_name, struct Session *session,
4184 struct ValidationEntry *va = cls; 315 const void *plugin_addr, size_t plugin_addr_len,
4185 struct ForeignAddressList *peer_address; 316 struct GNUNET_BANDWIDTH_Value32NBO bandwidth)
4186 struct TransportPingMessage ping;
4187 uint16_t hello_size;
4188 size_t tsize;
4189 char *message_buf;
4190 struct GNUNET_PeerIdentity id;
4191 size_t slen;
4192
4193 GNUNET_CRYPTO_hash (&va->publicKey,
4194 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4195 &id.hashPubKey);
4196 if (neighbour == NULL)
4197 {
4198 /* FIXME: stats... */
4199 GNUNET_break (GNUNET_OK ==
4200 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4201 &id.hashPubKey, va));
4202 abort_validation (NULL, NULL, va);
4203 return;
4204 }
4205 neighbour->publicKey = va->publicKey;
4206 neighbour->public_key_valid = GNUNET_YES;
4207 peer_address =
4208 add_peer_address (neighbour, va->transport_name, NULL,
4209 (const void *) &va[1], va->addrlen);
4210 if (peer_address == NULL)
4211 {
4212 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4213 "Failed to add peer `%4s' for plugin `%s'\n",
4214 GNUNET_i2s (&neighbour->id), va->transport_name);
4215 GNUNET_break (GNUNET_OK ==
4216 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4217 &id.hashPubKey, va));
4218 abort_validation (NULL, NULL, va);
4219 return;
4220 }
4221 if (NULL == our_hello)
4222 refresh_hello_task (NULL, NULL);
4223 hello_size = GNUNET_HELLO_size (our_hello);
4224 slen = strlen (va->transport_name) + 1;
4225 tsize =
4226 sizeof (struct TransportPingMessage) + hello_size + va->addrlen + slen;
4227 message_buf = GNUNET_malloc (tsize);
4228 ping.challenge = htonl (va->challenge);
4229 ping.header.size =
4230 htons (sizeof (struct TransportPingMessage) + slen + va->addrlen);
4231 ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4232 memcpy (&ping.target, &neighbour->id, sizeof (struct GNUNET_PeerIdentity));
4233 memcpy (message_buf, our_hello, hello_size);
4234 memcpy (&message_buf[hello_size], &ping,
4235 sizeof (struct TransportPingMessage));
4236 memcpy (&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4237 va->transport_name, slen);
4238 memcpy (&message_buf
4239 [hello_size + sizeof (struct TransportPingMessage) + slen], &va[1],
4240 va->addrlen);
4241#if DEBUG_TRANSPORT
4242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4243 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4244 (va->addrlen == 0) ? "<inbound>" : a2s (va->transport_name,
4245 (const void *) &va[1],
4246 va->addrlen),
4247 va->transport_name, GNUNET_i2s (&neighbour->id), "HELLO",
4248 hello_size, "PING",
4249 sizeof (struct TransportPingMessage) + va->addrlen + slen);
4250#endif
4251
4252 GNUNET_STATISTICS_update (stats,
4253 gettext_noop
4254 ("# PING messages sent for initial validation"), 1,
4255 GNUNET_NO);
4256 transmit_to_peer (NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4257 HELLO_VERIFICATION_TIMEOUT, message_buf, tsize, GNUNET_YES,
4258 neighbour);
4259 GNUNET_free (message_buf);
4260}
4261
4262
4263/**
4264 * Check if the given address is already being validated; if not,
4265 * append the given address to the list of entries that are being be
4266 * validated and initiate validation.
4267 *
4268 * @param cls closure ('struct CheckHelloValidatedContext *')
4269 * @param tname name of the transport
4270 * @param expiration expiration time
4271 * @param addr the address
4272 * @param addrlen length of the address
4273 * @return GNUNET_OK (always)
4274 */
4275static int
4276run_validation (void *cls, const char *tname,
4277 struct GNUNET_TIME_Absolute expiration, const void *addr,
4278 uint16_t addrlen)
4279{ 317{
4280 struct CheckHelloValidatedContext *chvc = cls; 318 GST_neighbours_switch_to_address (peer, plugin_name, plugin_addr,
4281 struct GNUNET_PeerIdentity id; 319 plugin_addr_len, session, NULL, 0);
4282 struct TransportPlugin *tp; 320 GST_neighbours_set_incoming_quota (peer, bandwidth);
4283 struct ValidationEntry *va;
4284 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4285 struct CheckAddressExistsClosure caec;
4286 struct OwnAddressList *oal;
4287
4288 GNUNET_assert (addr != NULL);
4289
4290 GNUNET_STATISTICS_update (stats,
4291 gettext_noop
4292 ("# peer addresses scheduled for validation"), 1,
4293 GNUNET_NO);
4294 tp = find_transport (tname);
4295 if (tp == NULL)
4296 {
4297 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
4298 _
4299 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4300 tname);
4301 GNUNET_STATISTICS_update (stats,
4302 gettext_noop
4303 ("# peer addresses not validated (plugin not available)"),
4304 1, GNUNET_NO);
4305 return GNUNET_OK;
4306 }
4307 /* check if this is one of our own addresses */
4308 oal = tp->addresses;
4309 while (NULL != oal)
4310 {
4311 if ((oal->addrlen == addrlen) && (0 == memcmp (&oal[1], addr, addrlen)))
4312 {
4313 /* not plausible, this address is equivalent to our own address! */
4314 GNUNET_STATISTICS_update (stats,
4315 gettext_noop
4316 ("# peer addresses not validated (loopback)"),
4317 1, GNUNET_NO);
4318 return GNUNET_OK;
4319 }
4320 oal = oal->next;
4321 }
4322 GNUNET_HELLO_get_key (chvc->hello, &pk);
4323 GNUNET_CRYPTO_hash (&pk,
4324 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4325 &id.hashPubKey);
4326
4327 if (is_blacklisted (&id, tp))
4328 {
4329#if DEBUG_TRANSPORT
4330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4331 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4332 GNUNET_i2s (&id), tname);
4333#endif
4334 return GNUNET_OK;
4335 }
4336
4337 caec.addr = addr;
4338 caec.addrlen = addrlen;
4339 caec.session = NULL;
4340 caec.tname = tname;
4341 caec.exists = GNUNET_NO;
4342 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &check_address_exists,
4343 &caec);
4344 if (caec.exists == GNUNET_YES)
4345 {
4346 /* During validation attempts we will likely trigger the other
4347 * peer trying to validate our address which in turn will cause
4348 * it to send us its HELLO, so we expect to hit this case rather
4349 * frequently. Only print something if we are very verbose. */
4350#if DEBUG_TRANSPORT > 1
4351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4352 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4353 a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id));
4354#endif
4355 GNUNET_STATISTICS_update (stats,
4356 gettext_noop
4357 ("# peer addresses not validated (in progress)"),
4358 1, GNUNET_NO);
4359 return GNUNET_OK;
4360 }
4361 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4362 va->chvc = chvc;
4363 chvc->ve_count++;
4364 va->transport_name = GNUNET_strdup (tname);
4365 va->challenge =
4366 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT_MAX);
4367 va->send_time = GNUNET_TIME_absolute_get ();
4368 va->addr = (const void *) &va[1];
4369 memcpy (&va[1], addr, addrlen);
4370 va->addrlen = addrlen;
4371 GNUNET_HELLO_get_key (chvc->hello, &va->publicKey);
4372 va->timeout_task =
4373 GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4374 &timeout_hello_validation, va);
4375 GNUNET_CONTAINER_multihashmap_put (validation_map, &id.hashPubKey, va,
4376 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4377 setup_peer_check_blacklist (&id, GNUNET_NO, &transmit_hello_and_ping, va);
4378 return GNUNET_OK;
4379} 321}
4380 322
4381 323
4382/** 324/**
4383 * Check if addresses in validated hello "h" overlap with 325 * Function called to notify transport users that another
4384 * those in "chvc->hello" and validate the rest. 326 * peer connected to us.
4385 * 327 *
4386 * @param cls closure 328 * @param cls closure
4387 * @param peer id of the peer, NULL for last call 329 * @param peer the peer that connected
4388 * @param h hello message for the peer (can be NULL) 330 * @param ats performance data
4389 * @param err_msg NULL if successful, otherwise contains error message 331 * @param ats_count number of entries in ats (excluding 0-termination)
4390 */ 332 */
4391static void 333static void
4392check_hello_validated (void *cls, const struct GNUNET_PeerIdentity *peer, 334neighbours_connect_notification (void *cls,
4393 const struct GNUNET_HELLO_Message *h, 335 const struct GNUNET_PeerIdentity *peer,
4394 const char *err_msg) 336 const struct GNUNET_TRANSPORT_ATS_Information
337 *ats, uint32_t ats_count)
4395{ 338{
4396 struct CheckHelloValidatedContext *chvc = cls; 339 char buf[sizeof (struct ConnectInfoMessage) +
4397 struct GNUNET_HELLO_Message *plain_hello; 340 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)];
4398 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; 341 struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
4399 struct GNUNET_PeerIdentity target; 342 struct GNUNET_TRANSPORT_ATS_Information *atsm = &connect_msg->ats;
4400 struct NeighbourMapEntry *n;
4401
4402 if (err_msg != NULL)
4403 {
4404#if DEBUG_TRANSPORT
4405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4406 _("Error in communication with PEERINFO service: %s\n"),
4407 err_msg);
4408#endif
4409 /* return; */
4410 }
4411 343
4412 if (peer == NULL) 344 connect_msg->header.size = htons (sizeof (buf));
4413 { 345 connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4414 GNUNET_STATISTICS_update (stats, 346 connect_msg->ats_count = htonl (ats_count);
4415 gettext_noop 347 connect_msg->id = *peer;
4416 ("# outstanding peerinfo iterate requests"), -1, 348 memcpy (&connect_msg->ats, ats,
4417 GNUNET_NO); 349 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
4418 chvc->piter = NULL; 350 atsm[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4419 if (GNUNET_NO == chvc->hello_known) 351 atsm[ats_count].value = htonl (0);
4420 { 352 GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
4421 /* notify PEERINFO about the peer now, so that we at least
4422 * have the public key if some other component needs it */
4423 GNUNET_HELLO_get_key (chvc->hello, &pk);
4424 GNUNET_CRYPTO_hash (&pk,
4425 sizeof (struct
4426 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4427 &target.hashPubKey);
4428 plain_hello = GNUNET_HELLO_create (&pk, NULL, NULL);
4429 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4430 GNUNET_free (plain_hello);
4431#if DEBUG_TRANSPORT_HELLO
4432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4433 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4434 "HELLO", GNUNET_i2s (&target));
4435#endif
4436 GNUNET_STATISTICS_update (stats,
4437 gettext_noop
4438 ("# new HELLOs requiring full validation"), 1,
4439 GNUNET_NO);
4440 GNUNET_HELLO_iterate_addresses (chvc->hello, GNUNET_NO, &run_validation,
4441 chvc);
4442 }
4443 else
4444 {
4445 GNUNET_STATISTICS_update (stats,
4446 gettext_noop ("# duplicate HELLO (peer known)"),
4447 1, GNUNET_NO);
4448 }
4449 chvc->ve_count--;
4450 if (chvc->ve_count == 0)
4451 {
4452 GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
4453 GNUNET_free (chvc);
4454 }
4455 return;
4456 }
4457 if (h == NULL)
4458 return;
4459#if DEBUG_TRANSPORT_HELLO
4460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4461 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4462 "HELLO", GNUNET_i2s (peer));
4463#endif
4464 chvc->hello_known = GNUNET_YES;
4465 n = find_neighbour (peer);
4466 if (n != NULL)
4467 {
4468#if DEBUG_TRANSPORT_HELLO
4469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4470 "Calling hello_iterate_addresses for %s!\n", GNUNET_i2s (peer));
4471#endif
4472 GNUNET_HELLO_iterate_addresses (h, GNUNET_NO, &add_to_foreign_address_list,
4473 n);
4474 try_transmission_to_peer (n);
4475 }
4476 else
4477 {
4478#if DEBUG_TRANSPORT_HELLO
4479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4480 "No existing neighbor record for %s!\n", GNUNET_i2s (peer));
4481#endif
4482 GNUNET_STATISTICS_update (stats,
4483 gettext_noop
4484 ("# no existing neighbour record (validating HELLO)"),
4485 1, GNUNET_NO);
4486 }
4487 GNUNET_STATISTICS_update (stats,
4488 gettext_noop ("# HELLO validations (update case)"),
4489 1, GNUNET_NO);
4490 GNUNET_HELLO_iterate_new_addresses (chvc->hello, h,
4491 GNUNET_TIME_relative_to_absolute
4492 (HELLO_REVALIDATION_START_TIME),
4493 &run_validation, chvc);
4494}
4495
4496
4497/**
4498 * Process HELLO-message.
4499 *
4500 * @param plugin transport involved, may be NULL
4501 * @param message the actual message
4502 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4503 */
4504static int
4505process_hello (struct TransportPlugin *plugin,
4506 const struct GNUNET_MessageHeader *message)
4507{
4508 uint16_t hsize;
4509 struct GNUNET_PeerIdentity target;
4510 const struct GNUNET_HELLO_Message *hello;
4511 struct CheckHelloValidatedContext *chvc;
4512 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4513 struct NeighbourMapEntry *n;
4514
4515#if DEBUG_TRANSPORT_HELLO > 2
4516 char *my_id;
4517#endif
4518
4519 hsize = ntohs (message->size);
4520 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4521 (hsize < sizeof (struct GNUNET_MessageHeader)))
4522 {
4523 GNUNET_break (0);
4524 return GNUNET_SYSERR;
4525 }
4526 GNUNET_STATISTICS_update (stats,
4527 gettext_noop ("# HELLOs received for validation"),
4528 1, GNUNET_NO);
4529
4530 hello = (const struct GNUNET_HELLO_Message *) message;
4531 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4532 {
4533#if DEBUG_TRANSPORT_HELLO
4534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4535 "Unable to get public key from `%s' for `%4s'!\n", "HELLO",
4536 GNUNET_i2s (&target));
4537#endif
4538 GNUNET_break_op (0);
4539 return GNUNET_SYSERR;
4540 }
4541 GNUNET_CRYPTO_hash (&publicKey,
4542 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4543 &target.hashPubKey);
4544
4545#if DEBUG_TRANSPORT_HELLO
4546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message for `%4s'\n",
4547 "HELLO", GNUNET_i2s (&target));
4548#endif
4549 if (0 == memcmp (&my_identity, &target, sizeof (struct GNUNET_PeerIdentity)))
4550 {
4551 GNUNET_STATISTICS_update (stats,
4552 gettext_noop
4553 ("# HELLOs ignored for validation (is my own HELLO)"),
4554 1, GNUNET_NO);
4555 return GNUNET_OK;
4556 }
4557 n = find_neighbour (&target);
4558 if ((NULL != n) && (!n->public_key_valid))
4559 {
4560 GNUNET_HELLO_get_key (hello, &n->publicKey);
4561 n->public_key_valid = GNUNET_YES;
4562 }
4563
4564 /* check if load is too high before doing expensive stuff */
4565 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) >
4566 MAX_HELLO_LOAD)
4567 {
4568 GNUNET_STATISTICS_update (stats,
4569 gettext_noop
4570 ("# HELLOs ignored due to high load"), 1,
4571 GNUNET_NO);
4572#if DEBUG_TRANSPORT_HELLO
4573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4574 "Ignoring `%s' for `%4s', load too high.\n", "HELLO",
4575 GNUNET_i2s (&target));
4576#endif
4577 return GNUNET_OK;
4578 }
4579
4580
4581 chvc = chvc_head;
4582 while (NULL != chvc)
4583 {
4584 if (GNUNET_HELLO_equals
4585 (hello, chvc->hello, GNUNET_TIME_absolute_get ()).abs_value > 0)
4586 {
4587#if DEBUG_TRANSPORT_HELLO > 2
4588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4589 "Received duplicate `%s' message for `%4s'; ignored\n",
4590 "HELLO", GNUNET_i2s (&target));
4591#endif
4592 return GNUNET_OK; /* validation already pending */
4593 }
4594 if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4595 GNUNET_break (0 !=
4596 memcmp (hello, chvc->hello, GNUNET_HELLO_size (hello)));
4597 chvc = chvc->next;
4598 }
4599
4600#if BREAK_TESTS
4601 struct NeighbourMapEntry *temp_neighbor = find_neighbour (&target);
4602
4603 if ((NULL != temp_neighbor))
4604 {
4605 fprintf (stderr, "Already know peer, ignoring hello\n");
4606 return GNUNET_OK;
4607 }
4608#endif
4609
4610#if DEBUG_TRANSPORT_HELLO > 2
4611 if (plugin != NULL)
4612 {
4613#if DEBUG_TRANSPORT
4614 my_id = GNUNET_strdup (GNUNET_i2s (plugin->env.my_identity));
4615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4616 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4617 my_id, "HELLO", GNUNET_i2s (&target), plugin->short_name,
4618 GNUNET_HELLO_size (hello));
4619 GNUNET_free (my_id);
4620#endif
4621 }
4622#endif
4623 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4624 chvc->ve_count = 1;
4625 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4626 memcpy (&chvc[1], hello, hsize);
4627 GNUNET_CONTAINER_DLL_insert (chvc_head, chvc_tail, chvc);
4628 /* finally, check if HELLO was previously validated
4629 * (continuation will then schedule actual validation) */
4630 GNUNET_STATISTICS_update (stats,
4631 gettext_noop
4632 ("# peerinfo process hello iterate requests"), 1,
4633 GNUNET_NO);
4634 GNUNET_STATISTICS_update (stats,
4635 gettext_noop
4636 ("# outstanding peerinfo iterate requests"), 1,
4637 GNUNET_NO);
4638 chvc->piter =
4639 GNUNET_PEERINFO_iterate (peerinfo, &target, HELLO_VERIFICATION_TIMEOUT,
4640 &check_hello_validated, chvc);
4641 return GNUNET_OK;
4642} 353}
4643 354
4644 355
4645/** 356/**
4646 * The peer specified by the given neighbour has timed-out or a plugin 357 * Function called to notify transport users that another
4647 * has disconnected. We may either need to do nothing (other plugins 358 * peer disconnected from us.
4648 * still up), or trigger a full disconnect and clean up. This
4649 * function updates our state and does the necessary notifications.
4650 * Also notifies our clients that the neighbour is now officially
4651 * gone.
4652 *
4653 * @param n the neighbour list entry for the peer
4654 * @param check GNUNET_YES to check if ALL addresses for this peer
4655 * are gone, GNUNET_NO to force a disconnect of the peer
4656 * regardless of whether other addresses exist.
4657 */
4658static void
4659disconnect_neighbour (struct NeighbourMapEntry *n, int check)
4660{
4661 struct ReadyList *rpos;
4662 struct MessageQueue *mq;
4663 struct ForeignAddressList *peer_addresses;
4664 struct ForeignAddressList *peer_pos;
4665
4666 if (GNUNET_YES == n->in_disconnect)
4667 return;
4668 if (GNUNET_YES == check)
4669 {
4670 rpos = n->plugins;
4671 while (NULL != rpos)
4672 {
4673 peer_addresses = rpos->addresses;
4674 while (peer_addresses != NULL)
4675 {
4676 /* Do not disconnect if: an address is connected or an inbound address exists */
4677 if ((GNUNET_YES == peer_addresses->connected) ||
4678 (peer_addresses->addrlen == 0))
4679 {
4680#if DEBUG_TRANSPORT
4681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4682 "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4683 GNUNET_i2s (&n->id),
4684 a2s (peer_addresses->ready_list->plugin->short_name,
4685 peer_addresses->addr, peer_addresses->addrlen));
4686#endif
4687 return; /* still connected */
4688 }
4689 peer_addresses = peer_addresses->next;
4690 }
4691 rpos = rpos->next;
4692 }
4693 }
4694#if DEBUG_TRANSPORT
4695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4696 "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
4697#endif
4698 n->in_disconnect = GNUNET_YES; /* prevent recursive entry */
4699
4700 /* notify all clients about disconnect */
4701 if (GNUNET_YES == n->received_pong)
4702 {
4703 n->received_pong = GNUNET_NO;
4704 notify_clients_disconnect (&n->id);
4705 }
4706#if HAVE_LIBGLPK
4707 ats_modify_problem_state (ats, ATS_MODIFIED);
4708#endif
4709 /* clean up all plugins, cancel connections and pending transmissions */
4710 while (NULL != (rpos = n->plugins))
4711 {
4712 n->plugins = rpos->next;
4713 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4714 while (rpos->addresses != NULL)
4715 {
4716 peer_pos = rpos->addresses;
4717 rpos->addresses = peer_pos->next;
4718 if (peer_pos->connected == GNUNET_YES)
4719 {
4720 GNUNET_STATISTICS_update (stats, gettext_noop ("# connected addresses"),
4721 -1, GNUNET_NO);
4722 peer_pos->connected = GNUNET_NO;
4723 }
4724 if (GNUNET_YES == peer_pos->validated)
4725 GNUNET_STATISTICS_update (stats,
4726 gettext_noop
4727 ("# peer addresses considered valid"), -1,
4728 GNUNET_NO);
4729 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4730 {
4731 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4732 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4733 }
4734 GNUNET_free (peer_pos->ressources);
4735 peer_pos->ressources = NULL;
4736 GNUNET_free (peer_pos->quality);
4737 peer_pos->ressources = NULL;
4738 GNUNET_free (peer_pos);
4739 }
4740 GNUNET_free (rpos);
4741 }
4742
4743 /* free all messages on the queue */
4744 while (NULL != (mq = n->messages_head))
4745 {
4746 GNUNET_STATISTICS_update (stats,
4747 gettext_noop
4748 ("# bytes in message queue for other peers"),
4749 -(int64_t) mq->message_buf_size, GNUNET_NO);
4750 GNUNET_STATISTICS_update (stats,
4751 gettext_noop
4752 ("# bytes discarded due to disconnect"),
4753 mq->message_buf_size, GNUNET_NO);
4754 GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
4755 GNUNET_assert (0 ==
4756 memcmp (&mq->neighbour_id, &n->id,
4757 sizeof (struct GNUNET_PeerIdentity)));
4758 GNUNET_free (mq);
4759 }
4760
4761 while (NULL != (mq = n->cont_head))
4762 {
4763
4764 GNUNET_CONTAINER_DLL_remove (n->cont_head, n->cont_tail, mq);
4765 GNUNET_assert (0 ==
4766 memcmp (&mq->neighbour_id, &n->id,
4767 sizeof (struct GNUNET_PeerIdentity)));
4768 GNUNET_free (mq);
4769 }
4770
4771 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4772 {
4773 GNUNET_SCHEDULER_cancel (n->timeout_task);
4774 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4775 }
4776 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4777 {
4778 GNUNET_SCHEDULER_cancel (n->retry_task);
4779 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4780 }
4781 if (n->piter != NULL)
4782 {
4783 GNUNET_PEERINFO_iterate_cancel (n->piter);
4784 GNUNET_STATISTICS_update (stats,
4785 gettext_noop
4786 ("# outstanding peerinfo iterate requests"), -1,
4787 GNUNET_NO);
4788 n->piter = NULL;
4789 }
4790
4791 GNUNET_assert (GNUNET_OK ==
4792 GNUNET_CONTAINER_multihashmap_remove (neighbours,
4793 &n->id.hashPubKey, n));
4794 /* finally, free n itself */
4795 GNUNET_STATISTICS_update (stats, gettext_noop ("# active neighbours"), -1,
4796 GNUNET_NO);
4797 GNUNET_free_non_null (n->pre_connect_message_buffer);
4798 GNUNET_free (n);
4799}
4800
4801
4802/**
4803 * We have received a PING message from someone. Need to send a PONG message
4804 * in response to the peer by any means necessary.
4805 */
4806static int
4807handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4808 const struct GNUNET_PeerIdentity *peer, struct Session *session,
4809 const char *sender_address, uint16_t sender_address_len)
4810{
4811 struct TransportPlugin *plugin = cls;
4812 struct SessionHeader *session_header = (struct SessionHeader *) session;
4813 struct TransportPingMessage *ping;
4814 struct TransportPongMessage *pong;
4815 struct NeighbourMapEntry *n;
4816 struct ReadyList *rl;
4817 struct ForeignAddressList *fal;
4818 struct OwnAddressList *oal;
4819 const char *addr;
4820 size_t alen;
4821 size_t slen;
4822 int did_pong;
4823
4824 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4825 {
4826 GNUNET_break_op (0);
4827 return GNUNET_SYSERR;
4828 }
4829
4830 ping = (struct TransportPingMessage *) message;
4831 if (0 !=
4832 memcmp (&ping->target, plugin->env.my_identity,
4833 sizeof (struct GNUNET_PeerIdentity)))
4834 {
4835#if DEBUG_TRANSPORT
4836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4837 _
4838 ("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4839 "PING", (sender_address != NULL) ? a2s (plugin->short_name,
4840 (const struct sockaddr
4841 *) sender_address,
4842 sender_address_len) :
4843 "<inbound>", GNUNET_i2s (&ping->target));
4844#endif
4845 return GNUNET_SYSERR;
4846 }
4847#if DEBUG_PING_PONG
4848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4849 "Processing `%s' from `%s'\n", "PING",
4850 (sender_address != NULL) ? a2s (plugin->short_name,
4851 (const struct sockaddr *)
4852 sender_address,
4853 sender_address_len) :
4854 "<inbound>");
4855#endif
4856 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), 1,
4857 GNUNET_NO);
4858 addr = (const char *) &ping[1];
4859 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4860 slen = strlen (plugin->short_name) + 1;
4861 if (alen == 0)
4862 {
4863 /* peer wants to confirm that we have an outbound connection to him */
4864 if (session == NULL)
4865 {
4866 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4867 _
4868 ("Refusing to create PONG since I do not have a session with `%s'.\n"),
4869 GNUNET_i2s (peer));
4870 return GNUNET_SYSERR;
4871 }
4872 /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
4873 * 1) it is NULL when we need to have a real value
4874 * 2) it is documented to be the address of the sender (source-IP), where
4875 * what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
4876 * have...
4877 */
4878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4879 "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
4880 a2s (plugin->short_name, sender_address, sender_address_len),
4881 GNUNET_i2s (peer));
4882
4883 pong =
4884 GNUNET_malloc (sizeof (struct TransportPongMessage) +
4885 sender_address_len + slen);
4886 pong->header.size =
4887 htons (sizeof (struct TransportPongMessage) + sender_address_len +
4888 slen);
4889 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4890 pong->purpose.size =
4891 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4892 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4893 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4894 pong->purpose.purpose =
4895 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4896 pong->challenge = ping->challenge;
4897 pong->addrlen = htonl (sender_address_len + slen);
4898 memcpy (&pong->pid, peer, sizeof (struct GNUNET_PeerIdentity));
4899 memcpy (&pong[1], plugin->short_name, slen);
4900 if ((sender_address != NULL) && (sender_address_len > 0))
4901 memcpy (&((char *) &pong[1])[slen], sender_address, sender_address_len);
4902 if (GNUNET_TIME_absolute_get_remaining
4903 (session_header->pong_sig_expires).rel_value <
4904 PONG_SIGNATURE_LIFETIME.rel_value / 4)
4905 {
4906 /* create / update cached sig */
4907#if DEBUG_TRANSPORT
4908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4909 "Creating PONG signature to indicate active connection.\n");
4910#endif
4911 session_header->pong_sig_expires =
4912 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4913 pong->expiration =
4914 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4915 GNUNET_assert (GNUNET_OK ==
4916 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4917 &session_header->pong_signature));
4918 }
4919 else
4920 {
4921 pong->expiration =
4922 GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4923 }
4924 memcpy (&pong->signature, &session_header->pong_signature,
4925 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4926
4927
4928 }
4929 else
4930 {
4931 /* peer wants to confirm that this is one of our addresses */
4932 addr += slen;
4933 alen -= slen;
4934 if (GNUNET_OK != plugin->api->check_address (plugin->api->cls, addr, alen))
4935 {
4936 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4937 _
4938 ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4939 a2s (plugin->short_name, addr, alen));
4940 return GNUNET_NO;
4941 }
4942 oal = plugin->addresses;
4943 while (NULL != oal)
4944 {
4945 if ((oal->addrlen == alen) && (0 == memcmp (addr, &oal[1], alen)))
4946 break;
4947 oal = oal->next;
4948 }
4949 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4950 pong->header.size =
4951 htons (sizeof (struct TransportPongMessage) + alen + slen);
4952 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4953 pong->purpose.size =
4954 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4955 sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4956 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4957 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4958 pong->challenge = ping->challenge;
4959 pong->addrlen = htonl (alen + slen);
4960 memcpy (&pong->pid, &my_identity, sizeof (struct GNUNET_PeerIdentity));
4961 memcpy (&pong[1], plugin->short_name, slen);
4962 memcpy (&((char *) &pong[1])[slen], addr, alen);
4963 if ((oal != NULL) &&
4964 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value <
4965 PONG_SIGNATURE_LIFETIME.rel_value / 4))
4966 {
4967 /* create / update cached sig */
4968#if DEBUG_TRANSPORT
4969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4970 "Creating PONG signature to indicate ownership.\n");
4971#endif
4972 oal->pong_sig_expires =
4973 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4974 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4975 GNUNET_assert (GNUNET_OK ==
4976 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4977 &oal->pong_signature));
4978 memcpy (&pong->signature, &oal->pong_signature,
4979 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4980 }
4981 else if (oal == NULL)
4982 {
4983 /* not using cache (typically DV-only) */
4984 pong->expiration =
4985 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
4986 (PONG_SIGNATURE_LIFETIME));
4987 GNUNET_assert (GNUNET_OK ==
4988 GNUNET_CRYPTO_rsa_sign (my_private_key, &pong->purpose,
4989 &pong->signature));
4990 }
4991 else
4992 {
4993 /* can used cached version */
4994 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4995 memcpy (&pong->signature, &oal->pong_signature,
4996 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4997 }
4998 }
4999 n = find_neighbour (peer);
5000 GNUNET_assert (n != NULL);
5001 did_pong = GNUNET_NO;
5002 /* first try reliable response transmission */
5003 rl = n->plugins;
5004 while (rl != NULL)
5005 {
5006 fal = rl->addresses;
5007 while (fal != NULL)
5008 {
5009 if (-1 !=
5010 rl->plugin->api->send (rl->plugin->api->cls, peer,
5011 (const char *) pong, ntohs (pong->header.size),
5012 TRANSPORT_PONG_PRIORITY,
5013 HELLO_VERIFICATION_TIMEOUT, fal->session,
5014 fal->addr, fal->addrlen, GNUNET_SYSERR, NULL,
5015 NULL))
5016 {
5017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5018 "Transmitted PONG to `%s' via reliable mechanism\n",
5019 GNUNET_i2s (peer));
5020 /* done! */
5021 GNUNET_STATISTICS_update (stats,
5022 gettext_noop
5023 ("# PONGs unicast via reliable transport"), 1,
5024 GNUNET_NO);
5025 GNUNET_free (pong);
5026 return GNUNET_OK;
5027 }
5028 did_pong = GNUNET_YES;
5029 fal = fal->next;
5030 }
5031 rl = rl->next;
5032 }
5033 /* no reliable method found, do multicast */
5034 GNUNET_STATISTICS_update (stats,
5035 gettext_noop
5036 ("# PONGs multicast to all available addresses"), 1,
5037 GNUNET_NO);
5038 rl = n->plugins;
5039 while (rl != NULL)
5040 {
5041 fal = rl->addresses;
5042 while (fal != NULL)
5043 {
5044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5045 "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5046 GNUNET_i2s (peer), a2s (rl->plugin->short_name, fal->addr,
5047 fal->addrlen),
5048 rl->plugin->short_name);
5049 transmit_to_peer (NULL, fal, TRANSPORT_PONG_PRIORITY,
5050 HELLO_VERIFICATION_TIMEOUT, (const char *) pong,
5051 ntohs (pong->header.size), GNUNET_YES, n);
5052 did_pong = GNUNET_YES;
5053 fal = fal->next;
5054 }
5055 rl = rl->next;
5056 }
5057 GNUNET_free (pong);
5058 if (GNUNET_YES != did_pong)
5059 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5060 _("Could not send PONG to `%s': no address available\n"),
5061 GNUNET_i2s (peer));
5062 return GNUNET_OK;
5063}
5064
5065
5066/**
5067 * Function called by the plugin for each received message. Update
5068 * data volumes, possibly notify plugins about reducing the rate at
5069 * which they read from the socket and generally forward to our
5070 * receive callback.
5071 *
5072 * @param cls the "struct TransportPlugin *" we gave to the plugin
5073 * @param peer (claimed) identity of the other peer
5074 * @param message the message, NULL if we only care about
5075 * learning about the delay until we should receive again
5076 * @param ats_data information for automatic transport selection
5077 * @param ats_count number of elements in ats not including 0-terminator
5078 * @param session identifier used for this session (can be NULL)
5079 * @param sender_address binary address of the sender (if observed)
5080 * @param sender_address_len number of bytes in sender_address
5081 * @return how long in ms the plugin should wait until receiving more data
5082 * (plugins that do not support this, can ignore the return value)
5083 */
5084static struct GNUNET_TIME_Relative
5085plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5086 const struct GNUNET_MessageHeader *message,
5087 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5088 uint32_t ats_count, struct Session *session,
5089 const char *sender_address, uint16_t sender_address_len)
5090{
5091 struct TransportPlugin *plugin = cls;
5092 struct ReadyList *service_context;
5093 struct ForeignAddressList *peer_address;
5094 uint16_t msize;
5095 struct NeighbourMapEntry *n;
5096 struct GNUNET_TIME_Relative ret;
5097 uint32_t distance;
5098 int c;
5099
5100 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
5101 {
5102 /* refuse to receive from myself */
5103 GNUNET_break (0);
5104 return GNUNET_TIME_UNIT_FOREVER_REL;
5105 }
5106 if (is_blacklisted (peer, plugin))
5107 return GNUNET_TIME_UNIT_FOREVER_REL;
5108 n = find_neighbour (peer);
5109 if (n == NULL)
5110 n = setup_new_neighbour (peer, GNUNET_YES);
5111 service_context = n->plugins;
5112 while ((service_context != NULL) && (plugin != service_context->plugin))
5113 service_context = service_context->next;
5114 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5115 peer_address = NULL;
5116 distance = 1;
5117
5118 for (c = 0; c < ats_count; c++)
5119 if (ntohl (ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5120 distance = ntohl (ats_data[c].value);
5121
5122
5123 if (message != NULL)
5124 {
5125 if ((session != NULL) || (sender_address != NULL))
5126 peer_address =
5127 add_peer_address (n, plugin->short_name, session, sender_address,
5128 sender_address_len);
5129 if (peer_address != NULL)
5130 {
5131 update_addr_ats (peer_address, ats_data, ats_count);
5132 update_addr_value (peer_address, distance,
5133 GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5134
5135 peer_address->distance = distance;
5136 if (GNUNET_YES == peer_address->validated)
5137 {
5138 mark_address_connected (peer_address);
5139 schedule_next_ping (peer_address);
5140 }
5141 else
5142 {
5143#if DEBUG_TRANSPORT
5144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5145 "New address is unvalidated, trying to validate it now\n");
5146#endif
5147 if (peer_address->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
5148 {
5149 GNUNET_SCHEDULER_cancel (peer_address->revalidate_task);
5150 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
5151 }
5152 peer_address->revalidate_task =
5153 GNUNET_SCHEDULER_add_now (&send_periodic_ping, peer_address);
5154
5155 }
5156 peer_address->timeout =
5157 GNUNET_TIME_relative_to_absolute
5158 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5159 }
5160 /* update traffic received amount ... */
5161 msize = ntohs (message->size);
5162
5163 GNUNET_STATISTICS_update (stats,
5164 gettext_noop
5165 ("# bytes received from other peers"), msize,
5166 GNUNET_NO);
5167 n->distance = distance;
5168 n->peer_timeout =
5169 GNUNET_TIME_relative_to_absolute
5170 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5171 GNUNET_SCHEDULER_cancel (n->timeout_task);
5172 n->timeout_task =
5173 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5174 &neighbour_timeout_task, n);
5175 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5176 {
5177 /* dropping message due to frequent inbound volume violations! */
5178 GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
5179 _
5180 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5181 n->in_tracker.available_bytes_per_s__,
5182 n->quota_violation_count);
5183 GNUNET_STATISTICS_update (stats,
5184 gettext_noop
5185 ("# bandwidth quota violations by other peers"),
5186 1, GNUNET_NO);
5187 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5188 }
5189 if ((ntohs (message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5190 (ntohs (message->size) ==
5191 (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5192 {
5193#if HAVE_LIBGLPK
5194 uint32_t value = ntohl (*((uint32_t *) & message[1]));
5195
5196 //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5197 /* Force ressource and quality update */
5198 if ((value == 4) && (ats != NULL))
5199 ats_modify_problem_state (ats, ATS_QUALITY_COST_UPDATED);
5200 /* Force cost update */
5201 if ((value == 3) && (ats != NULL))
5202 ats_modify_problem_state (ats, ATS_COST_UPDATED);
5203 /* Force quality update */
5204 if ((value == 2) && (ats != NULL))
5205 ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
5206 /* Force full rebuild */
5207 if ((value == 1) && (ats != NULL))
5208 ats_modify_problem_state (ats, ATS_MODIFIED);
5209#endif
5210 }
5211
5212#if DEBUG_PING_PONG
5213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5214 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5215 ntohs (message->type), ntohs (message->size),
5216 GNUNET_i2s (peer));
5217#endif
5218 switch (ntohs (message->type))
5219 {
5220 case GNUNET_MESSAGE_TYPE_HELLO:
5221 GNUNET_STATISTICS_update (stats,
5222 gettext_noop
5223 ("# HELLO messages received from other peers"),
5224 1, GNUNET_NO);
5225 process_hello (plugin, message);
5226 break;
5227 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5228 handle_ping (plugin, message, peer, session, sender_address,
5229 sender_address_len);
5230 if (GNUNET_YES != n->received_pong)
5231 transmit_plain_ping (n);
5232 break;
5233 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5234 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5235 break;
5236 case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5237 break;
5238 default:
5239 handle_payload_message (message, n);
5240 break;
5241 }
5242 }
5243 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5244 if (ret.rel_value > 0)
5245 {
5246#if DEBUG_TRANSPORT
5247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5248 "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5249 (unsigned long long) n->
5250 in_tracker.consumption_since_last_update__,
5251 (unsigned int) n->in_tracker.available_bytes_per_s__,
5252 (unsigned long long) ret.rel_value);
5253#endif
5254 GNUNET_STATISTICS_update (stats, gettext_noop ("# ms throttling suggested"),
5255 (int64_t) ret.rel_value, GNUNET_NO);
5256 }
5257 return ret;
5258}
5259
5260
5261static int
5262notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
5263 void *value)
5264{
5265 struct TransportClient *c = cls;
5266 struct NeighbourMapEntry *n = value;
5267 struct ConnectInfoMessage *cim;
5268 uint32_t ats_count;
5269 size_t size;
5270
5271 if (GNUNET_YES != n->received_pong)
5272 return GNUNET_OK;
5273
5274 ats_count = 2;
5275 size =
5276 sizeof (struct ConnectInfoMessage) +
5277 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5278 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
5279 cim = GNUNET_malloc (size);
5280 cim->header.size = htons (size);
5281 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5282 cim->ats_count = htonl (ats_count);
5283 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5284 (&(cim->ats))[2].value = htonl (0);
5285 if (GNUNET_YES == n->received_pong)
5286 {
5287 (&cim->ats)[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5288 (&cim->ats)[0].value = htonl (n->distance);
5289 (&cim->ats)[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5290 (&cim->ats)[1].value = htonl ((uint32_t) n->latency.rel_value);
5291 cim->id = n->id;
5292 transmit_to_client (c, &cim->header, GNUNET_NO);
5293 }
5294 GNUNET_free (cim);
5295 return GNUNET_OK;
5296}
5297
5298
5299/**
5300 * Handle START-message. This is the first message sent to us
5301 * by any client which causes us to add it to our list.
5302 *
5303 * @param cls closure (always NULL)
5304 * @param client identification of the client
5305 * @param message the actual message
5306 */
5307static void
5308handle_start (void *cls, struct GNUNET_SERVER_Client *client,
5309 const struct GNUNET_MessageHeader *message)
5310{
5311 const struct StartMessage *start;
5312 struct TransportClient *c;
5313
5314 start = (const struct StartMessage *) message;
5315#if DEBUG_TRANSPORT
5316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n",
5317 "START");
5318#endif
5319 c = clients;
5320 while (c != NULL)
5321 {
5322 if (c->client == client)
5323 {
5324 /* client already on our list! */
5325 GNUNET_break (0);
5326 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5327 return;
5328 }
5329 c = c->next;
5330 }
5331 if ((GNUNET_NO != ntohl (start->do_check)) &&
5332 (0 !=
5333 memcmp (&start->self, &my_identity,
5334 sizeof (struct GNUNET_PeerIdentity))))
5335 {
5336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5337 _
5338 ("Rejecting control connection from peer `%s', which is not me!\n"),
5339 GNUNET_i2s (&start->self));
5340 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5341 return;
5342 }
5343 c = GNUNET_malloc (sizeof (struct TransportClient));
5344 c->next = clients;
5345 clients = c;
5346 c->client = client;
5347 if (our_hello != NULL)
5348 {
5349#if DEBUG_TRANSPORT
5350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending our own `%s' to new client\n",
5351 "HELLO");
5352#endif
5353 transmit_to_client (c, (const struct GNUNET_MessageHeader *) our_hello,
5354 GNUNET_NO);
5355 /* tell new client about all existing connections */
5356 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
5357 &notify_client_about_neighbour, c);
5358 }
5359 else
5360 {
5361#if DEBUG_TRANSPORT_HELLO
5362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5363 "No HELLO created yet, will transmit HELLO to client later!\n");
5364#endif
5365 refresh_hello ();
5366 }
5367 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5368}
5369
5370
5371/**
5372 * Handle HELLO-message.
5373 *
5374 * @param cls closure (always NULL)
5375 * @param client identification of the client
5376 * @param message the actual message
5377 */
5378static void
5379handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
5380 const struct GNUNET_MessageHeader *message)
5381{
5382 int ret;
5383
5384 GNUNET_STATISTICS_update (stats,
5385 gettext_noop ("# HELLOs received from clients"), 1,
5386 GNUNET_NO);
5387 ret = process_hello (NULL, message);
5388 GNUNET_SERVER_receive_done (client, ret);
5389}
5390
5391
5392/**
5393 * Closure for 'transmit_client_message'; followed by
5394 * 'msize' bytes of the actual message.
5395 */
5396struct TransmitClientMessageContext
5397{
5398 /**
5399 * Client on whom's behalf we are sending.
5400 */
5401 struct GNUNET_SERVER_Client *client;
5402
5403 /**
5404 * Timeout for the transmission.
5405 */
5406 struct GNUNET_TIME_Absolute timeout;
5407
5408 /**
5409 * Message priority.
5410 */
5411 uint32_t priority;
5412
5413 /**
5414 * Size of the message in bytes.
5415 */
5416 uint16_t msize;
5417};
5418
5419
5420/**
5421 * Schedule transmission of a message we got from a client to a peer.
5422 *
5423 * @param cls the 'struct TransmitClientMessageContext*'
5424 * @param n destination, or NULL on error (in that case, drop the message)
5425 */
5426static void
5427transmit_client_message (void *cls, struct NeighbourMapEntry *n)
5428{
5429 struct TransmitClientMessageContext *tcmc = cls;
5430 struct TransportClient *tc;
5431
5432 tc = clients;
5433 while ((tc != NULL) && (tc->client != tcmc->client))
5434 tc = tc->next;
5435
5436 if (n != NULL)
5437 {
5438 transmit_to_peer (tc, NULL, tcmc->priority,
5439 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5440 (char *) &tcmc[1], tcmc->msize, GNUNET_NO, n);
5441 }
5442 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5443 GNUNET_SERVER_client_drop (tcmc->client);
5444 GNUNET_free (tcmc);
5445}
5446
5447
5448/**
5449 * Handle SEND-message.
5450 *
5451 * @param cls closure (always NULL)
5452 * @param client identification of the client
5453 * @param message the actual message
5454 */
5455static void
5456handle_send (void *cls, struct GNUNET_SERVER_Client *client,
5457 const struct GNUNET_MessageHeader *message)
5458{
5459 const struct OutboundMessage *obm;
5460 const struct GNUNET_MessageHeader *obmm;
5461 struct TransmitClientMessageContext *tcmc;
5462 uint16_t size;
5463 uint16_t msize;
5464
5465 size = ntohs (message->size);
5466 if (size <
5467 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5468 {
5469 GNUNET_break (0);
5470 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5471 return;
5472 }
5473 GNUNET_STATISTICS_update (stats,
5474 gettext_noop ("# payload received for other peers"),
5475 size, GNUNET_NO);
5476 obm = (const struct OutboundMessage *) message;
5477 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5478 msize = size - sizeof (struct OutboundMessage);
5479#if DEBUG_TRANSPORT
5480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5481 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5482 "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
5483#endif
5484 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5485 tcmc->client = client;
5486 tcmc->priority = ntohl (obm->priority);
5487 tcmc->timeout =
5488 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh
5489 (obm->timeout));
5490 tcmc->msize = msize;
5491 /* FIXME: this memcpy can be up to 7% of our total runtime */
5492 memcpy (&tcmc[1], obmm, msize);
5493 GNUNET_SERVER_client_keep (client);
5494 setup_peer_check_blacklist (&obm->peer, GNUNET_YES, &transmit_client_message,
5495 tcmc);
5496}
5497
5498
5499/**
5500 * Handle request connect message
5501 *
5502 * @param cls closure (always NULL)
5503 * @param client identification of the client
5504 * @param message the actual message
5505 */
5506static void
5507handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
5508 const struct GNUNET_MessageHeader *message)
5509{
5510 const struct TransportRequestConnectMessage *trcm =
5511 (const struct TransportRequestConnectMessage *) message;
5512
5513 GNUNET_STATISTICS_update (stats,
5514 gettext_noop
5515 ("# REQUEST CONNECT messages received"), 1,
5516 GNUNET_NO);
5517#if DEBUG_TRANSPORT
5518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5519 "Received a request connect message for peer `%s'\n",
5520 GNUNET_i2s (&trcm->peer));
5521#endif
5522 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES, NULL, NULL);
5523 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5524}
5525
5526
5527/**
5528 * Handle SET_QUOTA-message.
5529 *
5530 * @param cls closure (always NULL)
5531 * @param client identification of the client
5532 * @param message the actual message
5533 */
5534static void
5535handle_set_quota (void *cls, struct GNUNET_SERVER_Client *client,
5536 const struct GNUNET_MessageHeader *message)
5537{
5538 const struct QuotaSetMessage *qsm = (const struct QuotaSetMessage *) message;
5539 struct NeighbourMapEntry *n;
5540
5541 GNUNET_STATISTICS_update (stats,
5542 gettext_noop ("# SET QUOTA messages received"), 1,
5543 GNUNET_NO);
5544 n = find_neighbour (&qsm->peer);
5545 if (n == NULL)
5546 {
5547 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5548 GNUNET_STATISTICS_update (stats,
5549 gettext_noop
5550 ("# SET QUOTA messages ignored (no such peer)"),
5551 1, GNUNET_NO);
5552 return;
5553 }
5554#if DEBUG_TRANSPORT
5555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5556 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5557 "SET_QUOTA", (unsigned int) ntohl (qsm->quota.value__),
5558 (unsigned int) n->in_tracker.available_bytes_per_s__,
5559 GNUNET_i2s (&qsm->peer));
5560#endif
5561 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, qsm->quota);
5562 if (0 == ntohl (qsm->quota.value__))
5563 {
5564#if DEBUG_TRANSPORT
5565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
5566 GNUNET_i2s (&n->id), "SET_QUOTA");
5567#endif
5568 GNUNET_STATISTICS_update (stats,
5569 gettext_noop ("# disconnects due to quota of 0"),
5570 1, GNUNET_NO);
5571 disconnect_neighbour (n, GNUNET_NO);
5572 }
5573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5574}
5575
5576
5577/**
5578 * Take the given address and append it to the set of results sent back to
5579 * the client.
5580 *
5581 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5582 * @param address the resolved name, NULL to indicate the last response
5583 */
5584static void
5585transmit_address_to_client (void *cls, const char *address)
5586{
5587 struct GNUNET_SERVER_TransmitContext *tc = cls;
5588 size_t slen;
5589
5590 if (NULL != address)
5591 {
5592 slen = strlen (address) + 1;
5593 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5594 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5595 }
5596 else
5597 {
5598 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5599 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5600 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5601 }
5602}
5603
5604
5605/**
5606 * Handle AddressLookup-message.
5607 *
5608 * @param cls closure (always NULL)
5609 * @param client identification of the client
5610 * @param message the actual message
5611 */
5612static void
5613handle_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5614 const struct GNUNET_MessageHeader *message)
5615{
5616 const struct AddressLookupMessage *alum;
5617 struct TransportPlugin *lsPlugin;
5618 const char *nameTransport;
5619 const char *address;
5620 uint16_t size;
5621 struct GNUNET_SERVER_TransmitContext *tc;
5622 struct GNUNET_TIME_Relative rtimeout;
5623 int32_t numeric;
5624
5625 size = ntohs (message->size);
5626 if (size < sizeof (struct AddressLookupMessage))
5627 {
5628 GNUNET_break_op (0);
5629 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5630 return;
5631 }
5632 alum = (const struct AddressLookupMessage *) message;
5633 uint32_t addressLen = ntohl (alum->addrlen);
5634
5635 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5636 {
5637 GNUNET_break_op (0);
5638 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5639 return;
5640 }
5641 address = (const char *) &alum[1];
5642 nameTransport = (const char *) &address[addressLen];
5643 if (nameTransport
5644 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5645 {
5646 GNUNET_break_op (0);
5647 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5648 return;
5649 }
5650 rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
5651 numeric = ntohl (alum->numeric_only);
5652 lsPlugin = find_transport (nameTransport);
5653 if (NULL == lsPlugin)
5654 {
5655 tc = GNUNET_SERVER_transmit_context_create (client);
5656 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5657 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5658 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5659 return;
5660 }
5661 GNUNET_SERVER_disable_receive_done_warning (client);
5662 tc = GNUNET_SERVER_transmit_context_create (client);
5663 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls, nameTransport,
5664 address, addressLen, numeric, rtimeout,
5665 &transmit_address_to_client, tc);
5666}
5667
5668/**
5669 * Handle PeerAddressLookupMessage.
5670 *
5671 * @param cls closure (always NULL)
5672 * @param client identification of the client
5673 * @param message the actual message
5674 */
5675static void
5676handle_peer_address_lookup (void *cls, struct GNUNET_SERVER_Client *client,
5677 const struct GNUNET_MessageHeader *message)
5678{
5679 const struct PeerAddressLookupMessage *peer_address_lookup;
5680 struct NeighbourMapEntry *neighbor_iterator;
5681 struct ReadyList *ready_iterator;
5682 struct ForeignAddressList *foreign_address_iterator;
5683 struct TransportPlugin *transport_plugin;
5684
5685 uint16_t size;
5686 struct GNUNET_SERVER_TransmitContext *tc;
5687 struct GNUNET_TIME_Relative rtimeout;
5688 char *addr_buf;
5689
5690 size = ntohs (message->size);
5691 if (size < sizeof (struct PeerAddressLookupMessage))
5692 {
5693 GNUNET_break_op (0);
5694 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5695 return;
5696 }
5697 peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5698
5699 rtimeout = GNUNET_TIME_relative_ntoh (peer_address_lookup->timeout);
5700
5701 neighbor_iterator = find_neighbour (&peer_address_lookup->peer);
5702
5703 /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5704 if (neighbor_iterator == NULL)
5705 {
5706 GNUNET_break (0);
5707 tc = GNUNET_SERVER_transmit_context_create (client);
5708 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5709 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5710 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5711 return;
5712 }
5713
5714 ready_iterator = neighbor_iterator->plugins;
5715 GNUNET_SERVER_disable_receive_done_warning (client);
5716 tc = GNUNET_SERVER_transmit_context_create (client);
5717 while (ready_iterator != NULL)
5718 {
5719 foreign_address_iterator = ready_iterator->addresses;
5720 while (foreign_address_iterator != NULL)
5721 {
5722 transport_plugin = foreign_address_iterator->ready_list->plugin;
5723 if (foreign_address_iterator->addr != NULL)
5724 {
5725 GNUNET_asprintf (&addr_buf, "%s --- %s, %s",
5726 a2s (transport_plugin->short_name,
5727 foreign_address_iterator->addr,
5728 foreign_address_iterator->addrlen),
5729 (foreign_address_iterator->connected ==
5730 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5731 (foreign_address_iterator->validated ==
5732 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5733 transmit_address_to_client (tc, addr_buf);
5734 GNUNET_free (addr_buf);
5735 }
5736 else if (foreign_address_iterator->addrlen == 0)
5737 {
5738 GNUNET_asprintf (&addr_buf, "%s --- %s, %s", "<inbound>",
5739 (foreign_address_iterator->connected ==
5740 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5741 (foreign_address_iterator->validated ==
5742 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5743 transmit_address_to_client (tc, addr_buf);
5744 GNUNET_free (addr_buf);
5745 }
5746
5747 foreign_address_iterator = foreign_address_iterator->next;
5748 }
5749 ready_iterator = ready_iterator->next;
5750 }
5751 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5752 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5753 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5754}
5755
5756
5757
5758static int
5759output_addresses (void *cls, const GNUNET_HashCode * key, void *value)
5760{
5761 struct GNUNET_SERVER_TransmitContext *tc = cls;
5762 struct NeighbourMapEntry *neighbor_iterator = value;
5763 struct ForeignAddressList *foreign_address_iterator;
5764 struct TransportPlugin *transport_plugin;
5765 struct ReadyList *ready_iterator;
5766 char *addr_buf;
5767
5768 ready_iterator = neighbor_iterator->plugins;
5769 while (ready_iterator != NULL)
5770 {
5771 foreign_address_iterator = ready_iterator->addresses;
5772 while (foreign_address_iterator != NULL)
5773 {
5774 transport_plugin = foreign_address_iterator->ready_list->plugin;
5775 if (foreign_address_iterator->addr != NULL)
5776 {
5777 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5778 GNUNET_i2s (&neighbor_iterator->id),
5779 a2s (transport_plugin->short_name,
5780 foreign_address_iterator->addr,
5781 foreign_address_iterator->addrlen),
5782 (foreign_address_iterator->connected ==
5783 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5784 (foreign_address_iterator->validated ==
5785 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5786 transmit_address_to_client (tc, addr_buf);
5787 GNUNET_free (addr_buf);
5788 }
5789 else if (foreign_address_iterator->addrlen == 0)
5790 {
5791 GNUNET_asprintf (&addr_buf, "%s:%s --- %s, %s",
5792 GNUNET_i2s (&neighbor_iterator->id), "<inbound>",
5793 (foreign_address_iterator->connected ==
5794 GNUNET_YES) ? "CONNECTED" : "DISCONNECTED",
5795 (foreign_address_iterator->validated ==
5796 GNUNET_YES) ? "VALIDATED" : "UNVALIDATED");
5797 transmit_address_to_client (tc, addr_buf);
5798 GNUNET_free (addr_buf);
5799 }
5800
5801 foreign_address_iterator = foreign_address_iterator->next;
5802 }
5803 ready_iterator = ready_iterator->next;
5804 }
5805 return GNUNET_OK;
5806}
5807
5808
5809/**
5810 * Handle AddressIterateMessage
5811 *
5812 * @param cls closure (always NULL)
5813 * @param client identification of the client
5814 * @param message the actual message
5815 */
5816static void
5817handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
5818 const struct GNUNET_MessageHeader *message)
5819{
5820 struct GNUNET_SERVER_TransmitContext *tc;
5821 uint16_t size;
5822
5823 size = ntohs (message->size);
5824 if (size < sizeof (struct AddressIterateMessage))
5825 {
5826 GNUNET_break_op (0);
5827 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5828 return;
5829 }
5830 GNUNET_SERVER_disable_receive_done_warning (client);
5831 tc = GNUNET_SERVER_transmit_context_create (client);
5832 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &output_addresses, tc);
5833 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5834 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5835 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5836}
5837
5838
5839static const struct GNUNET_MessageHeader *
5840do_get_our_hello ()
5841{
5842 return (const struct GNUNET_MessageHeader *) our_hello;
5843}
5844
5845
5846/**
5847 * Setup the environment for this plugin.
5848 */
5849static void
5850create_environment (struct TransportPlugin *plug)
5851{
5852 plug->env.cfg = cfg;
5853 plug->env.my_identity = &my_identity;
5854 plug->env.get_our_hello = &do_get_our_hello;
5855 plug->env.cls = plug;
5856 plug->env.receive = &plugin_env_receive;
5857 plug->env.notify_address = &plugin_env_notify_address;
5858 plug->env.session_end = &plugin_env_session_end;
5859 plug->env.max_connections = max_connect_per_transport;
5860 plug->env.stats = stats;
5861}
5862
5863
5864/**
5865 * Start the specified transport (load the plugin).
5866 */
5867static void
5868start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
5869{
5870 struct TransportPlugin *plug;
5871 char *libname;
5872
5873 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
5874 name);
5875 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5876 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5877 create_environment (plug);
5878 plug->short_name = GNUNET_strdup (name);
5879 plug->lib_name = libname;
5880 plug->next = plugins;
5881 plugins = plug;
5882 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5883 if (plug->api == NULL)
5884 {
5885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5886 _("Failed to load transport plugin for `%s'\n"), name);
5887 GNUNET_free (plug->short_name);
5888 plugins = plug->next;
5889 GNUNET_free (libname);
5890 GNUNET_free (plug);
5891 }
5892}
5893
5894
5895static int
5896null_mq_client_pointers (void *cls, const GNUNET_HashCode * key, void *value)
5897{
5898 struct TransportClient *pos = cls;
5899 struct NeighbourMapEntry *n = value;
5900 struct MessageQueue *mq;
5901
5902 for (mq = n->messages_head; mq != NULL; mq = mq->next)
5903 {
5904 if (mq->client == pos)
5905 mq->client = NULL; /* do not use anymore! */
5906 }
5907 return GNUNET_OK;
5908}
5909
5910
5911/**
5912 * Called whenever a client is disconnected. Frees our
5913 * resources associated with that client.
5914 * 359 *
5915 * @param cls closure 360 * @param cls closure
5916 * @param client identification of the client 361 * @param peer the peer that disconnected
5917 */ 362 */
5918static void 363static void
5919client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) 364neighbours_disconnect_notification (void *cls,
365 const struct GNUNET_PeerIdentity *peer)
5920{ 366{
5921 struct TransportClient *pos; 367 struct DisconnectInfoMessage disconnect_msg;
5922 struct TransportClient *prev;
5923 struct ClientMessageQueueEntry *mqe;
5924 struct Blacklisters *bl;
5925 struct BlacklistCheck *bc;
5926 368
5927 if (client == NULL) 369 disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage));
5928 return; 370 disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
5929#if DEBUG_TRANSPORT 371 disconnect_msg.reserved = htonl (0);
5930 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, 372 disconnect_msg.peer = *peer;
5931 "Client disconnected, cleaning up.\n"); 373 GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
5932#endif
5933 /* clean up blacklister */
5934 bl = bl_head;
5935 while (bl != NULL)
5936 {
5937 if (bl->client == client)
5938 {
5939 bc = bc_head;
5940 while (bc != NULL)
5941 {
5942 if (bc->bl_pos == bl)
5943 {
5944 bc->bl_pos = bl->next;
5945 if (bc->th != NULL)
5946 {
5947 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5948 bc->th = NULL;
5949 }
5950 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5951 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
5952 break;
5953 }
5954 bc = bc->next;
5955 }
5956 GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
5957 GNUNET_SERVER_client_drop (bl->client);
5958 GNUNET_free (bl);
5959 break;
5960 }
5961 bl = bl->next;
5962 }
5963 /* clean up 'normal' clients */
5964 prev = NULL;
5965 pos = clients;
5966 while ((pos != NULL) && (pos->client != client))
5967 {
5968 prev = pos;
5969 pos = pos->next;
5970 }
5971 if (pos == NULL)
5972 return;
5973 while (NULL != (mqe = pos->message_queue_head))
5974 {
5975 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5976 pos->message_queue_tail, mqe);
5977 pos->message_count--;
5978 GNUNET_free (mqe);
5979 }
5980 if (NULL != neighbours)
5981 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &null_mq_client_pointers,
5982 pos);
5983 if (prev == NULL)
5984 clients = pos->next;
5985 else
5986 prev->next = pos->next;
5987 if (GNUNET_YES == pos->tcs_pending)
5988 {
5989 pos->client = NULL;
5990 return;
5991 }
5992 if (pos->th != NULL)
5993 {
5994 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5995 pos->th = NULL;
5996 }
5997 GNUNET_break (0 == pos->message_count);
5998 GNUNET_free (pos);
5999}
6000
6001
6002static int
6003disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
6004{
6005 struct NeighbourMapEntry *n = value;
6006
6007#if DEBUG_TRANSPORT
6008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
6009 GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
6010#endif
6011 disconnect_neighbour (n, GNUNET_NO);
6012 return GNUNET_OK;
6013} 374}
6014 375
6015 376
@@ -6023,280 +384,33 @@ disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
6023static void 384static void
6024shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 385shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6025{ 386{
6026 struct TransportPlugin *plug; 387 GST_validation_stop ();
6027 struct OwnAddressList *al; 388 GST_plugins_unload ();
6028 struct CheckHelloValidatedContext *chvc; 389 GST_neighbours_stop ();
6029 390 GNUNET_ATS_shutdown (GST_ats);
6030 shutdown_in_progress = GNUNET_YES; 391 GST_ats = NULL;
6031 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours, 392 GST_clients_stop ();
6032 NULL); 393 GST_blacklist_stop ();
6033#if DEBUG_TRANSPORT 394 GST_hello_stop ();
6034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6035 "Transport service is unloading plugins...\n");
6036#endif
6037 while (NULL != (plug = plugins))
6038 {
6039 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6040 {
6041 GNUNET_SCHEDULER_cancel (plug->address_update_task);
6042 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6043 }
6044 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6045 GNUNET_free (plug->lib_name);
6046 GNUNET_free (plug->short_name);
6047 while (NULL != (al = plug->addresses))
6048 {
6049 plug->addresses = al->next;
6050 GNUNET_free (al);
6051 }
6052 plugins = plug->next;
6053 GNUNET_free (plug);
6054 }
6055 if (my_private_key != NULL)
6056 GNUNET_CRYPTO_rsa_key_free (my_private_key);
6057 GNUNET_free_non_null (our_hello);
6058
6059 GNUNET_CONTAINER_multihashmap_iterate (validation_map, &abort_validation,
6060 NULL);
6061 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6062 validation_map = NULL;
6063
6064
6065 if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6066 {
6067 GNUNET_SCHEDULER_cancel (ats_task);
6068 ats_task = GNUNET_SCHEDULER_NO_TASK;
6069 }
6070#if HAVE_LIBGLPK
6071 if (ats != NULL)
6072 ats_shutdown (ats);
6073#endif
6074
6075 /* free 'chvc' data structure */
6076 while (NULL != (chvc = chvc_head))
6077 {
6078 chvc_head = chvc->next;
6079 if (chvc->piter != NULL)
6080 {
6081 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6082 GNUNET_STATISTICS_update (stats,
6083 gettext_noop
6084 ("# outstanding peerinfo iterate requests"), -1,
6085 GNUNET_NO);
6086 chvc->ve_count--;
6087 }
6088 else
6089 GNUNET_break (0);
6090 GNUNET_assert (chvc->ve_count == 0);
6091 GNUNET_free (chvc);
6092 }
6093 chvc_tail = NULL;
6094
6095 if (stats != NULL)
6096 {
6097 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6098 stats = NULL;
6099 }
6100 if (peerinfo != NULL)
6101 {
6102 GNUNET_PEERINFO_disconnect (peerinfo);
6103 peerinfo = NULL;
6104 }
6105 if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6106 {
6107 GNUNET_SCHEDULER_cancel (hello_task);
6108 hello_task = GNUNET_SCHEDULER_NO_TASK;
6109 }
6110 /* Can we assume those are gone by now, or do we need to clean up
6111 * explicitly!? */
6112 GNUNET_break (bl_head == NULL);
6113 GNUNET_break (bc_head == NULL);
6114 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6115 neighbours = NULL;
6116}
6117
6118
6119void
6120ats_result_cb ()
6121{
6122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS Result callback\n");
6123}
6124 395
6125 396 if (GST_peerinfo != NULL)
6126#if HAVE_LIBGLPK
6127struct AtsBuildContext
6128{
6129 struct ATS_mechanism *mechanisms;
6130 struct ATS_peer *peers;
6131 int c_peers;
6132 int c_mechs;
6133};
6134
6135
6136static int
6137find_and_count_addresses (void *cls, const GNUNET_HashCode * key, void *value)
6138{
6139 struct AtsBuildContext *abc = cls;
6140 struct NeighbourMapEntry *next = value;
6141 int found_addresses = GNUNET_NO;
6142
6143 struct ReadyList *r_next = next->plugins;
6144
6145 while (r_next != NULL)
6146 { 397 {
6147 struct ForeignAddressList *a_next = r_next->addresses; 398 GNUNET_PEERINFO_disconnect (GST_peerinfo);
6148 399 GST_peerinfo = NULL;
6149 while (a_next != NULL)
6150 {
6151 abc->c_mechs++;
6152 found_addresses = GNUNET_YES;
6153 a_next = a_next->next;
6154 }
6155 r_next = r_next->next;
6156 } 400 }
6157 if (found_addresses) 401 if (GST_stats != NULL)
6158 abc->c_peers++;
6159 return GNUNET_OK;
6160}
6161
6162
6163static int
6164setup_ats_problem (void *cls, const GNUNET_HashCode * key, void *value)
6165{
6166 struct AtsBuildContext *abc = cls;
6167 struct NeighbourMapEntry *next = value;
6168
6169 int found_addresses = GNUNET_NO;
6170 struct ReadyList *r_next = next->plugins;
6171
6172 while (r_next != NULL)
6173 { 402 {
6174 struct ForeignAddressList *a_next = r_next->addresses; 403 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
6175 404 GST_stats = NULL;
6176 while (a_next != NULL)
6177 {
6178 if (found_addresses == GNUNET_NO)
6179 {
6180 abc->peers[abc->c_peers].peer = next->id;
6181 abc->peers[abc->c_peers].m_head = NULL;
6182 abc->peers[abc->c_peers].m_tail = NULL;
6183 abc->peers[abc->c_peers].f = 1.0 / abc->c_mechs;
6184 }
6185 abc->mechanisms[abc->c_mechs].addr = a_next;
6186 abc->mechanisms[abc->c_mechs].col_index = abc->c_mechs;
6187 abc->mechanisms[abc->c_mechs].peer = &abc->peers[abc->c_peers];
6188 abc->mechanisms[abc->c_mechs].next = NULL;
6189 abc->mechanisms[abc->c_mechs].plugin = r_next->plugin;
6190 abc->mechanisms[abc->c_mechs].ressources = a_next->ressources;
6191 abc->mechanisms[abc->c_mechs].quality = a_next->quality;
6192 GNUNET_CONTAINER_DLL_insert_tail (abc->peers[abc->c_peers].m_head,
6193 abc->peers[abc->c_peers].m_tail,
6194 &abc->mechanisms[abc->c_mechs]);
6195 found_addresses = GNUNET_YES;
6196 abc->c_mechs++;
6197 a_next = a_next->next;
6198 }
6199 r_next = r_next->next;
6200 } 405 }
6201 if (found_addresses == GNUNET_YES) 406 if (GST_my_private_key != NULL)
6202 abc->c_peers++;
6203 return GNUNET_OK;
6204}
6205
6206
6207static void
6208create_ats_information (struct ATS_peer **p, int *c_p, struct ATS_mechanism **m,
6209 int *c_m)
6210{
6211 struct AtsBuildContext abc;
6212
6213#if VERBOSE_ATS
6214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6215 "ATS requires clean address information\n");
6216#endif
6217 abc.c_peers = 0;
6218 abc.c_mechs = 0;
6219 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &find_and_count_addresses,
6220 &abc);
6221#if VERBOSE_ATS
6222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6223 "Found %u peers with % u transport mechanisms\n", c_peers,
6224 c_mechs);
6225#endif
6226
6227 if ((abc.c_peers == 0) && (abc.c_mechs == 0))
6228 { 407 {
6229 *p = NULL; 408 GNUNET_CRYPTO_rsa_key_free (GST_my_private_key);
6230 (*c_p) = 0; 409 GST_my_private_key = NULL;
6231 *m = NULL;
6232 (*c_m) = 0;
6233 return;
6234 } 410 }
6235
6236 abc.mechanisms =
6237 GNUNET_malloc ((1 + abc.c_mechs) * sizeof (struct ATS_mechanism));
6238 abc.peers = GNUNET_malloc ((1 + abc.c_peers) * sizeof (struct ATS_peer));
6239 abc.c_mechs = 1;
6240 abc.c_peers = 1;
6241 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &setup_ats_problem, &abc);
6242 abc.c_mechs--;
6243 abc.c_peers--;
6244 (*c_m) = abc.c_mechs;
6245 (*c_p) = abc.c_peers;
6246 (*p) = abc.peers;
6247 (*m) = abc.mechanisms;
6248} 411}
6249 412
6250 413
6251static void
6252schedule_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6253{
6254 struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6255
6256 if (ats == NULL)
6257 return;
6258
6259 ats_task = GNUNET_SCHEDULER_NO_TASK;
6260 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6261 return;
6262
6263 if (shutdown_in_progress == GNUNET_YES)
6264 return;
6265
6266 struct GNUNET_TIME_Relative delta =
6267 GNUNET_TIME_absolute_get_difference (last_ats_execution,
6268 GNUNET_TIME_absolute_get ());
6269
6270 if (delta.rel_value < ats_minimum_interval.rel_value)
6271 {
6272#if DEBUG_ATS
6273 GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6274 "Minimum time between cycles not reached\n");
6275#endif
6276 return;
6277 }
6278
6279#if DEBUG_ATS
6280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6281#endif
6282#if HAVE_LIBGLPK
6283 ats_calculate_bandwidth_distribution (ats);
6284#endif
6285 last_ats_execution = GNUNET_TIME_absolute_get ();
6286
6287 ats_task =
6288 GNUNET_SCHEDULER_add_delayed (ats_regular_interval, &schedule_ats, ats);
6289}
6290#endif
6291
6292
6293struct ForeignAddressList *
6294get_preferred_ats_address (struct NeighbourMapEntry *n)
6295{
6296 // TODO get ATS prefered address
6297 return find_ready_address (n);
6298}
6299
6300/** 414/**
6301 * Initiate transport service. 415 * Initiate transport service.
6302 * 416 *
@@ -6308,209 +422,55 @@ static void
6308run (void *cls, struct GNUNET_SERVER_Handle *server, 422run (void *cls, struct GNUNET_SERVER_Handle *server,
6309 const struct GNUNET_CONFIGURATION_Handle *c) 423 const struct GNUNET_CONFIGURATION_Handle *c)
6310{ 424{
6311 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6312 {&handle_start, NULL,
6313 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6314 {&handle_hello, NULL,
6315 GNUNET_MESSAGE_TYPE_HELLO, 0},
6316 {&handle_send, NULL,
6317 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6318 {&handle_request_connect, NULL,
6319 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
6320 sizeof (struct TransportRequestConnectMessage)},
6321 {&handle_set_quota, NULL,
6322 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6323 {&handle_address_lookup, NULL,
6324 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6325 0},
6326 {&handle_peer_address_lookup, NULL,
6327 GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6328 0},
6329 {&handle_address_iterate, NULL,
6330 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
6331 0},
6332 {&handle_blacklist_init, NULL,
6333 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
6334 sizeof (struct GNUNET_MessageHeader)},
6335 {&handle_blacklist_reply, NULL,
6336 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
6337 sizeof (struct BlacklistMessage)},
6338 {NULL, NULL, 0, 0}
6339 };
6340 char *plugs;
6341 char *pos;
6342 int no_transports;
6343 unsigned long long tneigh;
6344 char *keyfile; 425 char *keyfile;
6345 426
6346 shutdown_in_progress = GNUNET_NO; 427 /* setup globals */
6347 cfg = c; 428 GST_cfg = c;
6348 stats = GNUNET_STATISTICS_create ("transport", cfg); 429 if (GNUNET_OK !=
6349 validation_map = GNUNET_CONTAINER_multihashmap_create (64); 430 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
6350 neighbours = GNUNET_CONTAINER_multihashmap_create (256); 431 &keyfile))
6351 /* parse configuration */
6352 if ((GNUNET_OK !=
6353 GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT", "NEIGHBOUR_LIMIT",
6354 &tneigh)) ||
6355 (GNUNET_OK !=
6356 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
6357 &keyfile)))
6358 { 432 {
6359 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6360 _ 434 _
6361 ("Transport service is lacking key configuration settings. Exiting.\n")); 435 ("Transport service is lacking key configuration settings. Exiting.\n"));
6362 GNUNET_SCHEDULER_shutdown (); 436 GNUNET_SCHEDULER_shutdown ();
6363 if (stats != NULL)
6364 {
6365 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6366 stats = NULL;
6367 }
6368 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6369 validation_map = NULL;
6370 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6371 neighbours = NULL;
6372 return;
6373 }
6374
6375 max_connect_per_transport = (uint32_t) tneigh;
6376 peerinfo = GNUNET_PEERINFO_connect (cfg);
6377 if (peerinfo == NULL)
6378 {
6379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6380 _("Could not access PEERINFO service. Exiting.\n"));
6381 GNUNET_SCHEDULER_shutdown ();
6382 if (stats != NULL)
6383 {
6384 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6385 stats = NULL;
6386 }
6387 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6388 validation_map = NULL;
6389 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6390 neighbours = NULL;
6391 GNUNET_free (keyfile);
6392 return; 437 return;
6393 } 438 }
6394 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); 439 GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6395 GNUNET_free (keyfile); 440 GNUNET_free (keyfile);
6396 if (my_private_key == NULL) 441 if (GST_my_private_key == NULL)
6397 { 442 {
6398 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6399 _("Transport service could not access hostkey. Exiting.\n")); 444 _("Transport service could not access hostkey. Exiting.\n"));
6400 GNUNET_SCHEDULER_shutdown (); 445 GNUNET_SCHEDULER_shutdown ();
6401 if (stats != NULL)
6402 {
6403 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6404 stats = NULL;
6405 }
6406 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6407 validation_map = NULL;
6408 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
6409 neighbours = NULL;
6410 return; 446 return;
6411 } 447 }
6412 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); 448 GST_stats = GNUNET_STATISTICS_create ("transport", c);
6413 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), 449 GST_peerinfo = GNUNET_PEERINFO_connect (c);
6414 &my_identity.hashPubKey); 450 GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key);
6415 /* setup notification */ 451 GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key),
6416 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, 452 &GST_my_identity.hashPubKey);
6417 NULL);
6418 /* load plugins... */
6419 no_transports = 1;
6420 if (GNUNET_OK ==
6421 GNUNET_CONFIGURATION_get_value_string (c, "TRANSPORT", "PLUGINS", &plugs))
6422 {
6423 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
6424 plugs);
6425 pos = strtok (plugs, " ");
6426 while (pos != NULL)
6427 {
6428 start_transport (server, pos);
6429 no_transports = 0;
6430 pos = strtok (NULL, " ");
6431 }
6432 GNUNET_free (plugs);
6433 }
6434 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, 453 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
6435 NULL); 454 NULL);
6436 if (no_transports) 455 if (GST_peerinfo == NULL)
6437 refresh_hello ();
6438
6439 /* Initializing ATS */
6440 int co;
6441 char *section;
6442 unsigned long long value;
6443
6444#if HAVE_LIBGLPK
6445 double D = 1.0;
6446 double U = 1.0;
6447 double R = 1.0;
6448 int v_b_min = 64000;
6449 int v_n_min = 5;
6450#endif
6451
6452 ats_minimum_interval = ATS_MIN_INTERVAL;
6453 ats_regular_interval = ATS_EXEC_INTERVAL;
6454
6455 /* loading cost ressources */
6456 for (co = 0; co < available_ressources; co++)
6457 { 456 {
6458 GNUNET_asprintf (&section, "%s_UP", ressources[co].cfg_param); 457 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6459 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section)) 458 _("Could not access PEERINFO service. Exiting.\n"));
6460 { 459 GNUNET_SCHEDULER_shutdown ();
6461 if (GNUNET_OK == 460 return;
6462 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6463 &value))
6464 {
6465#if DEBUG_ATS
6466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6467 "Found ressource cost: [%s] = %llu\n", section, value);
6468#endif
6469 ressources[co].c_max = value;
6470 }
6471 }
6472 GNUNET_free (section);
6473 GNUNET_asprintf (&section, "%s_DOWN", ressources[co].cfg_param);
6474 if (GNUNET_CONFIGURATION_have_value (cfg, "transport", section))
6475 {
6476 if (GNUNET_OK ==
6477 GNUNET_CONFIGURATION_get_value_number (cfg, "transport", section,
6478 &value))
6479 {
6480#if DEBUG_ATS
6481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6482 "Found ressource cost: [%s] = %llu\n", section, value);
6483#endif
6484 ressources[co].c_min = value;
6485 }
6486 }
6487 GNUNET_free (section);
6488 } 461 }
6489#if HAVE_LIBGLPK
6490 ats =
6491 ats_init (D, U, R, v_b_min, v_n_min, ATS_MAX_ITERATIONS,
6492 ATS_MAX_EXEC_DURATION, &create_ats_information, ats_result_cb);
6493 ats_set_logging_options (ats, stats, cfg);
6494 GNUNET_break (GNUNET_OK ==
6495 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6496 "ATS_EXEC_INTERVAL",
6497 &ats_regular_interval));
6498 GNUNET_break (GNUNET_OK ==
6499 GNUNET_CONFIGURATION_get_value_time (cfg, "transport",
6500 "ATS_MIN_INTERVAL",
6501 &ats_minimum_interval));
6502 if (ats != NULL)
6503 ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6504#endif
6505 462
6506 463 /* start subsystems */
6507#if DEBUG_TRANSPORT 464 GST_hello_start (&process_hello_update, NULL);
6508 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n")); 465 GST_blacklist_start (server);
6509#endif 466 GST_plugins_load (&plugin_env_receive_callback,
6510 /* If we have a blacklist file, read from it */ 467 &plugin_env_address_change_notification,
6511 read_blacklist_file (cfg); 468 &plugin_env_session_end);
6512 /* process client requests */ 469 GST_ats = GNUNET_ATS_init (GST_cfg, &ats_request_address_change, NULL);
6513 GNUNET_SERVER_add_handlers (server, handlers); 470 GST_neighbours_start (NULL, &neighbours_connect_notification,
471 &neighbours_disconnect_notification);
472 GST_clients_start (server);
473 GST_validation_start ();
6514} 474}
6515 475
6516 476
@@ -6524,10 +484,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
6524int 484int
6525main (int argc, char *const *argv) 485main (int argc, char *const *argv)
6526{ 486{
6527 a2s (NULL, NULL, 0); /* make compiler happy */
6528 return (GNUNET_OK == 487 return (GNUNET_OK ==
6529 GNUNET_SERVICE_run (argc, argv, "transport", 488 GNUNET_SERVICE_run (argc, argv, "transport",
6530 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; 489 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
6531} 490}
6532 491
6533/* end of gnunet-service-transport.c */ 492/* end of file gnunet-service-transport-new.c */