2 This file is part of GNUnet.
3 (C) 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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.
22 * @file topology/gnunet-daemon-topology.c
23 * @brief code for maintaining the mesh topology
24 * @author Christian Grothoff
29 #include "gnunet_core_service.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_util_lib.h"
36 #define DEBUG_TOPOLOGY GNUNET_NO
39 * For how long do we blacklist a peer after a failed
42 #define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS
45 * For how long do we blacklist a friend after a failed
48 #define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
51 * How frequently are we allowed to ask PEERINFO for more
52 * HELLO's to advertise (at most)?
54 #define MIN_HELLO_GATHER_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 27)
57 * 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
61 #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
65 * List of neighbours, friends and blacklisted peers.
71 * This is a linked list.
73 struct PeerList *next;
76 * Is this peer listed here because he is a friend?
81 * Are we connected to this peer right now?
86 * Until what time should we not try to connect again
89 struct GNUNET_TIME_Absolute blacklisted_until;
92 * Last time we transmitted a HELLO to this peer?
94 struct GNUNET_TIME_Absolute last_hello_sent;
99 struct GNUNET_PeerIdentity id;
105 * List of HELLOs we may consider for advertising.
110 * This is a linked list.
112 struct HelloList *next;
115 * Pointer to the HELLO message. Memory allocated as part
116 * of the "struct HelloList" --- do not free!
118 struct GNUNET_HELLO_Message *msg;
121 * Bloom filter used to mark which peers already got
124 struct GNUNET_CONTAINER_BloomFilter *filter;
127 * What peer is this HELLO for?
129 struct GNUNET_PeerIdentity id;
132 * When should we remove this entry from the linked list (either
133 * resetting the filter or possibly eliminating it for good because
134 * we no longer consider the peer to be participating in the
137 struct GNUNET_TIME_Absolute expiration;
142 * Our peerinfo notification context. We use notification
143 * to instantly learn about new peers as they are discovered
144 * as well as periodic iteration to try peers again after
147 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
150 * Linked list of HELLOs for advertising.
152 static struct HelloList *hellos;
157 static struct GNUNET_SCHEDULER_Handle * sched;
162 static const struct GNUNET_CONFIGURATION_Handle * cfg;
165 * Handle to the core API.
167 static struct GNUNET_CORE_Handle *handle;
170 * Handle to the transport API.
172 static struct GNUNET_TRANSPORT_Handle *transport;
175 * Identity of this peer.
177 static struct GNUNET_PeerIdentity my_identity;
180 * Linked list of all of our friends and all of our current
183 static struct PeerList *friends;
186 * Timestamp from the last time we tried to gather HELLOs.
188 static struct GNUNET_TIME_Absolute last_hello_gather_time;
191 * Flag to disallow non-friend connections (pure F2F mode).
193 static int friends_only;
196 * Minimum number of friends to have in the
197 * connection set before we allow non-friends.
199 static unsigned int minimum_friend_count;
202 * Number of peers (friends and others) that we are currently connected to.
204 static unsigned int connection_count;
207 * Target number of connections.
209 static unsigned int target_connection_count;
212 * Number of friends that we are currently connected to.
214 static unsigned int friend_count;
217 * Should the topology daemon try to establish connections?
219 static int autoconnect;
222 * Are we currently having a request pending with
223 * PEERINFO asking for HELLOs for advertising?
225 static int hello_gathering_active;
230 * Force a disconnect from the specified peer.
233 force_disconnect (const struct GNUNET_PeerIdentity *peer)
235 GNUNET_CORE_peer_configure (handle,
237 GNUNET_TIME_UNIT_FOREVER_REL,
247 * Function called by core when our attempt to connect
248 * succeeded. Does nothing.
251 ready_callback (void *cls,
252 size_t size, void *buf)
254 struct GNUNET_MessageHeader hdr;
258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259 "Core told us that our attempt to connect failed.\n");
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "Sending dummy message to establish connection.\n");
267 hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
268 hdr.type = htons (GNUNET_MESSAGE_TYPE_TOPOLOGY_DUMMY);
269 memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
270 return sizeof (struct GNUNET_MessageHeader);
275 * Try to connect to the specified peer.
277 * @param peer who we should try to connect to
278 * @param pos entry in our friend list; NULL if not in friend list yet
281 attempt_connect (const struct GNUNET_PeerIdentity *peer,
282 struct PeerList *pos)
289 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
296 pos = GNUNET_malloc (sizeof(struct PeerList));
301 if (GNUNET_YES == pos->is_friend)
302 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
304 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "Asking core to connect to `%s'\n",
310 GNUNET_CORE_notify_transmit_ready (handle,
312 GNUNET_TIME_UNIT_MINUTES,
314 sizeof(struct GNUNET_MessageHeader),
321 * Is this peer one of our friends?
324 is_friend (const struct GNUNET_PeerIdentity * peer)
326 struct PeerList *pos;
331 if ( (GNUNET_YES == pos->is_friend) &&
332 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336 "Determined that `%s' is a friend\n",
348 * Check if an additional connection from the given peer is allowed.
351 is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
353 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
354 return GNUNET_SYSERR; /* disallow connections to self */
355 if (is_friend (peer))
357 if (GNUNET_YES == friends_only)
360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361 "Determined that `%s' is not allowed to connect (not a friend)\n",
364 return GNUNET_SYSERR;
366 if (friend_count >= minimum_friend_count)
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
373 return GNUNET_SYSERR;
378 * Method called whenever a peer connects.
381 * @param peer peer identity this notification is about
383 static void connect_notify (void *cls,
385 GNUNET_PeerIdentity * peer)
387 struct PeerList *pos;
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Core told us that we are connecting to `%s'\n",
398 if ( (GNUNET_YES == pos->is_friend) &&
399 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
401 GNUNET_assert (GNUNET_NO == pos->is_connected);
402 pos->is_connected = GNUNET_YES;
403 pos->blacklisted_until.value = 0; /* remove blacklisting */
409 pos = GNUNET_malloc (sizeof(struct PeerList));
411 pos->is_connected = GNUNET_YES;
414 if (GNUNET_OK != is_connection_allowed (peer))
417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
418 "Connection to `%s' is forbidden, forcing disconnect!\n",
421 force_disconnect (peer);
427 * Disconnect from all non-friends (we're below quota).
432 struct PeerList *pos;
437 if (GNUNET_NO == pos->is_friend)
439 GNUNET_assert (GNUNET_YES == pos->is_connected);
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Connection to `%s' is not from a friend, forcing disconnect!\n",
443 GNUNET_i2s (&pos->id));
445 force_disconnect (&pos->id);
453 * Method called whenever a peer disconnects.
456 * @param peer peer identity this notification is about
458 static void disconnect_notify (void *cls,
460 GNUNET_PeerIdentity * peer)
462 struct PeerList *pos;
463 struct PeerList *prev;
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
467 "Core told us that we disconnected from `%s'\n",
475 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
477 GNUNET_assert (GNUNET_YES == pos->is_connected);
478 pos->is_connected = GNUNET_NO;
479 if (GNUNET_YES == pos->is_friend)
482 if (friend_count < minimum_friend_count)
484 /* disconnect from all non-friends */
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487 "Not enough friendly connections, dropping all non-friend connections\n");
490 attempt_connect (peer, pos);
499 prev->next = pos->next;
512 * Find more peers that we should connect to and ask the
513 * core to establish connections.
516 find_more_peers (void *cls,
517 const struct GNUNET_SCHEDULER_TaskContext *tc);
521 * Determine when we should try again to find more peers and
525 schedule_peer_search ()
527 struct GNUNET_TIME_Relative delay;
529 /* Typically, we try again every 15 minutes; the minimum period is
530 15s; if we are above the connection target, we reduce re-trying
531 by the square of how much we are above; so for example, with 200%
532 of the connection target we would only look for more peers once
533 every hour (after all, we're quite busy processing twice as many
534 connections as we intended to have); similarly, if we are at only
535 25% of our connectivity goal, we will try 16x as hard to connect
536 (so roughly once a minute, plus the 15s minimum delay */
537 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
538 15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count);
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "Will try to find more peers in %llums\n",
542 (unsigned long long) delay.value);
544 GNUNET_SCHEDULER_add_delayed (sched,
554 * Iterator called on each address.
556 * @param cls flag that we will set if we see any addresses
557 * @param tname name of the transport
558 * @param expiration when will the given address expire
559 * @param addr the address of the peer
560 * @param addrlen number of bytes in addr
561 * @return GNUNET_SYSERR always, to terminate iteration
564 address_iterator (void *cls,
566 struct GNUNET_TIME_Absolute expiration,
567 const void *addr, size_t addrlen)
571 return GNUNET_SYSERR;
576 * We've gotten a HELLO from another peer.
577 * Consider it for advertising.
580 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
583 struct GNUNET_PeerIdentity pid;
584 struct HelloList *pos;
587 have_address = GNUNET_NO;
588 GNUNET_HELLO_iterate_addresses (hello,
592 if (GNUNET_NO == have_address)
593 return; /* no point in advertising this one... */
594 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
598 if (0 == memcmp (&pos->id,
600 sizeof(struct GNUNET_PeerIdentity)))
601 return; /* duplicate, at least "mostly" */
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Found `%s' from peer `%s' for advertising\n",
610 size = GNUNET_HELLO_size (hello);
611 pos = GNUNET_malloc (sizeof(struct HelloList) + size);
612 pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
613 memcpy (&pos->msg, hello, size);
615 pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
616 /* 2^{-5} chance of not sending a HELLO to a peer is
617 acceptably small (if the filter is 50% full);
618 64 bytes of memory are small compared to the rest
619 of the data structure and would only really become
620 "useless" once a HELLO has been passed on to ~100
621 other peers, which is likely more than enough in
622 any case; hence 64, 5 as bloomfilter parameters. */
623 pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
624 /* never send a peer its own HELLO */
625 GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
632 * Peerinfo calls this function to let us know about a
633 * possible peer that we might want to connect to.
636 process_peer (void *cls,
637 const struct GNUNET_PeerIdentity *peer,
638 const struct GNUNET_HELLO_Message *hello,
641 struct PeerList *pos;
645 /* last call, schedule 'find_more_peers' again... */
646 if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN))
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650 "Received shutdown request, stopping search for peers to connect to.\n");
654 schedule_peer_search ();
659 /* no HELLO known; can not connect, ignore! */
662 if (0 == memcmp (&my_identity,
663 peer, sizeof (struct GNUNET_PeerIdentity)))
664 return; /* that's me! */
666 consider_for_advertising (hello);
668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
669 "Considering connecting to peer `%s'\n",
675 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
677 if (GNUNET_YES == pos->is_connected)
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Already connected to peer `%s'\n",
686 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690 "Already tried peer `%s' recently\n",
693 return; /* peer still blacklisted */
695 if (GNUNET_YES == pos->is_friend)
697 attempt_connect (peer, pos);
703 if ( (GNUNET_YES == friends_only) ||
704 (friend_count < minimum_friend_count) )
707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708 "Peer `%s' is not a friend, and we currently only connect to friends\n",
713 attempt_connect (peer, NULL);
718 * Try to add more friends to our connection set.
723 struct PeerList *pos;
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Considering all of our friends for new connections\n");
732 if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
733 (GNUNET_YES == pos->is_friend) &&
734 (GNUNET_YES != pos->is_connected) )
735 attempt_connect (&pos->id, pos);
742 * Discard peer entries for blacklisted peers
743 * where the blacklisting has expired.
746 discard_old_blacklist_entries ()
748 struct PeerList *pos;
749 struct PeerList *next;
750 struct PeerList *prev;
754 while (NULL != (pos = next))
757 if ( (GNUNET_NO == pos->is_friend) &&
758 (GNUNET_NO == pos->is_connected) &&
759 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
761 /* delete 'pos' from list */
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n",
765 GNUNET_i2s (&pos->id));
782 * Find more peers that we should connect to and ask the
783 * core to establish connections.
786 find_more_peers (void *cls,
787 const struct GNUNET_SCHEDULER_TaskContext *tc)
789 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
792 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793 "Received shutdown request, stopping search for peers to connect to.\n");
797 discard_old_blacklist_entries ();
798 if (connection_count <= target_connection_count)
800 schedule_peer_search ();
803 if ( (GNUNET_YES == friends_only) ||
804 (friend_count < minimum_friend_count) )
807 schedule_peer_search ();
811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812 "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
814 target_connection_count,
817 GNUNET_PEERINFO_for_all (cfg,
820 0, GNUNET_TIME_UNIT_FOREVER_REL,
821 &process_peer, NULL);
826 * Function called after GNUNET_CORE_connect has succeeded
827 * (or failed for good).
830 * @param server handle to the server, NULL if we failed
831 * @param my_id ID of this peer, NULL if we failed
832 * @param publicKey public key of this peer, NULL if we failed
835 core_init (void *cls,
836 struct GNUNET_CORE_Handle * server,
837 const struct GNUNET_PeerIdentity *
840 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
845 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
846 _("Failed to connect to core service, can not manage topology!\n"));
847 GNUNET_SCHEDULER_shutdown (sched);
851 my_identity = *my_id;
853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 GNUNET_SCHEDULER_add_delayed (sched,
859 GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
866 * gnunet-daemon-topology command line options.
868 static struct GNUNET_GETOPT_CommandLineOption options[] = {
869 GNUNET_GETOPT_OPTION_END
874 * Read the friends file.
877 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
884 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
885 unsigned int entries_found;
889 GNUNET_CONFIGURATION_get_value_filename (cfg,
894 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
895 _("Option `%s' in section `%s' not specified!\n"),
900 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
901 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
902 | GNUNET_DISK_PERM_USER_WRITE);
903 if (0 != STAT (fn, &frstat))
905 if ((friends_only) || (minimum_friend_count > 0))
907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
908 _("Could not read friends list `%s'\n"), fn);
913 if (frstat.st_size == 0)
915 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
916 _("Friends file `%s' is empty.\n"),
921 data = GNUNET_malloc_large (frstat.st_size);
922 if (frstat.st_size !=
923 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
925 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
926 _("Failed to read friends list from `%s'\n"), fn);
933 while ((pos < frstat.st_size) && isspace (data[pos]))
935 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
936 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
938 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
939 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
941 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
942 _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
943 (unsigned long long) pos);
945 while ((pos < frstat.st_size) && (!isspace (data[pos])))
949 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
950 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
952 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
953 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
954 (unsigned long long) pos,
960 fl = GNUNET_malloc (sizeof(struct PeerList));
961 fl->is_friend = GNUNET_YES;
962 fl->id.hashPubKey = hc;
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Found friend `%s' in configuration\n",
968 GNUNET_i2s (&fl->id));
971 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
972 while ((pos < frstat.st_size) && isspace (data[pos]))
977 if ( (minimum_friend_count > entries_found) &&
978 (friends_only == GNUNET_NO) )
980 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
981 _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
983 if ( (minimum_friend_count > target_connection_count) &&
984 (friends_only == GNUNET_NO) )
986 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
987 _("More friendly connections required than target total number of connections.\n"));
993 * This function is called whenever an encrypted HELLO message is
997 * @param other the other peer involved (sender or receiver, NULL
998 * for loopback messages where we are both sender and receiver)
999 * @param message the actual HELLO message
1000 * @return GNUNET_OK to keep the connection open,
1001 * GNUNET_SYSERR to close it (signal serious error)
1004 handle_encrypted_hello (void *cls,
1005 const struct GNUNET_PeerIdentity * other,
1006 const struct GNUNET_MessageHeader *
1010 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1011 "Received encrypted `%s' from peer `%s'",
1013 GNUNET_i2s (other));
1015 if (transport != NULL)
1016 GNUNET_TRANSPORT_offer_hello (transport,
1023 * Peerinfo calls this function to let us know about a
1024 * possible peer that we might want to connect to.
1027 * @param peer NULL for the end of the list, otherwise a peer identity
1028 * @param hello a HELLO for a peer, or NULL
1029 * @param trust how much do we trust the given peer?
1032 gather_hello_callback (void *cls,
1033 const struct GNUNET_PeerIdentity *peer,
1034 const struct GNUNET_HELLO_Message *hello,
1039 hello_gathering_active = GNUNET_NO;
1043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1044 "Received `%s' for peer `%s'",
1049 consider_for_advertising (hello);
1054 * Function to fill send buffer with HELLO.
1057 * @param receiver the receiver of the message
1058 * @param position is the reference to the
1059 * first unused position in the buffer where GNUnet is building
1061 * @param padding is the number of bytes left in that buffer.
1062 * @return the number of bytes written to
1063 * that buffer (must be a positive number).
1066 hello_advertising (void *cls,
1067 const struct GNUNET_PeerIdentity *
1072 struct PeerList *pl;
1073 struct HelloList *pos;
1074 struct HelloList *prev;
1075 struct HelloList *next;
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "Data solicited for `%s', considering sending `%s's",
1081 GNUNET_i2s (receiver),
1087 if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1096 /* find applicable HELLOs */
1099 while (NULL != (pos = next))
1103 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1104 &receiver->hashPubKey))
1106 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1108 /* time to discard... */
1113 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1123 size = GNUNET_HELLO_size (pos->msg);
1126 memcpy (position, pos->msg, size);
1127 GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1128 &receiver->hashPubKey);
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "Sending %u bytes of `%s's",
1137 (unsigned int) size,
1142 if ( (GNUNET_NO == hello_gathering_active) &&
1143 (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1144 MIN_HELLO_GATHER_DELAY.value) )
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "Have no `%s's, trying to get some from `%s' for next time",
1152 hello_gathering_active = GNUNET_YES;
1153 last_hello_gather_time = GNUNET_TIME_absolute_get();
1154 GNUNET_PEERINFO_for_all (cfg,
1157 0, GNUNET_TIME_UNIT_FOREVER_REL,
1158 &gather_hello_callback, NULL);
1165 * Last task run during shutdown. Disconnects us from
1166 * the transport and core.
1169 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1171 struct PeerList *pl;
1173 if (NULL != peerinfo_notify)
1175 GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
1176 peerinfo_notify = NULL;
1178 GNUNET_TRANSPORT_disconnect (transport);
1182 GNUNET_CORE_disconnect (handle);
1185 while (NULL != (pl = friends))
1194 * Main function that will be run.
1196 * @param cls closure
1197 * @param s the scheduler to use
1198 * @param args remaining command-line arguments
1199 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1200 * @param c configuration
1204 struct GNUNET_SCHEDULER_Handle * s,
1206 const char *cfgfile,
1207 const struct GNUNET_CONFIGURATION_Handle * c)
1209 struct GNUNET_CORE_MessageHandler handlers[] =
1211 { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1214 unsigned long long opt;
1218 autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1221 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1225 GNUNET_CONFIGURATION_get_value_number (cfg,
1230 minimum_friend_count = (unsigned int) opt;
1232 GNUNET_CONFIGURATION_get_value_number (cfg,
1234 "TARGET-CONNECTION-COUNT",
1237 target_connection_count = (unsigned int) opt;
1239 if ( (friends_only == GNUNET_YES) ||
1240 (minimum_friend_count > 0) )
1241 read_friends_file (cfg);
1243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1244 "Topology would like %u connections with at least %u friends (%s)\n",
1245 target_connection_count,
1246 minimum_friend_count,
1247 autoconnect ? "autoconnect enabled" : "autoconnect disabled");
1249 transport = GNUNET_TRANSPORT_connect (sched,
1255 handle = GNUNET_CORE_connect (sched,
1257 GNUNET_TIME_UNIT_FOREVER_REL,
1266 GNUNET_SCHEDULER_add_delayed (sched,
1267 GNUNET_TIME_UNIT_FOREVER_REL,
1268 &cleaning_task, NULL);
1269 if (NULL == transport)
1271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1272 _("Failed to connect to `%s' service.\n"),
1274 GNUNET_SCHEDULER_shutdown (sched);
1279 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1280 _("Failed to connect to `%s' service.\n"),
1282 GNUNET_SCHEDULER_shutdown (sched);
1285 peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
1292 * The main function for the topology daemon.
1294 * @param argc number of arguments from the command line
1295 * @param argv command line arguments
1296 * @return 0 ok, 1 on error
1299 main (int argc, char *const *argv)
1304 GNUNET_PROGRAM_run (argc,
1307 _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1309 &run, NULL)) ? 0 : 1;
1313 /* end of gnunet-daemon-topology.c */