aboutsummaryrefslogtreecommitdiff
path: root/src/topology
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-01-18 13:57:58 +0000
committerChristian Grothoff <christian@grothoff.org>2010-01-18 13:57:58 +0000
commitc914e078ab8e9dc2b65f2bc02ce260b9d1d209de (patch)
tree7ee8cd9ad2b4302a0f5166f3ca05c6407fe3b6fe /src/topology
parent7a65c4fb6e8d2f0fd85fe8e951214c39882193e7 (diff)
downloadgnunet-c914e078ab8e9dc2b65f2bc02ce260b9d1d209de.tar.gz
gnunet-c914e078ab8e9dc2b65f2bc02ce260b9d1d209de.zip
cleaning up topology code:
Diffstat (limited to 'src/topology')
-rw-r--r--src/topology/gnunet-daemon-topology.c1041
-rw-r--r--src/topology/test_gnunet_service_topology_data.conf1
2 files changed, 492 insertions, 550 deletions
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c
index 16707777d..5c581fd42 100644
--- a/src/topology/gnunet-daemon-topology.c
+++ b/src/topology/gnunet-daemon-topology.c
@@ -22,6 +22,20 @@
22 * @file topology/gnunet-daemon-topology.c 22 * @file topology/gnunet-daemon-topology.c
23 * @brief code for maintaining the mesh topology 23 * @brief code for maintaining the mesh topology
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - make sure that PEERINFO *also* notifies us when a HELLO expires
28 * (otherwise the 'soft state' of this module does not work nicely)
29 * - CORE API's connect/disconnect API is not nice (we think we are
30 * connected when we are not; disconnect using bandwidth-limiting
31 * does not really work and is not nice)
32 * OPTIMIZATIONS:
33 * - move code to use hash table instead of linked list
34 * - instead of periodically discarding blacklisted entries,
35 * simply add task that is triggered at the right time (earlier free,
36 * more balanced load)
37 * - check if new HELLO learned is different from old HELLO
38 * before resetting entire state!
25 */ 39 */
26 40
27#include <stdlib.h> 41#include <stdlib.h>
@@ -36,29 +50,26 @@
36#define DEBUG_TOPOLOGY GNUNET_NO 50#define DEBUG_TOPOLOGY GNUNET_NO
37 51
38/** 52/**
39 * For how long do we blacklist a peer after a failed 53 * For how long do we blacklist a peer after a failed connection
40 * connection attempt? 54 * attempt?
41 */ 55 */
42#define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS 56#define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS
43 57
44/** 58/**
45 * For how long do we blacklist a friend after a failed 59 * For how long do we blacklist a friend after a failed connection
46 * connection attempt? 60 * attempt?
47 */ 61 */
48#define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) 62#define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
49 63
50/** 64/**
51 * How frequently are we allowed to ask PEERINFO for more 65 * How often do we at most advertise any HELLO to a peer?
52 * HELLO's to advertise (at most)?
53 */ 66 */
54#define MIN_HELLO_GATHER_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 27) 67#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
55 68
56/** 69/**
57 * How often do we at most advertise the same HELLO to the same peer? 70 * How often do we at most advertise the same HELLO to the same peer?
58 * Also used to remove HELLOs of peers that PEERINFO no longer lists
59 * from our cache.
60 */ 71 */
61#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) 72#define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
62 73
63 74
64/** 75/**
@@ -73,68 +84,65 @@ struct PeerList
73 struct PeerList *next; 84 struct PeerList *next;
74 85
75 /** 86 /**
76 * Is this peer listed here because he is a friend? 87 * Our handle for the request to transmit HELLOs to this peer; NULL
88 * if no such request is pending.
77 */ 89 */
78 int is_friend; 90 struct GNUNET_CORE_TransmitHandle *hello_req;
79 91
80 /** 92 /**
81 * Are we connected to this peer right now? 93 * Our handle for the request to connect to this peer; NULL if no
94 * such request is pending.
82 */ 95 */
83 int is_connected; 96 struct GNUNET_CORE_TransmitHandle *connect_req;
84 97
85 /** 98 /**
86 * Until what time should we not try to connect again 99 * Pointer to the HELLO message of this peer; can be NULL.
87 * to this peer?
88 */ 100 */
89 struct GNUNET_TIME_Absolute blacklisted_until; 101 struct GNUNET_HELLO_Message *hello;
90 102
91 /** 103 /**
92 * Last time we transmitted a HELLO to this peer? 104 * Bloom filter used to mark which peers already got the HELLO
105 * from this peer.
93 */ 106 */
94 struct GNUNET_TIME_Absolute last_hello_sent; 107 struct GNUNET_CONTAINER_BloomFilter *filter;
95 108
96 /** 109 /**
97 * ID of the peer. 110 * Is this peer listed here because he is a friend?
98 */ 111 */
99 struct GNUNET_PeerIdentity id; 112 int is_friend;
100
101};
102 113
114 /**
115 * Are we connected to this peer right now?
116 */
117 int is_connected;
103 118
104/**
105 * List of HELLOs we may consider for advertising.
106 */
107struct HelloList
108{
109 /** 119 /**
110 * This is a linked list. 120 * Until what time should we not try to connect again
121 * to this peer?
111 */ 122 */
112 struct HelloList *next; 123 struct GNUNET_TIME_Absolute blacklisted_until;
113 124
114 /** 125 /**
115 * Pointer to the HELLO message. Memory allocated as part 126 * Next time we are allowed to transmit a HELLO to this peer?
116 * of the "struct HelloList" --- do not free!
117 */ 127 */
118 struct GNUNET_HELLO_Message *msg; 128 struct GNUNET_TIME_Absolute next_hello_allowed;
119 129
120 /** 130 /**
121 * Bloom filter used to mark which peers already got 131 * When should we reset the bloom filter of this entry?
122 * this HELLO.
123 */ 132 */
124 struct GNUNET_CONTAINER_BloomFilter *filter; 133 struct GNUNET_TIME_Absolute filter_expiration;
125 134
126 /** 135 /**
127 * What peer is this HELLO for? 136 * ID of task we use to wait for the time to send the next HELLO
137 * to this peer.
128 */ 138 */
129 struct GNUNET_PeerIdentity id; 139 GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
130 140
131 /** 141 /**
132 * When should we remove this entry from the linked list (either 142 * ID of the peer.
133 * resetting the filter or possibly eliminating it for good because
134 * we no longer consider the peer to be participating in the
135 * network)?
136 */ 143 */
137 struct GNUNET_TIME_Absolute expiration; 144 struct GNUNET_PeerIdentity id;
145
138}; 146};
139 147
140 148
@@ -166,29 +174,21 @@ struct DisconnectList
166}; 174};
167 175
168 176
169
170/** 177/**
171 * Our peerinfo notification context. We use notification 178 * Our peerinfo notification context. We use notification
172 * to instantly learn about new peers as they are discovered 179 * to instantly learn about new peers as they are discovered.
173 * as well as periodic iteration to try peers again after
174 * a while.
175 */ 180 */
176static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify; 181static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
177 182
178/** 183/**
179 * Linked list of HELLOs for advertising.
180 */
181static struct HelloList *hellos;
182
183/**
184 * Our scheduler. 184 * Our scheduler.
185 */ 185 */
186static struct GNUNET_SCHEDULER_Handle * sched; 186static struct GNUNET_SCHEDULER_Handle *sched;
187 187
188/** 188/**
189 * Our configuration. 189 * Our configuration.
190 */ 190 */
191static const struct GNUNET_CONFIGURATION_Handle * cfg; 191static const struct GNUNET_CONFIGURATION_Handle *cfg;
192 192
193/** 193/**
194 * Handle to the core API. 194 * Handle to the core API.
@@ -206,15 +206,10 @@ static struct GNUNET_TRANSPORT_Handle *transport;
206static struct GNUNET_PeerIdentity my_identity; 206static struct GNUNET_PeerIdentity my_identity;
207 207
208/** 208/**
209 * Linked list of all of our friends and all of our current 209 * Linked list of all of our friends, all of our current neighbours
210 * neighbours. 210 * and all peers for which we have HELLOs. So pretty much everyone.
211 */
212static struct PeerList *friends;
213
214/**
215 * Timestamp from the last time we tried to gather HELLOs.
216 */ 211 */
217static struct GNUNET_TIME_Absolute last_hello_gather_time; 212static struct PeerList *peers;
218 213
219/** 214/**
220 * Flag to disallow non-friend connections (pure F2F mode). 215 * Flag to disallow non-friend connections (pure F2F mode).
@@ -248,18 +243,6 @@ static unsigned int friend_count;
248static int autoconnect; 243static int autoconnect;
249 244
250/** 245/**
251 * Non-NULL if we are currently having a request pending with
252 * PEERINFO asking for HELLOs for advertising?
253 */
254static struct GNUNET_PEERINFO_IteratorContext *pitr;
255
256/**
257 * Non-NULL if we are currently having a request pending with
258 * PEERINFO looking for more peers to connect to.
259 */
260static struct GNUNET_PEERINFO_IteratorContext *pitr_more;
261
262/**
263 * Head of doubly-linked list of active 'disconnect' requests that we have issued. 246 * Head of doubly-linked list of active 'disconnect' requests that we have issued.
264 */ 247 */
265static struct DisconnectList *disconnect_head; 248static struct DisconnectList *disconnect_head;
@@ -303,7 +286,10 @@ disconnect_done (void *cls,
303 286
304 287
305/** 288/**
306 * Force a disconnect from the specified peer. 289 * Force a disconnect from the specified peer. This is currently done by
290 * changing the bandwidth policy to 0 bytes per second.
291 * FIXME: maybe we want a nicer CORE API for both connect and disconnect...
292 * FIXME: this policy change is never undone; how do we reconnect ever?
307 */ 293 */
308static void 294static void
309force_disconnect (const struct GNUNET_PeerIdentity *peer) 295force_disconnect (const struct GNUNET_PeerIdentity *peer)
@@ -327,14 +313,18 @@ force_disconnect (const struct GNUNET_PeerIdentity *peer)
327 313
328 314
329/** 315/**
330 * Function called by core when our attempt to connect 316 * Function called by core when our attempt to connect succeeded.
331 * succeeded. Does nothing. 317 * Transmits a 'DUMMY' message to trigger the session key exchange.
318 * FIXME: this is an issue with the current CORE API.
332 */ 319 */
333static size_t 320static size_t
334ready_callback (void *cls, 321ready_callback (void *cls,
335 size_t size, void *buf) 322 size_t size, void *buf)
336{ 323{
324 struct PeerList *pos = cls;
337 struct GNUNET_MessageHeader hdr; 325 struct GNUNET_MessageHeader hdr;
326
327 pos->connect_req = NULL;
338 if (buf == NULL) 328 if (buf == NULL)
339 { 329 {
340#if DEBUG_TOPOLOGY 330#if DEBUG_TOPOLOGY
@@ -361,26 +351,8 @@ ready_callback (void *cls,
361 * @param pos entry in our friend list; NULL if not in friend list yet 351 * @param pos entry in our friend list; NULL if not in friend list yet
362 */ 352 */
363static void 353static void
364attempt_connect (const struct GNUNET_PeerIdentity *peer, 354attempt_connect (struct PeerList *pos)
365 struct PeerList *pos)
366{ 355{
367 if (pos == NULL)
368 {
369 pos = friends;
370 while (pos != NULL)
371 {
372 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
373 break;
374 pos = pos->next;
375 }
376 }
377 if (pos == NULL)
378 {
379 pos = GNUNET_malloc (sizeof(struct PeerList));
380 pos->id = *peer;
381 pos->next = friends;
382 friends = pos;
383 }
384 if (GNUNET_YES == pos->is_friend) 356 if (GNUNET_YES == pos->is_friend)
385 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND); 357 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
386 else 358 else
@@ -388,42 +360,35 @@ attempt_connect (const struct GNUNET_PeerIdentity *peer,
388#if DEBUG_TOPOLOGY 360#if DEBUG_TOPOLOGY
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "Asking core to connect to `%s'\n", 362 "Asking core to connect to `%s'\n",
391 GNUNET_i2s (peer)); 363 GNUNET_i2s (&pos->id));
392#endif 364#endif
393 GNUNET_CORE_notify_transmit_ready (handle, 365 pos->connect_req = GNUNET_CORE_notify_transmit_ready (handle,
394 0 /* priority */, 366 0 /* priority */,
395 GNUNET_TIME_UNIT_MINUTES, 367 GNUNET_TIME_UNIT_MINUTES,
396 peer, 368 &pos->id,
397 sizeof(struct GNUNET_MessageHeader), 369 sizeof(struct GNUNET_MessageHeader),
398 &ready_callback, 370 &ready_callback,
399 NULL); 371 pos);
400} 372}
401 373
402 374
403/** 375/**
404 * Is this peer one of our friends? 376 * Find a peer in our linked list.
377 * FIXME: should probably use a hash map instead.
405 */ 378 */
406static int 379struct PeerList *
407is_friend (const struct GNUNET_PeerIdentity * peer) 380find_peer (const struct GNUNET_PeerIdentity * peer)
408{ 381{
409 struct PeerList *pos; 382 struct PeerList *pos;
410 383
411 pos = friends; 384 pos = peers;
412 while (pos != NULL) 385 while (pos != NULL)
413 { 386 {
414 if ( (GNUNET_YES == pos->is_friend) && 387 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
415 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) ) 388 return pos;
416 {
417#if DEBUG_TOPOLOGY
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "Determined that `%s' is a friend\n",
420 GNUNET_i2s (peer));
421#endif
422 return GNUNET_YES;
423 }
424 pos = pos->next; 389 pos = pos->next;
425 } 390 }
426 return GNUNET_NO; 391 return NULL;
427} 392}
428 393
429 394
@@ -431,18 +396,18 @@ is_friend (const struct GNUNET_PeerIdentity * peer)
431 * Check if an additional connection from the given peer is allowed. 396 * Check if an additional connection from the given peer is allowed.
432 */ 397 */
433static int 398static int
434is_connection_allowed (const struct GNUNET_PeerIdentity * peer) 399is_connection_allowed (struct PeerList *peer)
435{ 400{
436 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity))) 401 if (0 == memcmp (&my_identity, &peer->id, sizeof (struct GNUNET_PeerIdentity)))
437 return GNUNET_SYSERR; /* disallow connections to self */ 402 return GNUNET_SYSERR; /* disallow connections to self */
438 if (is_friend (peer)) 403 if (peer->is_friend)
439 return GNUNET_OK; 404 return GNUNET_OK;
440 if (GNUNET_YES == friends_only) 405 if (GNUNET_YES == friends_only)
441 { 406 {
442#if DEBUG_TOPOLOGY 407#if DEBUG_TOPOLOGY
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Determined that `%s' is not allowed to connect (not a friend)\n", 409 "Determined that `%s' is not allowed to connect (not a friend)\n",
445 GNUNET_i2s (peer)); 410 GNUNET_i2s (&peer->id));
446#endif 411#endif
447 return GNUNET_SYSERR; 412 return GNUNET_SYSERR;
448 } 413 }
@@ -451,21 +416,220 @@ is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
451#if DEBUG_TOPOLOGY 416#if DEBUG_TOPOLOGY
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453 "Determined that `%s' is not allowed to connect (not enough connected friends)\n", 418 "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
454 GNUNET_i2s (peer)); 419 GNUNET_i2s (&peer->id));
455#endif 420#endif
456 return GNUNET_SYSERR; 421 return GNUNET_SYSERR;
457} 422}
458 423
459 424
460/** 425/**
426 * Create a new entry in the peer list.
427 *
428 * @param peer identity of the new entry
429 * @param hello hello message, can be NULL
430 * @param is_friend is the new entry for a friend?
431 * @return the new entry
432 */
433static struct PeerList *
434make_peer (const struct
435 GNUNET_PeerIdentity * peer,
436 const struct GNUNET_HELLO_Message *hello,
437 int is_friend)
438{
439 struct PeerList *ret;
440
441 ret = GNUNET_malloc (sizeof (struct PeerList));
442 ret->id = *peer;
443 ret->is_friend = is_friend;
444 if (hello != NULL)
445 {
446 ret->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
447 memcpy (ret->hello, hello,
448 GNUNET_HELLO_size (hello));
449 }
450 ret->next = peers;
451 peers = ret;
452 return ret;
453}
454
455
456/**
457 * Free all resources associated with the given peer.
458 *
459 * @param peer peer to free
460 */
461static void
462free_peer (struct PeerList *peer)
463{
464 struct PeerList *pos;
465 struct PeerList *prev;
466 struct PeerList *next;
467
468 prev = NULL;
469 next = peers;
470 while (peer != (pos = next))
471 {
472 next = pos->next;
473 prev = pos;
474 }
475 GNUNET_assert (pos != NULL);
476 if (prev == NULL)
477 peers = next;
478 else
479 prev->next = next;
480 if (pos->hello_req != NULL)
481 GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
482 if (pos->connect_req != NULL)
483 GNUNET_CORE_notify_transmit_ready_cancel (pos->connect_req);
484 if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
485 GNUNET_SCHEDULER_cancel (sched,
486 pos->hello_delay_task);
487 GNUNET_free (pos);
488}
489
490
491/**
492 * Setup bloom filter for the given peer entry.
493 *
494 * @param peer entry to initialize
495 */
496static void
497setup_filter (struct PeerList *peer)
498{
499 /* 2^{-5} chance of not sending a HELLO to a peer is
500 acceptably small (if the filter is 50% full);
501 64 bytes of memory are small compared to the rest
502 of the data structure and would only really become
503 "useless" once a HELLO has been passed on to ~100
504 other peers, which is likely more than enough in
505 any case; hence 64, 5 as bloomfilter parameters. */
506 peer->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
507 peer->filter_expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
508 /* never send a peer its own HELLO */
509 GNUNET_CONTAINER_bloomfilter_add (peer->filter, &peer->id.hashPubKey);
510}
511
512
513/**
514 * Function to fill send buffer with HELLO.
515 *
516 * @param cls 'struct PeerList' of the target peer
517 * @param size number of bytes available in buf
518 * @param buf where the callee should write the message
519 * @return number of bytes written to buf
520 */
521static size_t
522hello_advertising_ready (void *cls,
523 size_t size,
524 void *buf);
525
526
527/**
528 * Calculate when we would like to send the next HELLO to this
529 * peer and ask for it.
530 *
531 * @param cls for which peer to schedule the HELLO
532 * @param tc task context
533 */
534static void
535schedule_next_hello (void *cls,
536 const struct GNUNET_SCHEDULER_TaskContext *tc)
537{
538 struct PeerList *pl = cls;
539 struct PeerList *pos;
540 struct PeerList *next;
541 uint16_t next_want;
542 struct GNUNET_TIME_Relative next_adv;
543 struct GNUNET_TIME_Relative rst_time;
544
545 pl->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
546 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
547 return; /* we're out of here */
548 next_want = 0;
549 next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
550 /* find applicable HELLOs */
551 next = peers;
552 while (NULL != (pos = next))
553 {
554 next = pos->next;
555 if (pos->hello == NULL)
556 continue;
557 rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
558 if (0 == rst_time.value)
559 {
560 /* time to discard... */
561 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
562 setup_filter (pos);
563 }
564 else
565 {
566 if (rst_time.value < next_adv.value)
567 next_want = GNUNET_HELLO_size (pos->hello);
568 next_adv = GNUNET_TIME_relative_min (rst_time,
569 next_adv);
570 }
571 if (GNUNET_NO ==
572 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
573 &pl->id.hashPubKey))
574 break;
575 }
576 if (pos != NULL)
577 next_adv = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
578 if (next_adv.value == 0)
579 {
580 /* now! */
581 pl->hello_req = GNUNET_CORE_notify_transmit_ready (handle, 0,
582 next_adv,
583 &pl->id,
584 next_want,
585 &hello_advertising_ready,
586 pl);
587 return;
588 }
589 pl->hello_delay_task
590 = GNUNET_SCHEDULER_add_delayed (sched,
591 next_adv,
592 &schedule_next_hello,
593 pl);
594}
595
596
597/**
598 * Cancel existing requests for sending HELLOs to this peer
599 * and recalculate when we should send HELLOs to it based
600 * on our current state (something changed!).
601 */
602static void
603reschedule_hellos (struct PeerList *peer)
604{
605 if (peer->hello_req != NULL)
606 {
607 GNUNET_CORE_notify_transmit_ready_cancel (peer->hello_req);
608 peer->hello_req = NULL;
609 }
610 if (peer->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
611 {
612 GNUNET_SCHEDULER_cancel (sched,
613 peer->hello_delay_task);
614 peer->hello_delay_task = GNUNET_SCHEDULER_NO_TASK;
615 }
616 peer->hello_delay_task
617 = GNUNET_SCHEDULER_add_now (sched,
618 &schedule_next_hello,
619 peer);
620}
621
622
623/**
461 * Method called whenever a peer connects. 624 * Method called whenever a peer connects.
462 * 625 *
463 * @param cls closure 626 * @param cls closure
464 * @param peer peer identity this notification is about 627 * @param peer peer identity this notification is about
465 */ 628 */
466static void connect_notify (void *cls, 629static void
467 const struct 630connect_notify (void *cls,
468 GNUNET_PeerIdentity * peer) 631 const struct
632 GNUNET_PeerIdentity * peer)
469{ 633{
470 struct PeerList *pos; 634 struct PeerList *pos;
471 635
@@ -473,36 +637,34 @@ static void connect_notify (void *cls,
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Core told us that we are connecting to `%s'\n", 638 "Core told us that we are connecting to `%s'\n",
475 GNUNET_i2s (peer)); 639 GNUNET_i2s (peer));
476#endif 640#endif
477 connection_count++; 641 connection_count++;
478 pos = friends; 642 pos = find_peer (peer);
479 while (pos != NULL) 643 if (pos == NULL)
480 { 644 {
481 if ( (GNUNET_YES == pos->is_friend) && 645 pos = make_peer (peer, NULL, GNUNET_NO);
482 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) ) 646 if (GNUNET_OK != is_connection_allowed (pos))
483 { 647 {
484 GNUNET_assert (GNUNET_NO == pos->is_connected); 648 GNUNET_assert (pos->is_friend == GNUNET_NO);
485 pos->is_connected = GNUNET_YES; 649 pos->is_connected = GNUNET_YES;
486 pos->blacklisted_until.value = 0; /* remove blacklisting */ 650#if DEBUG_TOPOLOGY
487 friend_count++; 651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652 "Connection to `%s' is forbidden, forcing disconnect!\n",
653 GNUNET_i2s (peer));
654#endif
655 force_disconnect (&pos->id);
488 return; 656 return;
489 } 657 }
490 pos = pos->next;
491 } 658 }
492 pos = GNUNET_malloc (sizeof(struct PeerList)); 659 else
493 pos->id = *peer;
494 pos->is_connected = GNUNET_YES;
495 pos->next = friends;
496 friends = pos;
497 if (GNUNET_OK != is_connection_allowed (peer))
498 { 660 {
499#if DEBUG_TOPOLOGY 661 GNUNET_assert (GNUNET_NO == pos->is_connected);
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 662 pos->blacklisted_until.value = 0; /* remove blacklisting */
501 "Connection to `%s' is forbidden, forcing disconnect!\n",
502 GNUNET_i2s (peer));
503#endif
504 force_disconnect (peer);
505 } 663 }
664 pos->is_connected = GNUNET_YES;
665 if (pos->is_friend)
666 friend_count++;
667 reschedule_hellos (pos);
506} 668}
507 669
508 670
@@ -514,12 +676,12 @@ drop_non_friends ()
514{ 676{
515 struct PeerList *pos; 677 struct PeerList *pos;
516 678
517 pos = friends; 679 pos = peers;
518 while (pos != NULL) 680 while (pos != NULL)
519 { 681 {
520 if (GNUNET_NO == pos->is_friend) 682 if ( (GNUNET_NO == pos->is_friend) &&
683 (GNUNET_YES == pos->is_connected) )
521 { 684 {
522 GNUNET_assert (GNUNET_YES == pos->is_connected);
523#if DEBUG_TOPOLOGY 685#if DEBUG_TOPOLOGY
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Connection to `%s' is not from a friend, forcing disconnect!\n", 687 "Connection to `%s' is not from a friend, forcing disconnect!\n",
@@ -533,106 +695,73 @@ drop_non_friends ()
533 695
534 696
535/** 697/**
698 * Try to add more peers to our connection set.
699 */
700static void
701try_add_peers ()
702{
703 struct PeerList *pos;
704
705 pos = peers;
706 while (pos != NULL)
707 {
708 if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
709 ( (GNUNET_YES == pos->is_friend) ||
710 (friend_count >= minimum_friend_count) ) &&
711 (GNUNET_YES != pos->is_connected) )
712 attempt_connect (pos);
713 pos = pos->next;
714 }
715}
716
717
718/**
536 * Method called whenever a peer disconnects. 719 * Method called whenever a peer disconnects.
537 * 720 *
538 * @param cls closure 721 * @param cls closure
539 * @param peer peer identity this notification is about 722 * @param peer peer identity this notification is about
540 */ 723 */
541static void disconnect_notify (void *cls, 724static void
542 const struct 725disconnect_notify (void *cls,
543 GNUNET_PeerIdentity * peer) 726 const struct
727 GNUNET_PeerIdentity * peer)
544{ 728{
545 struct PeerList *pos; 729 struct PeerList *pos;
546 struct PeerList *prev;
547 730
548#if DEBUG_TOPOLOGY 731#if DEBUG_TOPOLOGY
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Core told us that we disconnected from `%s'\n", 733 "Core told us that we disconnected from `%s'\n",
551 GNUNET_i2s (peer)); 734 GNUNET_i2s (peer));
552#endif 735#endif
736 pos = find_peer (peer);
737 if (pos == NULL)
738 {
739 GNUNET_break (0);
740 return;
741 }
742 if (pos->is_connected != GNUNET_YES)
743 {
744 GNUNET_break (0);
745 return;
746 }
553 connection_count--; 747 connection_count--;
554 pos = friends; 748 if (pos->is_friend)
555 prev = NULL; 749 friend_count--;
556 while (pos != NULL) 750 if ( (connection_count < target_connection_count) ||
751 (friend_count < minimum_friend_count) )
752 try_add_peers ();
753 if (friend_count < minimum_friend_count)
557 { 754 {
558 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) 755 /* disconnect from all non-friends */
559 {
560 GNUNET_assert (GNUNET_YES == pos->is_connected);
561 pos->is_connected = GNUNET_NO;
562 if (GNUNET_YES == pos->is_friend)
563 {
564 friend_count--;
565 if (friend_count < minimum_friend_count)
566 {
567 /* disconnect from all non-friends */
568#if DEBUG_TOPOLOGY 756#if DEBUG_TOPOLOGY
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570 "Not enough friendly connections, dropping all non-friend connections\n"); 758 "Not enough friendly connections, dropping all non-friend connections\n");
571#endif 759#endif
572 drop_non_friends (); 760 drop_non_friends ();
573 attempt_connect (peer, pos);
574 }
575 }
576 else
577 {
578 /* free entry */
579 if (prev == NULL)
580 friends = pos->next;
581 else
582 prev->next = pos->next;
583 GNUNET_free (pos);
584 }
585 return;
586 }
587 prev = pos;
588 pos = pos->next;
589 } 761 }
590 GNUNET_break (0);
591}
592
593
594/**
595 * Find more peers that we should connect to and ask the
596 * core to establish connections.
597 */
598static void
599find_more_peers (void *cls,
600 const struct GNUNET_SCHEDULER_TaskContext *tc);
601
602
603/**
604 * Determine when we should try again to find more peers and
605 * schedule the task.
606 */
607static void
608schedule_peer_search ()
609{
610 struct GNUNET_TIME_Relative delay;
611
612 /* Typically, we try again every 15 minutes; the minimum period is
613 15s; if we are above the connection target, we reduce re-trying
614 by the square of how much we are above; so for example, with 200%
615 of the connection target we would only look for more peers once
616 every hour (after all, we're quite busy processing twice as many
617 connections as we intended to have); similarly, if we are at only
618 25% of our connectivity goal, we will try 16x as hard to connect
619 (so roughly once a minute, plus the 15s minimum delay */
620 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
621 15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count);
622#if DEBUG_TOPOLOGY
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Will try to find more peers in %llums\n",
625 (unsigned long long) delay.value);
626#endif
627 GNUNET_SCHEDULER_add_delayed (sched,
628 delay,
629 &find_more_peers,
630 NULL);
631} 762}
632 763
633 764
634
635
636/** 765/**
637 * Iterator called on each address. 766 * Iterator called on each address.
638 * 767 *
@@ -656,15 +785,16 @@ address_iterator (void *cls,
656 785
657 786
658/** 787/**
659 * We've gotten a HELLO from another peer. 788 * We've gotten a HELLO from another peer. Consider it for
660 * Consider it for advertising. 789 * advertising.
661 */ 790 */
662static void 791static void
663consider_for_advertising (const struct GNUNET_HELLO_Message *hello) 792consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
664{ 793{
665 int have_address; 794 int have_address;
666 struct GNUNET_PeerIdentity pid; 795 struct GNUNET_PeerIdentity pid;
667 struct HelloList *pos; 796 struct PeerList *peer;
797 struct PeerList *pos;
668 uint16_t size; 798 uint16_t size;
669 799
670 have_address = GNUNET_NO; 800 have_address = GNUNET_NO;
@@ -675,15 +805,11 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
675 if (GNUNET_NO == have_address) 805 if (GNUNET_NO == have_address)
676 return; /* no point in advertising this one... */ 806 return; /* no point in advertising this one... */
677 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid)); 807 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
678 pos = hellos; 808 peer = find_peer (&pid);
679 while (pos != NULL) 809 if (peer == NULL)
680 { 810 peer = make_peer (&pid, hello, GNUNET_NO);
681 if (0 == memcmp (&pos->id, 811 // FIXME: check if 'hello' is any different from peer->hello?
682 &pid, 812 GNUNET_free_non_null (peer->hello);
683 sizeof(struct GNUNET_PeerIdentity)))
684 return; /* duplicate, at least "mostly" */
685 pos = pos->next;
686 }
687#if DEBUG_TOPOLOGY 813#if DEBUG_TOPOLOGY
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Found `%s' from peer `%s' for advertising\n", 815 "Found `%s' from peer `%s' for advertising\n",
@@ -691,29 +817,30 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
691 GNUNET_i2s (&pid)); 817 GNUNET_i2s (&pid));
692#endif 818#endif
693 size = GNUNET_HELLO_size (hello); 819 size = GNUNET_HELLO_size (hello);
694 pos = GNUNET_malloc (sizeof(struct HelloList) + size); 820 peer->hello = GNUNET_malloc (size);
695 pos->msg = (struct GNUNET_HELLO_Message*) &pos[1]; 821 memcpy (peer->hello, hello, size);
696 memcpy (&pos->msg, hello, size); 822 if (peer->filter != NULL)
697 pos->id = pid; 823 GNUNET_CONTAINER_bloomfilter_free (peer->filter);
698 pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); 824 setup_filter (peer);
699 /* 2^{-5} chance of not sending a HELLO to a peer is 825 /* since we have a new HELLO to pick from, re-schedule all
700 acceptably small (if the filter is 50% full); 826 HELLO requests that are not bound by the HELLO send rate! */
701 64 bytes of memory are small compared to the rest 827 pos = peers;
702 of the data structure and would only really become 828 while (NULL != pos)
703 "useless" once a HELLO has been passed on to ~100 829 {
704 other peers, which is likely more than enough in 830 if (pos != peer)
705 any case; hence 64, 5 as bloomfilter parameters. */ 831 {
706 pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5); 832 if ( (pos->is_connected) &&
707 /* never send a peer its own HELLO */ 833 (GNUNET_TIME_absolute_get_remaining (pos->next_hello_allowed).value <= HELLO_ADVERTISEMENT_MIN_FREQUENCY.value) )
708 GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey); 834 reschedule_hellos (pos);
709 pos->next = hellos; 835 }
710 hellos = pos; 836 pos = pos->next;
837 }
711} 838}
712 839
713 840
714/** 841/**
715 * Peerinfo calls this function to let us know about a 842 * Peerinfo calls this function to let us know about a possible peer
716 * possible peer that we might want to connect to. 843 * that we might want to connect to.
717 */ 844 */
718static void 845static void
719process_peer (void *cls, 846process_peer (void *cls,
@@ -723,102 +850,59 @@ process_peer (void *cls,
723{ 850{
724 struct PeerList *pos; 851 struct PeerList *pos;
725 852
726 if (peer == NULL) 853 GNUNET_assert (peer != NULL);
854 if (0 == memcmp (&my_identity,
855 peer, sizeof (struct GNUNET_PeerIdentity)))
856 return; /* that's me! */
857 if (hello == NULL)
727 { 858 {
728 pitr_more = NULL; 859 /* free existing HELLO, if any */
729 /* last call, schedule 'find_more_peers' again... */ 860 pos = find_peer (peer);
730 if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 861 if (NULL != (pos = find_peer (peer)))
731 { 862 {
732#if DEBUG_TOPOLOGY 863 GNUNET_free_non_null (pos->hello);
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 864 pos->hello = NULL;
734 "Received shutdown request, stopping search for peers to connect to.\n"); 865 if (pos->filter != NULL)
735#endif 866 {
736 return; 867 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
868 pos->filter = NULL;
869 }
870 if ( (! pos->is_connected) &&
871 (! pos->is_friend) &&
872 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
873 free_peer (pos);
737 } 874 }
738 schedule_peer_search ();
739 return;
740 }
741 if (hello == NULL)
742 {
743 /* no HELLO known; can not connect, ignore! */
744 return; 875 return;
745 } 876 }
746 if (0 == memcmp (&my_identity,
747 peer, sizeof (struct GNUNET_PeerIdentity)))
748 return; /* that's me! */
749
750 consider_for_advertising (hello); 877 consider_for_advertising (hello);
878 pos = find_peer (peer);
751#if DEBUG_TOPOLOGY 879#if DEBUG_TOPOLOGY
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "Considering connecting to peer `%s'\n", 881 "Considering connecting to peer `%s'\n",
754 GNUNET_i2s (peer)); 882 GNUNET_i2s (peer));
755#endif 883#endif
756 pos = friends; 884 if (GNUNET_YES == pos->is_connected)
757 while (pos != NULL)
758 {
759 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
760 {
761 if (GNUNET_YES == pos->is_connected)
762 {
763#if DEBUG_TOPOLOGY
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
765 "Already connected to peer `%s'\n",
766 GNUNET_i2s (peer));
767#endif
768 return;
769 }
770 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
771 {
772#if DEBUG_TOPOLOGY
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774 "Already tried peer `%s' recently\n",
775 GNUNET_i2s (peer));
776#endif
777 return; /* peer still blacklisted */
778 }
779 if (GNUNET_YES == pos->is_friend)
780 {
781 attempt_connect (peer, pos);
782 return;
783 }
784 }
785 pos = pos->next;
786 }
787 if ( (GNUNET_YES == friends_only) ||
788 (friend_count < minimum_friend_count) )
789 { 885 {
790#if DEBUG_TOPOLOGY 886#if DEBUG_TOPOLOGY
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 "Peer `%s' is not a friend, and we currently only connect to friends\n", 888 "Already connected to peer `%s'\n",
793 GNUNET_i2s (peer)); 889 GNUNET_i2s (peer));
794#endif 890#endif
795 return; 891 return;
796 } 892 }
797 attempt_connect (peer, NULL); 893 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
798} 894 {
799
800
801/**
802 * Try to add more friends to our connection set.
803 */
804static void
805try_add_friends ()
806{
807 struct PeerList *pos;
808
809#if DEBUG_TOPOLOGY 895#if DEBUG_TOPOLOGY
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Considering all of our friends for new connections\n"); 897 "Already tried peer `%s' recently\n",
898 GNUNET_i2s (peer));
812#endif 899#endif
813 pos = friends; 900 return; /* peer still blacklisted */
814 while (pos != NULL)
815 {
816 if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
817 (GNUNET_YES == pos->is_friend) &&
818 (GNUNET_YES != pos->is_connected) )
819 attempt_connect (&pos->id, pos);
820 pos = pos->next;
821 } 901 }
902 if ( (GNUNET_YES == pos->is_friend) ||
903 (GNUNET_YES != friends_only) ||
904 (friend_count >= minimum_friend_count) )
905 attempt_connect (pos);
822} 906}
823 907
824 908
@@ -827,82 +911,27 @@ try_add_friends ()
827 * where the blacklisting has expired. 911 * where the blacklisting has expired.
828 */ 912 */
829static void 913static void
830discard_old_blacklist_entries () 914discard_old_blacklist_entries (void *cls,
915 const struct GNUNET_SCHEDULER_TaskContext *tc)
831{ 916{
832 struct PeerList *pos; 917 struct PeerList *pos;
833 struct PeerList *next; 918 struct PeerList *next;
834 struct PeerList *prev;
835 919
836 next = friends; 920 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
837 prev = NULL; 921 return;
922 next = peers;
838 while (NULL != (pos = next)) 923 while (NULL != (pos = next))
839 { 924 {
840 next = pos->next; 925 next = pos->next;
841 if ( (GNUNET_NO == pos->is_friend) && 926 if ( (GNUNET_NO == pos->is_friend) &&
842 (GNUNET_NO == pos->is_connected) && 927 (GNUNET_NO == pos->is_connected) &&
843 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) ) 928 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
844 { 929 free_peer (pos);
845 /* delete 'pos' from list */
846#if DEBUG_TOPOLOGY
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848 "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n",
849 GNUNET_i2s (&pos->id));
850#endif
851 if (prev == NULL)
852 friends = next;
853 else
854 prev->next = next;
855 GNUNET_free (pos);
856 }
857 else
858 {
859 prev = pos;
860 }
861 }
862}
863
864
865/**
866 * Find more peers that we should connect to and ask the
867 * core to establish connections.
868 */
869static void
870find_more_peers (void *cls,
871 const struct GNUNET_SCHEDULER_TaskContext *tc)
872{
873 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
874 {
875#if DEBUG_TOPOLOGY
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
877 "Received shutdown request, stopping search for peers to connect to.\n");
878#endif
879 return;
880 }
881 discard_old_blacklist_entries ();
882 if (connection_count <= target_connection_count)
883 {
884 schedule_peer_search ();
885 return;
886 } 930 }
887 if ( (GNUNET_YES == friends_only) || 931 GNUNET_SCHEDULER_add_delayed (sched,
888 (friend_count < minimum_friend_count) ) 932 BLACKLIST_AFTER_ATTEMPT,
889 { 933 &discard_old_blacklist_entries,
890 try_add_friends (); 934 NULL);
891 schedule_peer_search ();
892 return;
893 }
894#if DEBUG_TOPOLOGY
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
896 "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
897 connection_count,
898 target_connection_count,
899 friend_count);
900#endif
901 pitr_more = GNUNET_PEERINFO_iterate (cfg,
902 sched,
903 NULL,
904 0, GNUNET_TIME_UNIT_FOREVER_REL,
905 &process_peer, NULL);
906} 935}
907 936
908 937
@@ -938,23 +967,14 @@ core_init (void *cls,
938 "I am peer `%s'\n", 967 "I am peer `%s'\n",
939 GNUNET_i2s (my_id)); 968 GNUNET_i2s (my_id));
940#endif 969#endif
941 if (autoconnect) 970 GNUNET_SCHEDULER_add_delayed (sched,
942 GNUNET_SCHEDULER_add_delayed (sched, 971 BLACKLIST_AFTER_ATTEMPT,
943 GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */, 972 &discard_old_blacklist_entries,
944 &find_more_peers, 973 NULL);
945 NULL);
946} 974}
947 975
948 976
949/** 977/**
950 * gnunet-daemon-topology command line options.
951 */
952static struct GNUNET_GETOPT_CommandLineOption options[] = {
953 GNUNET_GETOPT_OPTION_END
954};
955
956
957/**
958 * Read the friends file. 978 * Read the friends file.
959 */ 979 */
960static void 980static void
@@ -963,7 +983,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
963 char *fn; 983 char *fn;
964 char *data; 984 char *data;
965 size_t pos; 985 size_t pos;
966 GNUNET_HashCode hc; 986 struct GNUNET_PeerIdentity pid;
967 struct stat frstat; 987 struct stat frstat;
968 struct GNUNET_CRYPTO_HashAsciiEncoded enc; 988 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
969 unsigned int entries_found; 989 unsigned int entries_found;
@@ -1031,7 +1051,7 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1031 continue; 1051 continue;
1032 } 1052 }
1033 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; 1053 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1034 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc)) 1054 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1035 { 1055 {
1036 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1056 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1037 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), 1057 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
@@ -1041,11 +1061,9 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1041 else 1061 else
1042 { 1062 {
1043 entries_found++; 1063 entries_found++;
1044 fl = GNUNET_malloc (sizeof(struct PeerList)); 1064 fl = make_peer (&pid,
1045 fl->is_friend = GNUNET_YES; 1065 NULL,
1046 fl->id.hashPubKey = hc; 1066 GNUNET_YES);
1047 fl->next = friends;
1048 friends = fl;
1049#if DEBUG_TOPOLOGY 1067#if DEBUG_TOPOLOGY
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Found friend `%s' in configuration\n", 1069 "Found friend `%s' in configuration\n",
@@ -1104,144 +1122,73 @@ handle_encrypted_hello (void *cls,
1104 1122
1105 1123
1106/** 1124/**
1107 * Peerinfo calls this function to let us know about a
1108 * possible peer that we might want to connect to.
1109 *
1110 * @param cls unused
1111 * @param peer NULL for the end of the list, otherwise a peer identity
1112 * @param hello a HELLO for a peer, or NULL
1113 * @param trust how much do we trust the given peer?
1114 */
1115static void
1116gather_hello_callback (void *cls,
1117 const struct GNUNET_PeerIdentity *peer,
1118 const struct GNUNET_HELLO_Message *hello,
1119 uint32_t trust)
1120{
1121 if (peer == NULL)
1122 {
1123 pitr = NULL;
1124 return;
1125 }
1126#if DEBUG_TOPOLOGY
1127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1128 "Received `%s' for peer `%s'",
1129 "HELLO",
1130 GNUNET_i2s (peer));
1131#endif
1132 if (hello != NULL)
1133 consider_for_advertising (hello);
1134}
1135
1136
1137// FIXME: this no longer works (no solicitation!)
1138/**
1139 * Function to fill send buffer with HELLO. 1125 * Function to fill send buffer with HELLO.
1140 * 1126 *
1141 * @param cls unused 1127 * @param cls 'struct PeerList' of the target peer
1142 * @param receiver the receiver of the message 1128 * @param size number of bytes available in buf
1143 * @param position is the reference to the 1129 * @param buf where the callee should write the message
1144 * first unused position in the buffer where GNUnet is building 1130 * @return number of bytes written to buf
1145 * the message
1146 * @param padding is the number of bytes left in that buffer.
1147 * @return the number of bytes written to
1148 * that buffer (must be a positive number).
1149 */ 1131 */
1150/* static */ unsigned int 1132static size_t
1151hello_advertising (void *cls, 1133hello_advertising_ready (void *cls,
1152 const struct GNUNET_PeerIdentity * 1134 size_t size,
1153 receiver, 1135 void *buf)
1154 void *position,
1155 size_t padding)
1156{ 1136{
1157 struct PeerList *pl; 1137 struct PeerList *pl = cls;
1158 struct HelloList *pos; 1138 struct PeerList *pos;
1159 struct HelloList *prev; 1139 struct PeerList *next;
1160 struct HelloList *next; 1140 uint16_t want;
1161 uint16_t size; 1141 size_t hs;
1162 1142
1143 pl->hello_req = NULL;
1163#if DEBUG_TOPOLOGY 1144#if DEBUG_TOPOLOGY
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 "Data solicited for `%s', considering sending `%s's", 1146 "Data solicited for `%s', considering sending `%s'",
1166 GNUNET_i2s (receiver), 1147 GNUNET_i2s (&pl->id),
1167 "HELLO"); 1148 "HELLO");
1168#endif 1149#endif
1169 pl = friends;
1170 while (pl != NULL)
1171 {
1172 if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1173 break;
1174 pl = pl->next;
1175 }
1176 if (pl == NULL)
1177 {
1178 GNUNET_break (0);
1179 return 0;
1180 }
1181 /* find applicable HELLOs */ 1150 /* find applicable HELLOs */
1182 prev = NULL; 1151 next = peers;
1183 next = hellos;
1184 while (NULL != (pos = next)) 1152 while (NULL != (pos = next))
1185 { 1153 {
1186 next = pos->next; 1154 next = pos->next;
1187 if (GNUNET_NO == 1155 if (pos->hello == NULL)
1188 GNUNET_CONTAINER_bloomfilter_test (pos->filter, 1156 continue;
1189 &receiver->hashPubKey)) 1157 if (0 == GNUNET_TIME_absolute_get_remaining (pos->filter_expiration).value)
1190 break;
1191 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1192 { 1158 {
1193 /* time to discard... */ 1159 /* time to discard... */
1194 if (prev != NULL)
1195 prev->next = next;
1196 else
1197 hellos = next;
1198 GNUNET_CONTAINER_bloomfilter_free (pos->filter); 1160 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1199 GNUNET_free (pos); 1161 setup_filter (pos);
1200 }
1201 else
1202 {
1203 prev = pos;
1204 } 1162 }
1163 if (GNUNET_NO ==
1164 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1165 &pl->id.hashPubKey))
1166 break;
1205 } 1167 }
1168 want = 0;
1206 if (pos != NULL) 1169 if (pos != NULL)
1207 { 1170 {
1208 size = GNUNET_HELLO_size (pos->msg); 1171 hs = GNUNET_HELLO_size (pos->hello);
1209 if (size < padding) 1172 if (hs < size)
1210 { 1173 {
1211 memcpy (position, pos->msg, size); 1174 want = hs;
1175 memcpy (buf, pos->hello, want);
1212 GNUNET_CONTAINER_bloomfilter_add (pos->filter, 1176 GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1213 &receiver->hashPubKey); 1177 &pl->id.hashPubKey);
1214 } 1178 pl->next_hello_allowed = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
1215 else
1216 {
1217 size = 0;
1218 }
1219#if DEBUG_TOPOLOGY 1179#if DEBUG_TOPOLOGY
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Sending %u bytes of `%s's", 1181 "Sending %u bytes of `%s's",
1222 (unsigned int) size, 1182 (unsigned int) want,
1223 "HELLO"); 1183 "HELLO");
1224#endif
1225 return size;
1226 }
1227 if ( (NULL == pitr) &&
1228 (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1229 MIN_HELLO_GATHER_DELAY.value) )
1230 {
1231#if DEBUG_TOPOLOGY
1232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1233 "Have no `%s's, trying to get some from `%s' for next time",
1234 "HELLO",
1235 "PEERINFO");
1236#endif 1184#endif
1237 last_hello_gather_time = GNUNET_TIME_absolute_get(); 1185 }
1238 pitr = GNUNET_PEERINFO_iterate (cfg,
1239 sched,
1240 NULL,
1241 0, GNUNET_TIME_UNIT_FOREVER_REL,
1242 &gather_hello_callback, NULL);
1243 } 1186 }
1244 return 0; 1187 pl->hello_delay_task
1188 = GNUNET_SCHEDULER_add_now (sched,
1189 &schedule_next_hello,
1190 pl);
1191 return want;
1245} 1192}
1246 1193
1247 1194
@@ -1252,7 +1199,6 @@ hello_advertising (void *cls,
1252static void 1199static void
1253cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 1200cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1254{ 1201{
1255 struct PeerList *pl;
1256 struct DisconnectList *dl; 1202 struct DisconnectList *dl;
1257 1203
1258 if (NULL != peerinfo_notify) 1204 if (NULL != peerinfo_notify)
@@ -1260,28 +1206,15 @@ cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1260 GNUNET_PEERINFO_notify_cancel (peerinfo_notify); 1206 GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
1261 peerinfo_notify = NULL; 1207 peerinfo_notify = NULL;
1262 } 1208 }
1263 if (NULL != pitr)
1264 {
1265 GNUNET_PEERINFO_iterate_cancel (pitr);
1266 pitr = NULL;
1267 }
1268 if (NULL != pitr_more)
1269 {
1270 GNUNET_PEERINFO_iterate_cancel (pitr_more);
1271 pitr_more = NULL;
1272 }
1273 GNUNET_TRANSPORT_disconnect (transport); 1209 GNUNET_TRANSPORT_disconnect (transport);
1274 transport = NULL; 1210 transport = NULL;
1211 while (NULL != peers)
1212 free_peer (peers);
1275 if (handle != NULL) 1213 if (handle != NULL)
1276 { 1214 {
1277 GNUNET_CORE_disconnect (handle); 1215 GNUNET_CORE_disconnect (handle);
1278 handle = NULL; 1216 handle = NULL;
1279 } 1217 }
1280 while (NULL != (pl = friends))
1281 {
1282 friends = pl->next;
1283 GNUNET_free (pl);
1284 }
1285 while (NULL != (dl = disconnect_head)) 1218 while (NULL != (dl = disconnect_head))
1286 { 1219 {
1287 GNUNET_CONTAINER_DLL_remove (disconnect_head, 1220 GNUNET_CONTAINER_DLL_remove (disconnect_head,
@@ -1391,6 +1324,14 @@ run (void *cls,
1391 1324
1392 1325
1393/** 1326/**
1327 * gnunet-daemon-topology command line options.
1328 */
1329static struct GNUNET_GETOPT_CommandLineOption options[] = {
1330 GNUNET_GETOPT_OPTION_END
1331};
1332
1333
1334/**
1394 * The main function for the topology daemon. 1335 * The main function for the topology daemon.
1395 * 1336 *
1396 * @param argc number of arguments from the command line 1337 * @param argc number of arguments from the command line
diff --git a/src/topology/test_gnunet_service_topology_data.conf b/src/topology/test_gnunet_service_topology_data.conf
index 77c40da71..a4a832e56 100644
--- a/src/topology/test_gnunet_service_topology_data.conf
+++ b/src/topology/test_gnunet_service_topology_data.conf
@@ -29,6 +29,7 @@ PORT = 2670
29 29
30[topology] 30[topology]
31DEBUG = YES 31DEBUG = YES
32PREFIX = valgrind --tool=memcheck
32 33
33[testing] 34[testing]
34WEAKRANDOM = YES 35WEAKRANDOM = YES