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;
235 * Entry in linked list of active 'disconnect' requests that we have issued.
237 struct DisconnectList
240 * This is a doubly-linked list.
242 struct DisconnectList *next;
245 * This is a doubly-linked list.
247 struct DisconnectList *prev;
250 * Our request handle.
252 struct GNUNET_CORE_InformationRequestContext *rh;
255 * Peer we tried to disconnect.
257 struct GNUNET_PeerIdentity peer;
263 * Head of doubly-linked list of active 'disconnect' requests that we have issued.
265 static struct DisconnectList *disconnect_head;
268 * Head of doubly-linked list of active 'disconnect' requests that we have issued.
270 static struct DisconnectList *disconnect_tail;
274 * Function called once our request to 'disconnect' a peer
277 * @param cls our 'struct DisconnectList'
278 * @param peer NULL on error (then what?)
279 * @param bpm_in set to the current bandwidth limit (receiving) for this peer
280 * @param bpm_out set to the current bandwidth limit (sending) for this peer
281 * @param latency current latency estimate, "FOREVER" if we have been
283 * @param amount set to the amount that was actually reserved or unreserved
284 * @param preference current traffic preference for the given peer
287 disconnect_done (void *cls,
289 GNUNET_PeerIdentity * peer,
291 unsigned int bpm_out,
292 struct GNUNET_TIME_Relative
294 unsigned long long preference)
296 struct DisconnectList *dl = cls;
298 GNUNET_CONTAINER_DLL_remove (disconnect_head,
306 * Force a disconnect from the specified peer.
309 force_disconnect (const struct GNUNET_PeerIdentity *peer)
311 struct DisconnectList *dl;
313 dl = GNUNET_malloc (sizeof (struct DisconnectList));
315 GNUNET_CONTAINER_DLL_insert (disconnect_head,
318 dl->rh = GNUNET_CORE_peer_get_info (sched, cfg,
320 GNUNET_TIME_UNIT_FOREVER_REL,
330 * Function called by core when our attempt to connect
331 * succeeded. Does nothing.
334 ready_callback (void *cls,
335 size_t size, void *buf)
337 struct GNUNET_MessageHeader hdr;
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Core told us that our attempt to connect failed.\n");
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
348 "Sending dummy message to establish connection.\n");
350 hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
351 hdr.type = htons (GNUNET_MESSAGE_TYPE_TOPOLOGY_DUMMY);
352 memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
353 return sizeof (struct GNUNET_MessageHeader);
358 * Try to connect to the specified peer.
360 * @param peer who we should try to connect to
361 * @param pos entry in our friend list; NULL if not in friend list yet
364 attempt_connect (const struct GNUNET_PeerIdentity *peer,
365 struct PeerList *pos)
372 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
379 pos = GNUNET_malloc (sizeof(struct PeerList));
384 if (GNUNET_YES == pos->is_friend)
385 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
387 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "Asking core to connect to `%s'\n",
393 GNUNET_CORE_notify_transmit_ready (handle,
395 GNUNET_TIME_UNIT_MINUTES,
397 sizeof(struct GNUNET_MessageHeader),
404 * Is this peer one of our friends?
407 is_friend (const struct GNUNET_PeerIdentity * peer)
409 struct PeerList *pos;
414 if ( (GNUNET_YES == pos->is_friend) &&
415 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "Determined that `%s' is a friend\n",
431 * Check if an additional connection from the given peer is allowed.
434 is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
436 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
437 return GNUNET_SYSERR; /* disallow connections to self */
438 if (is_friend (peer))
440 if (GNUNET_YES == friends_only)
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Determined that `%s' is not allowed to connect (not a friend)\n",
447 return GNUNET_SYSERR;
449 if (friend_count >= minimum_friend_count)
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453 "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
456 return GNUNET_SYSERR;
461 * Method called whenever a peer connects.
464 * @param peer peer identity this notification is about
466 static void connect_notify (void *cls,
468 GNUNET_PeerIdentity * peer)
470 struct PeerList *pos;
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Core told us that we are connecting to `%s'\n",
481 if ( (GNUNET_YES == pos->is_friend) &&
482 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
484 GNUNET_assert (GNUNET_NO == pos->is_connected);
485 pos->is_connected = GNUNET_YES;
486 pos->blacklisted_until.value = 0; /* remove blacklisting */
492 pos = GNUNET_malloc (sizeof(struct PeerList));
494 pos->is_connected = GNUNET_YES;
497 if (GNUNET_OK != is_connection_allowed (peer))
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501 "Connection to `%s' is forbidden, forcing disconnect!\n",
504 force_disconnect (peer);
510 * Disconnect from all non-friends (we're below quota).
515 struct PeerList *pos;
520 if (GNUNET_NO == pos->is_friend)
522 GNUNET_assert (GNUNET_YES == pos->is_connected);
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Connection to `%s' is not from a friend, forcing disconnect!\n",
526 GNUNET_i2s (&pos->id));
528 force_disconnect (&pos->id);
536 * Method called whenever a peer disconnects.
539 * @param peer peer identity this notification is about
541 static void disconnect_notify (void *cls,
543 GNUNET_PeerIdentity * peer)
545 struct PeerList *pos;
546 struct PeerList *prev;
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Core told us that we disconnected from `%s'\n",
558 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
560 GNUNET_assert (GNUNET_YES == pos->is_connected);
561 pos->is_connected = GNUNET_NO;
562 if (GNUNET_YES == pos->is_friend)
565 if (friend_count < minimum_friend_count)
567 /* disconnect from all non-friends */
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570 "Not enough friendly connections, dropping all non-friend connections\n");
573 attempt_connect (peer, pos);
582 prev->next = pos->next;
595 * Find more peers that we should connect to and ask the
596 * core to establish connections.
599 find_more_peers (void *cls,
600 const struct GNUNET_SCHEDULER_TaskContext *tc);
604 * Determine when we should try again to find more peers and
608 schedule_peer_search ()
610 struct GNUNET_TIME_Relative delay;
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);
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "Will try to find more peers in %llums\n",
625 (unsigned long long) delay.value);
627 GNUNET_SCHEDULER_add_delayed (sched,
637 * Iterator called on each address.
639 * @param cls flag that we will set if we see any addresses
640 * @param tname name of the transport
641 * @param expiration when will the given address expire
642 * @param addr the address of the peer
643 * @param addrlen number of bytes in addr
644 * @return GNUNET_SYSERR always, to terminate iteration
647 address_iterator (void *cls,
649 struct GNUNET_TIME_Absolute expiration,
650 const void *addr, size_t addrlen)
654 return GNUNET_SYSERR;
659 * We've gotten a HELLO from another peer.
660 * Consider it for advertising.
663 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
666 struct GNUNET_PeerIdentity pid;
667 struct HelloList *pos;
670 have_address = GNUNET_NO;
671 GNUNET_HELLO_iterate_addresses (hello,
675 if (GNUNET_NO == have_address)
676 return; /* no point in advertising this one... */
677 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
681 if (0 == memcmp (&pos->id,
683 sizeof(struct GNUNET_PeerIdentity)))
684 return; /* duplicate, at least "mostly" */
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Found `%s' from peer `%s' for advertising\n",
693 size = GNUNET_HELLO_size (hello);
694 pos = GNUNET_malloc (sizeof(struct HelloList) + size);
695 pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
696 memcpy (&pos->msg, hello, size);
698 pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
699 /* 2^{-5} chance of not sending a HELLO to a peer is
700 acceptably small (if the filter is 50% full);
701 64 bytes of memory are small compared to the rest
702 of the data structure and would only really become
703 "useless" once a HELLO has been passed on to ~100
704 other peers, which is likely more than enough in
705 any case; hence 64, 5 as bloomfilter parameters. */
706 pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
707 /* never send a peer its own HELLO */
708 GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
715 * Peerinfo calls this function to let us know about a
716 * possible peer that we might want to connect to.
719 process_peer (void *cls,
720 const struct GNUNET_PeerIdentity *peer,
721 const struct GNUNET_HELLO_Message *hello,
724 struct PeerList *pos;
729 /* last call, schedule 'find_more_peers' again... */
730 if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN))
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734 "Received shutdown request, stopping search for peers to connect to.\n");
738 schedule_peer_search ();
743 /* no HELLO known; can not connect, ignore! */
746 if (0 == memcmp (&my_identity,
747 peer, sizeof (struct GNUNET_PeerIdentity)))
748 return; /* that's me! */
750 consider_for_advertising (hello);
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "Considering connecting to peer `%s'\n",
759 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
761 if (GNUNET_YES == pos->is_connected)
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
765 "Already connected to peer `%s'\n",
770 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774 "Already tried peer `%s' recently\n",
777 return; /* peer still blacklisted */
779 if (GNUNET_YES == pos->is_friend)
781 attempt_connect (peer, pos);
787 if ( (GNUNET_YES == friends_only) ||
788 (friend_count < minimum_friend_count) )
791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792 "Peer `%s' is not a friend, and we currently only connect to friends\n",
797 attempt_connect (peer, NULL);
802 * Try to add more friends to our connection set.
807 struct PeerList *pos;
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Considering all of our friends for new connections\n");
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);
826 * Discard peer entries for blacklisted peers
827 * where the blacklisting has expired.
830 discard_old_blacklist_entries ()
832 struct PeerList *pos;
833 struct PeerList *next;
834 struct PeerList *prev;
838 while (NULL != (pos = next))
841 if ( (GNUNET_NO == pos->is_friend) &&
842 (GNUNET_NO == pos->is_connected) &&
843 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
845 /* delete 'pos' from list */
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));
866 * Find more peers that we should connect to and ask the
867 * core to establish connections.
870 find_more_peers (void *cls,
871 const struct GNUNET_SCHEDULER_TaskContext *tc)
873 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
877 "Received shutdown request, stopping search for peers to connect to.\n");
881 discard_old_blacklist_entries ();
882 if (connection_count <= target_connection_count)
884 schedule_peer_search ();
887 if ( (GNUNET_YES == friends_only) ||
888 (friend_count < minimum_friend_count) )
891 schedule_peer_search ();
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
896 "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
898 target_connection_count,
901 pitr_more = GNUNET_PEERINFO_iterate (cfg,
904 0, GNUNET_TIME_UNIT_FOREVER_REL,
905 &process_peer, NULL);
910 * Function called after GNUNET_CORE_connect has succeeded
911 * (or failed for good).
914 * @param server handle to the server, NULL if we failed
915 * @param my_id ID of this peer, NULL if we failed
916 * @param publicKey public key of this peer, NULL if we failed
919 core_init (void *cls,
920 struct GNUNET_CORE_Handle * server,
921 const struct GNUNET_PeerIdentity *
924 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930 _("Failed to connect to core service, can not manage topology!\n"));
931 GNUNET_SCHEDULER_shutdown (sched);
935 my_identity = *my_id;
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942 GNUNET_SCHEDULER_add_delayed (sched,
943 GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
950 * gnunet-daemon-topology command line options.
952 static struct GNUNET_GETOPT_CommandLineOption options[] = {
953 GNUNET_GETOPT_OPTION_END
958 * Read the friends file.
961 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
968 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
969 unsigned int entries_found;
973 GNUNET_CONFIGURATION_get_value_filename (cfg,
978 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
979 _("Option `%s' in section `%s' not specified!\n"),
984 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
985 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
986 | GNUNET_DISK_PERM_USER_WRITE);
987 if (0 != STAT (fn, &frstat))
989 if ((friends_only) || (minimum_friend_count > 0))
991 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
992 _("Could not read friends list `%s'\n"), fn);
997 if (frstat.st_size == 0)
999 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1000 _("Friends file `%s' is empty.\n"),
1005 data = GNUNET_malloc_large (frstat.st_size);
1006 if (frstat.st_size !=
1007 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010 _("Failed to read friends list from `%s'\n"), fn);
1017 while ((pos < frstat.st_size) && isspace (data[pos]))
1019 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1020 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1022 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1023 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1025 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1026 _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
1027 (unsigned long long) pos);
1029 while ((pos < frstat.st_size) && (!isspace (data[pos])))
1033 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1034 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
1036 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1037 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
1038 (unsigned long long) pos,
1044 fl = GNUNET_malloc (sizeof(struct PeerList));
1045 fl->is_friend = GNUNET_YES;
1046 fl->id.hashPubKey = hc;
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Found friend `%s' in configuration\n",
1052 GNUNET_i2s (&fl->id));
1055 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1056 while ((pos < frstat.st_size) && isspace (data[pos]))
1061 if ( (minimum_friend_count > entries_found) &&
1062 (friends_only == GNUNET_NO) )
1064 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1065 _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
1067 if ( (minimum_friend_count > target_connection_count) &&
1068 (friends_only == GNUNET_NO) )
1070 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1071 _("More friendly connections required than target total number of connections.\n"));
1077 * This function is called whenever an encrypted HELLO message is
1080 * @param cls closure
1081 * @param other the other peer involved (sender or receiver, NULL
1082 * for loopback messages where we are both sender and receiver)
1083 * @param message the actual HELLO message
1084 * @return GNUNET_OK to keep the connection open,
1085 * GNUNET_SYSERR to close it (signal serious error)
1088 handle_encrypted_hello (void *cls,
1089 const struct GNUNET_PeerIdentity * other,
1090 const struct GNUNET_MessageHeader *
1094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1095 "Received encrypted `%s' from peer `%s'",
1097 GNUNET_i2s (other));
1099 if (transport != NULL)
1100 GNUNET_TRANSPORT_offer_hello (transport,
1107 * Peerinfo calls this function to let us know about a
1108 * possible peer that we might want to connect to.
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?
1116 gather_hello_callback (void *cls,
1117 const struct GNUNET_PeerIdentity *peer,
1118 const struct GNUNET_HELLO_Message *hello,
1127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1128 "Received `%s' for peer `%s'",
1133 consider_for_advertising (hello);
1137 // FIXME: this no longer works (no solicitation!)
1139 * Function to fill send buffer with HELLO.
1142 * @param receiver the receiver of the message
1143 * @param position is the reference to the
1144 * first unused position in the buffer where GNUnet is building
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).
1150 /* static */ unsigned int
1151 hello_advertising (void *cls,
1152 const struct GNUNET_PeerIdentity *
1157 struct PeerList *pl;
1158 struct HelloList *pos;
1159 struct HelloList *prev;
1160 struct HelloList *next;
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 "Data solicited for `%s', considering sending `%s's",
1166 GNUNET_i2s (receiver),
1172 if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1181 /* find applicable HELLOs */
1184 while (NULL != (pos = next))
1188 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1189 &receiver->hashPubKey))
1191 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1193 /* time to discard... */
1198 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1208 size = GNUNET_HELLO_size (pos->msg);
1211 memcpy (position, pos->msg, size);
1212 GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1213 &receiver->hashPubKey);
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Sending %u bytes of `%s's",
1222 (unsigned int) size,
1227 if ( (NULL == pitr) &&
1228 (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1229 MIN_HELLO_GATHER_DELAY.value) )
1232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1233 "Have no `%s's, trying to get some from `%s' for next time",
1237 last_hello_gather_time = GNUNET_TIME_absolute_get();
1238 pitr = GNUNET_PEERINFO_iterate (cfg,
1241 0, GNUNET_TIME_UNIT_FOREVER_REL,
1242 &gather_hello_callback, NULL);
1249 * Last task run during shutdown. Disconnects us from
1250 * the transport and core.
1253 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1255 struct PeerList *pl;
1256 struct DisconnectList *dl;
1258 if (NULL != peerinfo_notify)
1260 GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
1261 peerinfo_notify = NULL;
1265 GNUNET_PEERINFO_iterate_cancel (pitr);
1268 if (NULL != pitr_more)
1270 GNUNET_PEERINFO_iterate_cancel (pitr_more);
1273 GNUNET_TRANSPORT_disconnect (transport);
1277 GNUNET_CORE_disconnect (handle);
1280 while (NULL != (pl = friends))
1285 while (NULL != (dl = disconnect_head))
1287 GNUNET_CONTAINER_DLL_remove (disconnect_head,
1290 GNUNET_CORE_peer_get_info_cancel (dl->rh);
1297 * Main function that will be run.
1299 * @param cls closure
1300 * @param s the scheduler to use
1301 * @param args remaining command-line arguments
1302 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1303 * @param c configuration
1307 struct GNUNET_SCHEDULER_Handle * s,
1309 const char *cfgfile,
1310 const struct GNUNET_CONFIGURATION_Handle * c)
1312 struct GNUNET_CORE_MessageHandler handlers[] =
1314 { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1317 unsigned long long opt;
1321 autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1324 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1328 GNUNET_CONFIGURATION_get_value_number (cfg,
1333 minimum_friend_count = (unsigned int) opt;
1335 GNUNET_CONFIGURATION_get_value_number (cfg,
1337 "TARGET-CONNECTION-COUNT",
1340 target_connection_count = (unsigned int) opt;
1342 if ( (friends_only == GNUNET_YES) ||
1343 (minimum_friend_count > 0) )
1344 read_friends_file (cfg);
1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1347 "Topology would like %u connections with at least %u friends (%s)\n",
1348 target_connection_count,
1349 minimum_friend_count,
1350 autoconnect ? "autoconnect enabled" : "autoconnect disabled");
1352 transport = GNUNET_TRANSPORT_connect (sched,
1358 handle = GNUNET_CORE_connect (sched,
1360 GNUNET_TIME_UNIT_FOREVER_REL,
1368 GNUNET_SCHEDULER_add_delayed (sched,
1369 GNUNET_TIME_UNIT_FOREVER_REL,
1370 &cleaning_task, NULL);
1371 if (NULL == transport)
1373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1374 _("Failed to connect to `%s' service.\n"),
1376 GNUNET_SCHEDULER_shutdown (sched);
1381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1382 _("Failed to connect to `%s' service.\n"),
1384 GNUNET_SCHEDULER_shutdown (sched);
1387 peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
1394 * The main function for the topology daemon.
1396 * @param argc number of arguments from the command line
1397 * @param argv command line arguments
1398 * @return 0 ok, 1 on error
1401 main (int argc, char *const *argv)
1406 GNUNET_PROGRAM_run (argc,
1409 _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1411 &run, NULL)) ? 0 : 1;
1415 /* end of gnunet-daemon-topology.c */