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 * Non-NULL if we are currently having a request pending with
223 * PEERINFO asking for HELLOs for advertising?
225 static struct GNUNET_PEERINFO_IteratorContext *pitr;
228 * Non-NULL if we are currently having a request pending with
229 * PEERINFO looking for more peers to connect to.
231 static struct GNUNET_PEERINFO_IteratorContext *pitr_more;
236 * Force a disconnect from the specified peer.
239 force_disconnect (const struct GNUNET_PeerIdentity *peer)
241 GNUNET_CORE_peer_configure (handle,
243 GNUNET_TIME_UNIT_FOREVER_REL,
253 * Function called by core when our attempt to connect
254 * succeeded. Does nothing.
257 ready_callback (void *cls,
258 size_t size, void *buf)
260 struct GNUNET_MessageHeader hdr;
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "Core told us that our attempt to connect failed.\n");
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "Sending dummy message to establish connection.\n");
273 hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
274 hdr.type = htons (GNUNET_MESSAGE_TYPE_TOPOLOGY_DUMMY);
275 memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
276 return sizeof (struct GNUNET_MessageHeader);
281 * Try to connect to the specified peer.
283 * @param peer who we should try to connect to
284 * @param pos entry in our friend list; NULL if not in friend list yet
287 attempt_connect (const struct GNUNET_PeerIdentity *peer,
288 struct PeerList *pos)
295 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
302 pos = GNUNET_malloc (sizeof(struct PeerList));
307 if (GNUNET_YES == pos->is_friend)
308 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
310 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313 "Asking core to connect to `%s'\n",
316 GNUNET_CORE_notify_transmit_ready (handle,
318 GNUNET_TIME_UNIT_MINUTES,
320 sizeof(struct GNUNET_MessageHeader),
327 * Is this peer one of our friends?
330 is_friend (const struct GNUNET_PeerIdentity * peer)
332 struct PeerList *pos;
337 if ( (GNUNET_YES == pos->is_friend) &&
338 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Determined that `%s' is a friend\n",
354 * Check if an additional connection from the given peer is allowed.
357 is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
359 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
360 return GNUNET_SYSERR; /* disallow connections to self */
361 if (is_friend (peer))
363 if (GNUNET_YES == friends_only)
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "Determined that `%s' is not allowed to connect (not a friend)\n",
370 return GNUNET_SYSERR;
372 if (friend_count >= minimum_friend_count)
375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
379 return GNUNET_SYSERR;
384 * Method called whenever a peer connects.
387 * @param peer peer identity this notification is about
389 static void connect_notify (void *cls,
391 GNUNET_PeerIdentity * peer)
393 struct PeerList *pos;
396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397 "Core told us that we are connecting to `%s'\n",
404 if ( (GNUNET_YES == pos->is_friend) &&
405 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
407 GNUNET_assert (GNUNET_NO == pos->is_connected);
408 pos->is_connected = GNUNET_YES;
409 pos->blacklisted_until.value = 0; /* remove blacklisting */
415 pos = GNUNET_malloc (sizeof(struct PeerList));
417 pos->is_connected = GNUNET_YES;
420 if (GNUNET_OK != is_connection_allowed (peer))
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Connection to `%s' is forbidden, forcing disconnect!\n",
427 force_disconnect (peer);
433 * Disconnect from all non-friends (we're below quota).
438 struct PeerList *pos;
443 if (GNUNET_NO == pos->is_friend)
445 GNUNET_assert (GNUNET_YES == pos->is_connected);
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "Connection to `%s' is not from a friend, forcing disconnect!\n",
449 GNUNET_i2s (&pos->id));
451 force_disconnect (&pos->id);
459 * Method called whenever a peer disconnects.
462 * @param peer peer identity this notification is about
464 static void disconnect_notify (void *cls,
466 GNUNET_PeerIdentity * peer)
468 struct PeerList *pos;
469 struct PeerList *prev;
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473 "Core told us that we disconnected from `%s'\n",
481 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
483 GNUNET_assert (GNUNET_YES == pos->is_connected);
484 pos->is_connected = GNUNET_NO;
485 if (GNUNET_YES == pos->is_friend)
488 if (friend_count < minimum_friend_count)
490 /* disconnect from all non-friends */
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "Not enough friendly connections, dropping all non-friend connections\n");
496 attempt_connect (peer, pos);
505 prev->next = pos->next;
518 * Find more peers that we should connect to and ask the
519 * core to establish connections.
522 find_more_peers (void *cls,
523 const struct GNUNET_SCHEDULER_TaskContext *tc);
527 * Determine when we should try again to find more peers and
531 schedule_peer_search ()
533 struct GNUNET_TIME_Relative delay;
535 /* Typically, we try again every 15 minutes; the minimum period is
536 15s; if we are above the connection target, we reduce re-trying
537 by the square of how much we are above; so for example, with 200%
538 of the connection target we would only look for more peers once
539 every hour (after all, we're quite busy processing twice as many
540 connections as we intended to have); similarly, if we are at only
541 25% of our connectivity goal, we will try 16x as hard to connect
542 (so roughly once a minute, plus the 15s minimum delay */
543 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
544 15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count);
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
547 "Will try to find more peers in %llums\n",
548 (unsigned long long) delay.value);
550 GNUNET_SCHEDULER_add_delayed (sched,
560 * Iterator called on each address.
562 * @param cls flag that we will set if we see any addresses
563 * @param tname name of the transport
564 * @param expiration when will the given address expire
565 * @param addr the address of the peer
566 * @param addrlen number of bytes in addr
567 * @return GNUNET_SYSERR always, to terminate iteration
570 address_iterator (void *cls,
572 struct GNUNET_TIME_Absolute expiration,
573 const void *addr, size_t addrlen)
577 return GNUNET_SYSERR;
582 * We've gotten a HELLO from another peer.
583 * Consider it for advertising.
586 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
589 struct GNUNET_PeerIdentity pid;
590 struct HelloList *pos;
593 have_address = GNUNET_NO;
594 GNUNET_HELLO_iterate_addresses (hello,
598 if (GNUNET_NO == have_address)
599 return; /* no point in advertising this one... */
600 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
604 if (0 == memcmp (&pos->id,
606 sizeof(struct GNUNET_PeerIdentity)))
607 return; /* duplicate, at least "mostly" */
611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612 "Found `%s' from peer `%s' for advertising\n",
616 size = GNUNET_HELLO_size (hello);
617 pos = GNUNET_malloc (sizeof(struct HelloList) + size);
618 pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
619 memcpy (&pos->msg, hello, size);
621 pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
622 /* 2^{-5} chance of not sending a HELLO to a peer is
623 acceptably small (if the filter is 50% full);
624 64 bytes of memory are small compared to the rest
625 of the data structure and would only really become
626 "useless" once a HELLO has been passed on to ~100
627 other peers, which is likely more than enough in
628 any case; hence 64, 5 as bloomfilter parameters. */
629 pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
630 /* never send a peer its own HELLO */
631 GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
638 * Peerinfo calls this function to let us know about a
639 * possible peer that we might want to connect to.
642 process_peer (void *cls,
643 const struct GNUNET_PeerIdentity *peer,
644 const struct GNUNET_HELLO_Message *hello,
647 struct PeerList *pos;
652 /* last call, schedule 'find_more_peers' again... */
653 if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN))
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657 "Received shutdown request, stopping search for peers to connect to.\n");
661 schedule_peer_search ();
666 /* no HELLO known; can not connect, ignore! */
669 if (0 == memcmp (&my_identity,
670 peer, sizeof (struct GNUNET_PeerIdentity)))
671 return; /* that's me! */
673 consider_for_advertising (hello);
675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676 "Considering connecting to peer `%s'\n",
682 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
684 if (GNUNET_YES == pos->is_connected)
687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688 "Already connected to peer `%s'\n",
693 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697 "Already tried peer `%s' recently\n",
700 return; /* peer still blacklisted */
702 if (GNUNET_YES == pos->is_friend)
704 attempt_connect (peer, pos);
710 if ( (GNUNET_YES == friends_only) ||
711 (friend_count < minimum_friend_count) )
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Peer `%s' is not a friend, and we currently only connect to friends\n",
720 attempt_connect (peer, NULL);
725 * Try to add more friends to our connection set.
730 struct PeerList *pos;
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734 "Considering all of our friends for new connections\n");
739 if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
740 (GNUNET_YES == pos->is_friend) &&
741 (GNUNET_YES != pos->is_connected) )
742 attempt_connect (&pos->id, pos);
749 * Discard peer entries for blacklisted peers
750 * where the blacklisting has expired.
753 discard_old_blacklist_entries ()
755 struct PeerList *pos;
756 struct PeerList *next;
757 struct PeerList *prev;
761 while (NULL != (pos = next))
764 if ( (GNUNET_NO == pos->is_friend) &&
765 (GNUNET_NO == pos->is_connected) &&
766 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
768 /* delete 'pos' from list */
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n",
772 GNUNET_i2s (&pos->id));
789 * Find more peers that we should connect to and ask the
790 * core to establish connections.
793 find_more_peers (void *cls,
794 const struct GNUNET_SCHEDULER_TaskContext *tc)
796 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800 "Received shutdown request, stopping search for peers to connect to.\n");
804 discard_old_blacklist_entries ();
805 if (connection_count <= target_connection_count)
807 schedule_peer_search ();
810 if ( (GNUNET_YES == friends_only) ||
811 (friend_count < minimum_friend_count) )
814 schedule_peer_search ();
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
821 target_connection_count,
824 pitr_more = GNUNET_PEERINFO_iterate (cfg,
827 0, GNUNET_TIME_UNIT_FOREVER_REL,
828 &process_peer, NULL);
833 * Function called after GNUNET_CORE_connect has succeeded
834 * (or failed for good).
837 * @param server handle to the server, NULL if we failed
838 * @param my_id ID of this peer, NULL if we failed
839 * @param publicKey public key of this peer, NULL if we failed
842 core_init (void *cls,
843 struct GNUNET_CORE_Handle * server,
844 const struct GNUNET_PeerIdentity *
847 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
852 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
853 _("Failed to connect to core service, can not manage topology!\n"));
854 GNUNET_SCHEDULER_shutdown (sched);
858 my_identity = *my_id;
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865 GNUNET_SCHEDULER_add_delayed (sched,
866 GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
873 * gnunet-daemon-topology command line options.
875 static struct GNUNET_GETOPT_CommandLineOption options[] = {
876 GNUNET_GETOPT_OPTION_END
881 * Read the friends file.
884 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
891 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
892 unsigned int entries_found;
896 GNUNET_CONFIGURATION_get_value_filename (cfg,
901 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
902 _("Option `%s' in section `%s' not specified!\n"),
907 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
908 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
909 | GNUNET_DISK_PERM_USER_WRITE);
910 if (0 != STAT (fn, &frstat))
912 if ((friends_only) || (minimum_friend_count > 0))
914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 _("Could not read friends list `%s'\n"), fn);
920 if (frstat.st_size == 0)
922 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
923 _("Friends file `%s' is empty.\n"),
928 data = GNUNET_malloc_large (frstat.st_size);
929 if (frstat.st_size !=
930 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
932 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
933 _("Failed to read friends list from `%s'\n"), fn);
940 while ((pos < frstat.st_size) && isspace (data[pos]))
942 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
943 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
945 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
946 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
948 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
949 _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
950 (unsigned long long) pos);
952 while ((pos < frstat.st_size) && (!isspace (data[pos])))
956 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
957 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
959 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
960 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
961 (unsigned long long) pos,
967 fl = GNUNET_malloc (sizeof(struct PeerList));
968 fl->is_friend = GNUNET_YES;
969 fl->id.hashPubKey = hc;
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 "Found friend `%s' in configuration\n",
975 GNUNET_i2s (&fl->id));
978 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
979 while ((pos < frstat.st_size) && isspace (data[pos]))
984 if ( (minimum_friend_count > entries_found) &&
985 (friends_only == GNUNET_NO) )
987 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
988 _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
990 if ( (minimum_friend_count > target_connection_count) &&
991 (friends_only == GNUNET_NO) )
993 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
994 _("More friendly connections required than target total number of connections.\n"));
1000 * This function is called whenever an encrypted HELLO message is
1003 * @param cls closure
1004 * @param other the other peer involved (sender or receiver, NULL
1005 * for loopback messages where we are both sender and receiver)
1006 * @param message the actual HELLO message
1007 * @return GNUNET_OK to keep the connection open,
1008 * GNUNET_SYSERR to close it (signal serious error)
1011 handle_encrypted_hello (void *cls,
1012 const struct GNUNET_PeerIdentity * other,
1013 const struct GNUNET_MessageHeader *
1017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1018 "Received encrypted `%s' from peer `%s'",
1020 GNUNET_i2s (other));
1022 if (transport != NULL)
1023 GNUNET_TRANSPORT_offer_hello (transport,
1030 * Peerinfo calls this function to let us know about a
1031 * possible peer that we might want to connect to.
1034 * @param peer NULL for the end of the list, otherwise a peer identity
1035 * @param hello a HELLO for a peer, or NULL
1036 * @param trust how much do we trust the given peer?
1039 gather_hello_callback (void *cls,
1040 const struct GNUNET_PeerIdentity *peer,
1041 const struct GNUNET_HELLO_Message *hello,
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Received `%s' for peer `%s'",
1056 consider_for_advertising (hello);
1061 * Function to fill send buffer with HELLO.
1064 * @param receiver the receiver of the message
1065 * @param position is the reference to the
1066 * first unused position in the buffer where GNUnet is building
1068 * @param padding is the number of bytes left in that buffer.
1069 * @return the number of bytes written to
1070 * that buffer (must be a positive number).
1073 hello_advertising (void *cls,
1074 const struct GNUNET_PeerIdentity *
1079 struct PeerList *pl;
1080 struct HelloList *pos;
1081 struct HelloList *prev;
1082 struct HelloList *next;
1086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1087 "Data solicited for `%s', considering sending `%s's",
1088 GNUNET_i2s (receiver),
1094 if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1103 /* find applicable HELLOs */
1106 while (NULL != (pos = next))
1110 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1111 &receiver->hashPubKey))
1113 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1115 /* time to discard... */
1120 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1130 size = GNUNET_HELLO_size (pos->msg);
1133 memcpy (position, pos->msg, size);
1134 GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1135 &receiver->hashPubKey);
1142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1143 "Sending %u bytes of `%s's",
1144 (unsigned int) size,
1149 if ( (NULL == pitr) &&
1150 (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1151 MIN_HELLO_GATHER_DELAY.value) )
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155 "Have no `%s's, trying to get some from `%s' for next time",
1159 last_hello_gather_time = GNUNET_TIME_absolute_get();
1160 pitr = GNUNET_PEERINFO_iterate (cfg,
1163 0, GNUNET_TIME_UNIT_FOREVER_REL,
1164 &gather_hello_callback, NULL);
1171 * Last task run during shutdown. Disconnects us from
1172 * the transport and core.
1175 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1177 struct PeerList *pl;
1179 if (NULL != peerinfo_notify)
1181 GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
1182 peerinfo_notify = NULL;
1186 GNUNET_PEERINFO_iterate_cancel (pitr);
1189 if (NULL != pitr_more)
1191 GNUNET_PEERINFO_iterate_cancel (pitr_more);
1194 GNUNET_TRANSPORT_disconnect (transport);
1198 GNUNET_CORE_disconnect (handle);
1201 while (NULL != (pl = friends))
1210 * Main function that will be run.
1212 * @param cls closure
1213 * @param s the scheduler to use
1214 * @param args remaining command-line arguments
1215 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1216 * @param c configuration
1220 struct GNUNET_SCHEDULER_Handle * s,
1222 const char *cfgfile,
1223 const struct GNUNET_CONFIGURATION_Handle * c)
1225 struct GNUNET_CORE_MessageHandler handlers[] =
1227 { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1230 unsigned long long opt;
1234 autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1237 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1241 GNUNET_CONFIGURATION_get_value_number (cfg,
1246 minimum_friend_count = (unsigned int) opt;
1248 GNUNET_CONFIGURATION_get_value_number (cfg,
1250 "TARGET-CONNECTION-COUNT",
1253 target_connection_count = (unsigned int) opt;
1255 if ( (friends_only == GNUNET_YES) ||
1256 (minimum_friend_count > 0) )
1257 read_friends_file (cfg);
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "Topology would like %u connections with at least %u friends (%s)\n",
1261 target_connection_count,
1262 minimum_friend_count,
1263 autoconnect ? "autoconnect enabled" : "autoconnect disabled");
1265 transport = GNUNET_TRANSPORT_connect (sched,
1271 handle = GNUNET_CORE_connect (sched,
1273 GNUNET_TIME_UNIT_FOREVER_REL,
1282 GNUNET_SCHEDULER_add_delayed (sched,
1283 GNUNET_TIME_UNIT_FOREVER_REL,
1284 &cleaning_task, NULL);
1285 if (NULL == transport)
1287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1288 _("Failed to connect to `%s' service.\n"),
1290 GNUNET_SCHEDULER_shutdown (sched);
1295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1296 _("Failed to connect to `%s' service.\n"),
1298 GNUNET_SCHEDULER_shutdown (sched);
1301 peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
1308 * The main function for the topology daemon.
1310 * @param argc number of arguments from the command line
1311 * @param argv command line arguments
1312 * @return 0 ok, 1 on error
1315 main (int argc, char *const *argv)
1320 GNUNET_PROGRAM_run (argc,
1323 _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1325 &run, NULL)) ? 0 : 1;
1329 /* end of gnunet-daemon-topology.c */