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 // FIXME: do something with return value!
242 GNUNET_CORE_peer_get_info (sched, cfg,
244 GNUNET_TIME_UNIT_FOREVER_REL,
254 * Function called by core when our attempt to connect
255 * succeeded. Does nothing.
258 ready_callback (void *cls,
259 size_t size, void *buf)
261 struct GNUNET_MessageHeader hdr;
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266 "Core told us that our attempt to connect failed.\n");
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Sending dummy message to establish connection.\n");
274 hdr.size = htons (sizeof (struct GNUNET_MessageHeader));
275 hdr.type = htons (GNUNET_MESSAGE_TYPE_TOPOLOGY_DUMMY);
276 memcpy (buf, &hdr, sizeof (struct GNUNET_MessageHeader));
277 return sizeof (struct GNUNET_MessageHeader);
282 * Try to connect to the specified peer.
284 * @param peer who we should try to connect to
285 * @param pos entry in our friend list; NULL if not in friend list yet
288 attempt_connect (const struct GNUNET_PeerIdentity *peer,
289 struct PeerList *pos)
296 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
303 pos = GNUNET_malloc (sizeof(struct PeerList));
308 if (GNUNET_YES == pos->is_friend)
309 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
311 pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "Asking core to connect to `%s'\n",
317 GNUNET_CORE_notify_transmit_ready (handle,
319 GNUNET_TIME_UNIT_MINUTES,
321 sizeof(struct GNUNET_MessageHeader),
328 * Is this peer one of our friends?
331 is_friend (const struct GNUNET_PeerIdentity * peer)
333 struct PeerList *pos;
338 if ( (GNUNET_YES == pos->is_friend) &&
339 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Determined that `%s' is a friend\n",
355 * Check if an additional connection from the given peer is allowed.
358 is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
360 if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
361 return GNUNET_SYSERR; /* disallow connections to self */
362 if (is_friend (peer))
364 if (GNUNET_YES == friends_only)
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368 "Determined that `%s' is not allowed to connect (not a friend)\n",
371 return GNUNET_SYSERR;
373 if (friend_count >= minimum_friend_count)
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Determined that `%s' is not allowed to connect (not enough connected friends)\n",
380 return GNUNET_SYSERR;
385 * Method called whenever a peer connects.
388 * @param peer peer identity this notification is about
390 static void connect_notify (void *cls,
392 GNUNET_PeerIdentity * peer)
394 struct PeerList *pos;
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Core told us that we are connecting to `%s'\n",
405 if ( (GNUNET_YES == pos->is_friend) &&
406 (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
408 GNUNET_assert (GNUNET_NO == pos->is_connected);
409 pos->is_connected = GNUNET_YES;
410 pos->blacklisted_until.value = 0; /* remove blacklisting */
416 pos = GNUNET_malloc (sizeof(struct PeerList));
418 pos->is_connected = GNUNET_YES;
421 if (GNUNET_OK != is_connection_allowed (peer))
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Connection to `%s' is forbidden, forcing disconnect!\n",
428 force_disconnect (peer);
434 * Disconnect from all non-friends (we're below quota).
439 struct PeerList *pos;
444 if (GNUNET_NO == pos->is_friend)
446 GNUNET_assert (GNUNET_YES == pos->is_connected);
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "Connection to `%s' is not from a friend, forcing disconnect!\n",
450 GNUNET_i2s (&pos->id));
452 force_disconnect (&pos->id);
460 * Method called whenever a peer disconnects.
463 * @param peer peer identity this notification is about
465 static void disconnect_notify (void *cls,
467 GNUNET_PeerIdentity * peer)
469 struct PeerList *pos;
470 struct PeerList *prev;
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "Core told us that we disconnected from `%s'\n",
482 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
484 GNUNET_assert (GNUNET_YES == pos->is_connected);
485 pos->is_connected = GNUNET_NO;
486 if (GNUNET_YES == pos->is_friend)
489 if (friend_count < minimum_friend_count)
491 /* disconnect from all non-friends */
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
494 "Not enough friendly connections, dropping all non-friend connections\n");
497 attempt_connect (peer, pos);
506 prev->next = pos->next;
519 * Find more peers that we should connect to and ask the
520 * core to establish connections.
523 find_more_peers (void *cls,
524 const struct GNUNET_SCHEDULER_TaskContext *tc);
528 * Determine when we should try again to find more peers and
532 schedule_peer_search ()
534 struct GNUNET_TIME_Relative delay;
536 /* Typically, we try again every 15 minutes; the minimum period is
537 15s; if we are above the connection target, we reduce re-trying
538 by the square of how much we are above; so for example, with 200%
539 of the connection target we would only look for more peers once
540 every hour (after all, we're quite busy processing twice as many
541 connections as we intended to have); similarly, if we are at only
542 25% of our connectivity goal, we will try 16x as hard to connect
543 (so roughly once a minute, plus the 15s minimum delay */
544 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
545 15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count);
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Will try to find more peers in %llums\n",
549 (unsigned long long) delay.value);
551 GNUNET_SCHEDULER_add_delayed (sched,
561 * Iterator called on each address.
563 * @param cls flag that we will set if we see any addresses
564 * @param tname name of the transport
565 * @param expiration when will the given address expire
566 * @param addr the address of the peer
567 * @param addrlen number of bytes in addr
568 * @return GNUNET_SYSERR always, to terminate iteration
571 address_iterator (void *cls,
573 struct GNUNET_TIME_Absolute expiration,
574 const void *addr, size_t addrlen)
578 return GNUNET_SYSERR;
583 * We've gotten a HELLO from another peer.
584 * Consider it for advertising.
587 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
590 struct GNUNET_PeerIdentity pid;
591 struct HelloList *pos;
594 have_address = GNUNET_NO;
595 GNUNET_HELLO_iterate_addresses (hello,
599 if (GNUNET_NO == have_address)
600 return; /* no point in advertising this one... */
601 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
605 if (0 == memcmp (&pos->id,
607 sizeof(struct GNUNET_PeerIdentity)))
608 return; /* duplicate, at least "mostly" */
612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
613 "Found `%s' from peer `%s' for advertising\n",
617 size = GNUNET_HELLO_size (hello);
618 pos = GNUNET_malloc (sizeof(struct HelloList) + size);
619 pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
620 memcpy (&pos->msg, hello, size);
622 pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
623 /* 2^{-5} chance of not sending a HELLO to a peer is
624 acceptably small (if the filter is 50% full);
625 64 bytes of memory are small compared to the rest
626 of the data structure and would only really become
627 "useless" once a HELLO has been passed on to ~100
628 other peers, which is likely more than enough in
629 any case; hence 64, 5 as bloomfilter parameters. */
630 pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
631 /* never send a peer its own HELLO */
632 GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
639 * Peerinfo calls this function to let us know about a
640 * possible peer that we might want to connect to.
643 process_peer (void *cls,
644 const struct GNUNET_PeerIdentity *peer,
645 const struct GNUNET_HELLO_Message *hello,
648 struct PeerList *pos;
653 /* last call, schedule 'find_more_peers' again... */
654 if (0 != (GNUNET_SCHEDULER_get_reason (sched) & GNUNET_SCHEDULER_REASON_SHUTDOWN))
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Received shutdown request, stopping search for peers to connect to.\n");
662 schedule_peer_search ();
667 /* no HELLO known; can not connect, ignore! */
670 if (0 == memcmp (&my_identity,
671 peer, sizeof (struct GNUNET_PeerIdentity)))
672 return; /* that's me! */
674 consider_for_advertising (hello);
676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
677 "Considering connecting to peer `%s'\n",
683 if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
685 if (GNUNET_YES == pos->is_connected)
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Already connected to peer `%s'\n",
694 if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
698 "Already tried peer `%s' recently\n",
701 return; /* peer still blacklisted */
703 if (GNUNET_YES == pos->is_friend)
705 attempt_connect (peer, pos);
711 if ( (GNUNET_YES == friends_only) ||
712 (friend_count < minimum_friend_count) )
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "Peer `%s' is not a friend, and we currently only connect to friends\n",
721 attempt_connect (peer, NULL);
726 * Try to add more friends to our connection set.
731 struct PeerList *pos;
734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
735 "Considering all of our friends for new connections\n");
740 if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
741 (GNUNET_YES == pos->is_friend) &&
742 (GNUNET_YES != pos->is_connected) )
743 attempt_connect (&pos->id, pos);
750 * Discard peer entries for blacklisted peers
751 * where the blacklisting has expired.
754 discard_old_blacklist_entries ()
756 struct PeerList *pos;
757 struct PeerList *next;
758 struct PeerList *prev;
762 while (NULL != (pos = next))
765 if ( (GNUNET_NO == pos->is_friend) &&
766 (GNUNET_NO == pos->is_connected) &&
767 (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
769 /* delete 'pos' from list */
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n",
773 GNUNET_i2s (&pos->id));
790 * Find more peers that we should connect to and ask the
791 * core to establish connections.
794 find_more_peers (void *cls,
795 const struct GNUNET_SCHEDULER_TaskContext *tc)
797 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Received shutdown request, stopping search for peers to connect to.\n");
805 discard_old_blacklist_entries ();
806 if (connection_count <= target_connection_count)
808 schedule_peer_search ();
811 if ( (GNUNET_YES == friends_only) ||
812 (friend_count < minimum_friend_count) )
815 schedule_peer_search ();
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
822 target_connection_count,
825 pitr_more = GNUNET_PEERINFO_iterate (cfg,
828 0, GNUNET_TIME_UNIT_FOREVER_REL,
829 &process_peer, NULL);
834 * Function called after GNUNET_CORE_connect has succeeded
835 * (or failed for good).
838 * @param server handle to the server, NULL if we failed
839 * @param my_id ID of this peer, NULL if we failed
840 * @param publicKey public key of this peer, NULL if we failed
843 core_init (void *cls,
844 struct GNUNET_CORE_Handle * server,
845 const struct GNUNET_PeerIdentity *
848 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
853 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
854 _("Failed to connect to core service, can not manage topology!\n"));
855 GNUNET_SCHEDULER_shutdown (sched);
859 my_identity = *my_id;
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
866 GNUNET_SCHEDULER_add_delayed (sched,
867 GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
874 * gnunet-daemon-topology command line options.
876 static struct GNUNET_GETOPT_CommandLineOption options[] = {
877 GNUNET_GETOPT_OPTION_END
882 * Read the friends file.
885 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
892 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
893 unsigned int entries_found;
897 GNUNET_CONFIGURATION_get_value_filename (cfg,
902 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
903 _("Option `%s' in section `%s' not specified!\n"),
908 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
909 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
910 | GNUNET_DISK_PERM_USER_WRITE);
911 if (0 != STAT (fn, &frstat))
913 if ((friends_only) || (minimum_friend_count > 0))
915 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
916 _("Could not read friends list `%s'\n"), fn);
921 if (frstat.st_size == 0)
923 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
924 _("Friends file `%s' is empty.\n"),
929 data = GNUNET_malloc_large (frstat.st_size);
930 if (frstat.st_size !=
931 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
934 _("Failed to read friends list from `%s'\n"), fn);
941 while ((pos < frstat.st_size) && isspace (data[pos]))
943 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
944 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
946 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
947 if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
949 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
950 _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
951 (unsigned long long) pos);
953 while ((pos < frstat.st_size) && (!isspace (data[pos])))
957 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
958 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
960 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
961 _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
962 (unsigned long long) pos,
968 fl = GNUNET_malloc (sizeof(struct PeerList));
969 fl->is_friend = GNUNET_YES;
970 fl->id.hashPubKey = hc;
974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 "Found friend `%s' in configuration\n",
976 GNUNET_i2s (&fl->id));
979 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
980 while ((pos < frstat.st_size) && isspace (data[pos]))
985 if ( (minimum_friend_count > entries_found) &&
986 (friends_only == GNUNET_NO) )
988 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
989 _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
991 if ( (minimum_friend_count > target_connection_count) &&
992 (friends_only == GNUNET_NO) )
994 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
995 _("More friendly connections required than target total number of connections.\n"));
1001 * This function is called whenever an encrypted HELLO message is
1004 * @param cls closure
1005 * @param other the other peer involved (sender or receiver, NULL
1006 * for loopback messages where we are both sender and receiver)
1007 * @param message the actual HELLO message
1008 * @return GNUNET_OK to keep the connection open,
1009 * GNUNET_SYSERR to close it (signal serious error)
1012 handle_encrypted_hello (void *cls,
1013 const struct GNUNET_PeerIdentity * other,
1014 const struct GNUNET_MessageHeader *
1018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1019 "Received encrypted `%s' from peer `%s'",
1021 GNUNET_i2s (other));
1023 if (transport != NULL)
1024 GNUNET_TRANSPORT_offer_hello (transport,
1031 * Peerinfo calls this function to let us know about a
1032 * possible peer that we might want to connect to.
1035 * @param peer NULL for the end of the list, otherwise a peer identity
1036 * @param hello a HELLO for a peer, or NULL
1037 * @param trust how much do we trust the given peer?
1040 gather_hello_callback (void *cls,
1041 const struct GNUNET_PeerIdentity *peer,
1042 const struct GNUNET_HELLO_Message *hello,
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Received `%s' for peer `%s'",
1057 consider_for_advertising (hello);
1061 // FIXME: this no longer works (no solicitation!)
1063 * Function to fill send buffer with HELLO.
1066 * @param receiver the receiver of the message
1067 * @param position is the reference to the
1068 * first unused position in the buffer where GNUnet is building
1070 * @param padding is the number of bytes left in that buffer.
1071 * @return the number of bytes written to
1072 * that buffer (must be a positive number).
1074 /* static */ unsigned int
1075 hello_advertising (void *cls,
1076 const struct GNUNET_PeerIdentity *
1081 struct PeerList *pl;
1082 struct HelloList *pos;
1083 struct HelloList *prev;
1084 struct HelloList *next;
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "Data solicited for `%s', considering sending `%s's",
1090 GNUNET_i2s (receiver),
1096 if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1105 /* find applicable HELLOs */
1108 while (NULL != (pos = next))
1112 GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1113 &receiver->hashPubKey))
1115 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1117 /* time to discard... */
1122 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1132 size = GNUNET_HELLO_size (pos->msg);
1135 memcpy (position, pos->msg, size);
1136 GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1137 &receiver->hashPubKey);
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1145 "Sending %u bytes of `%s's",
1146 (unsigned int) size,
1151 if ( (NULL == pitr) &&
1152 (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1153 MIN_HELLO_GATHER_DELAY.value) )
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 "Have no `%s's, trying to get some from `%s' for next time",
1161 last_hello_gather_time = GNUNET_TIME_absolute_get();
1162 pitr = GNUNET_PEERINFO_iterate (cfg,
1165 0, GNUNET_TIME_UNIT_FOREVER_REL,
1166 &gather_hello_callback, NULL);
1173 * Last task run during shutdown. Disconnects us from
1174 * the transport and core.
1177 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1179 struct PeerList *pl;
1181 if (NULL != peerinfo_notify)
1183 GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
1184 peerinfo_notify = NULL;
1188 GNUNET_PEERINFO_iterate_cancel (pitr);
1191 if (NULL != pitr_more)
1193 GNUNET_PEERINFO_iterate_cancel (pitr_more);
1196 GNUNET_TRANSPORT_disconnect (transport);
1200 GNUNET_CORE_disconnect (handle);
1203 while (NULL != (pl = friends))
1212 * Main function that will be run.
1214 * @param cls closure
1215 * @param s the scheduler to use
1216 * @param args remaining command-line arguments
1217 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1218 * @param c configuration
1222 struct GNUNET_SCHEDULER_Handle * s,
1224 const char *cfgfile,
1225 const struct GNUNET_CONFIGURATION_Handle * c)
1227 struct GNUNET_CORE_MessageHandler handlers[] =
1229 { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1232 unsigned long long opt;
1236 autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1239 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1243 GNUNET_CONFIGURATION_get_value_number (cfg,
1248 minimum_friend_count = (unsigned int) opt;
1250 GNUNET_CONFIGURATION_get_value_number (cfg,
1252 "TARGET-CONNECTION-COUNT",
1255 target_connection_count = (unsigned int) opt;
1257 if ( (friends_only == GNUNET_YES) ||
1258 (minimum_friend_count > 0) )
1259 read_friends_file (cfg);
1261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1262 "Topology would like %u connections with at least %u friends (%s)\n",
1263 target_connection_count,
1264 minimum_friend_count,
1265 autoconnect ? "autoconnect enabled" : "autoconnect disabled");
1267 transport = GNUNET_TRANSPORT_connect (sched,
1273 handle = GNUNET_CORE_connect (sched,
1275 GNUNET_TIME_UNIT_FOREVER_REL,
1283 GNUNET_SCHEDULER_add_delayed (sched,
1284 GNUNET_TIME_UNIT_FOREVER_REL,
1285 &cleaning_task, NULL);
1286 if (NULL == transport)
1288 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1289 _("Failed to connect to `%s' service.\n"),
1291 GNUNET_SCHEDULER_shutdown (sched);
1296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1297 _("Failed to connect to `%s' service.\n"),
1299 GNUNET_SCHEDULER_shutdown (sched);
1302 peerinfo_notify = GNUNET_PEERINFO_notify (cfg, sched,
1309 * The main function for the topology daemon.
1311 * @param argc number of arguments from the command line
1312 * @param argv command line arguments
1313 * @return 0 ok, 1 on error
1316 main (int argc, char *const *argv)
1321 GNUNET_PROGRAM_run (argc,
1324 _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1326 &run, NULL)) ? 0 : 1;
1330 /* end of gnunet-daemon-topology.c */