gnunet-daemon-topology.c   gnunet-daemon-topology.c 
skipping to change at line 26 skipping to change at line 26
along with GNUnet; see the file COPYING. If not, write to the along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330, Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. Boston, MA 02111-1307, USA.
*/ */
/** /**
* @file topology/gnunet-daemon-topology.c * @file topology/gnunet-daemon-topology.c
* @brief code for maintaining the mesh topology * @brief code for maintaining the mesh topology
* @author Christian Grothoff * @author Christian Grothoff
*/ */
#include <stdlib.h>
#include "platform.h" #include "platform.h"
#include "gnunet_constants.h" #include "gnunet_constants.h"
#include "gnunet_core_service.h" #include "gnunet_core_service.h"
#include "gnunet_protocols.h" #include "gnunet_protocols.h"
#include "gnunet_peerinfo_service.h" #include "gnunet_peerinfo_service.h"
#include "gnunet_statistics_service.h" #include "gnunet_statistics_service.h"
#include "gnunet_transport_service.h" #include "gnunet_transport_service.h"
#include "gnunet_util_lib.h" #include "gnunet_util_lib.h"
#define DEBUG_TOPOLOGY GNUNET_YES /**
* Minimum required delay between calls to GNUNET_TRANSPORT_try_connect.
*/
#define MAX_CONNECT_FREQUENCY_DELAY GNUNET_TIME_relative_multiply (GNUNET_T
IME_UNIT_MILLISECONDS, 250)
/** /**
* For how long do we blacklist a peer after a failed connection * For how long do we blacklist a peer after a failed connection
* attempt? * attempt? This is the baseline factor which is then multiplied by
* two to the power of the number of failed attempts.
*/ */
#define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_U NIT_MINUTES, 15) #define GREYLIST_AFTER_ATTEMPT GNUNET_TIME_relative_multiply (GNUNET_TIME_U NIT_MINUTES, 1)
/** /**
* For how long do we blacklist a friend after a failed connection * For how long do we blacklist a friend after a failed connection
* attempt? * attempt? This is the baseline factor which is then multiplied by
* two to the power of the number of failed attempts.
*/ */
#define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET _TIME_UNIT_MINUTES, 2) #define GREYLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET _TIME_UNIT_SECONDS, 2)
/** /**
* For how long do we blacklist anyone under any cirumstances after a faile * For how long do we blacklist anyone under any cirumstances at least afte
d connection r a failed connection
* attempt? * attempt? This is the absolute minimum, regardless of what the calculati
on based on
* exponential backoff returns.
*/ */
#define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TI ME_UNIT_SECONDS, 15) #define GREYLIST_AFTER_ATTEMPT_MIN GNUNET_TIME_relative_multiply (GNUNET_TI ME_UNIT_SECONDS, 5)
/** /**
* For how long do we blacklist anyone under any cirumstances after a faile * For how long do we blacklist anyone under any cirumstances at most after
d connection a failed connection
* attempt? * attempt? This is the absolute maximum, regardless of what the calculati
on based on
* exponential back-off returns.
*/ */
#define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TI ME_UNIT_HOURS, 1) #define GREYLIST_AFTER_ATTEMPT_MAX GNUNET_TIME_relative_multiply (GNUNET_TI ME_UNIT_HOURS, 1)
/** /**
* How often do we at most advertise any HELLO to a peer? * At what frequency do we sent HELLOs to a peer?
*/ */
#define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GN UNET_TIME_UNIT_HOURS, 4) #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GN UNET_TIME_UNIT_MINUTES, 5)
/** /**
* How often do we at most advertise the same HELLO to the same peer? * After what time period do we expire the HELLO Bloom filter?
*/ */
#define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multi ply (GNUNET_TIME_UNIT_HOURS, 4) #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY GNUNET_TIME_relative_multi ply (GNUNET_TIME_UNIT_HOURS, 4)
/** /**
* Record for neighbours, friends and blacklisted peers. * Record for neighbours, friends and blacklisted peers.
*/ */
struct Peer struct Peer
{ {
/** /**
* Which peer is this entry about? * Which peer is this entry about?
skipping to change at line 123 skipping to change at line 128
*/ */
struct GNUNET_TIME_Absolute filter_expiration; struct GNUNET_TIME_Absolute filter_expiration;
/** /**
* ID of task we use to wait for the time to send the next HELLO * ID of task we use to wait for the time to send the next HELLO
* to this peer. * to this peer.
*/ */
GNUNET_SCHEDULER_TaskIdentifier hello_delay_task; GNUNET_SCHEDULER_TaskIdentifier hello_delay_task;
/** /**
* Task for issuing GNUNET_TRANSPORT_try_connect for this peer.
*/
GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task;
/**
* ID of task we use to clear peers from the greylist. * ID of task we use to clear peers from the greylist.
*/ */
GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task; GNUNET_SCHEDULER_TaskIdentifier greylist_clean_task;
/** /**
* How often have we tried so far? * How often have we tried so far?
*/ */
unsigned int connect_attempts; unsigned int connect_attempts;
/** /**
skipping to change at line 188 skipping to change at line 198
* Handle for reporting statistics. * Handle for reporting statistics.
*/ */
static struct GNUNET_STATISTICS_Handle *stats; static struct GNUNET_STATISTICS_Handle *stats;
/** /**
* Blacklist (NULL if we have none). * Blacklist (NULL if we have none).
*/ */
static struct GNUNET_TRANSPORT_Blacklist *blacklist; static struct GNUNET_TRANSPORT_Blacklist *blacklist;
/** /**
* When can we next ask transport to create a connection?
*/
static struct GNUNET_TIME_Absolute next_connect_attempt;
/**
* Task scheduled to try to add peers. * Task scheduled to try to add peers.
*/ */
static GNUNET_SCHEDULER_TaskIdentifier add_task; static GNUNET_SCHEDULER_TaskIdentifier add_task;
/** /**
* Flag to disallow non-friend connections (pure F2F mode). * Flag to disallow non-friend connections (pure F2F mode).
*/ */
static int friends_only; static int friends_only;
/** /**
skipping to change at line 275 skipping to change at line 290
static int static int
is_connection_allowed (struct Peer *peer) is_connection_allowed (struct Peer *peer)
{ {
if (0 == if (0 ==
memcmp (&my_identity, &peer->pid, sizeof (struct GNUNET_PeerIdentity) )) memcmp (&my_identity, &peer->pid, sizeof (struct GNUNET_PeerIdentity) ))
return GNUNET_SYSERR; /* disallow connections to self */ return GNUNET_SYSERR; /* disallow connections to self */
if (peer->is_friend) if (peer->is_friend)
return GNUNET_OK; return GNUNET_OK;
if (GNUNET_YES == friends_only) if (GNUNET_YES == friends_only)
{ {
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Determined that `%s' is not allowed to connect (not a frie nd)\n", "Determined that `%s' is not allowed to connect (not a frie nd)\n",
GNUNET_i2s (&peer->pid)); GNUNET_i2s (&peer->pid));
#endif
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (friend_count >= minimum_friend_count) if (friend_count >= minimum_friend_count)
return GNUNET_OK; return GNUNET_OK;
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Determined that `%s' is not allowed to connect (not enough c onnected friends)\n", "Determined that `%s' is not allowed to connect (not enough c onnected friends)\n",
GNUNET_i2s (&peer->pid)); GNUNET_i2s (&peer->pid));
#endif
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/** /**
* Free all resources associated with the given peer. * Free all resources associated with the given peer.
* *
* @param cls closure (not used) * @param cls closure (not used)
* @param pid identity of the peer * @param pid identity of the peer
* @param value peer to free * @param value peer to free
* @return GNUNET_YES (always: continue to iterate) * @return GNUNET_YES (always: continue to iterate)
*/ */
static int static int
free_peer (void *cls, const GNUNET_HashCode * pid, void *value) free_peer (void *cls, const GNUNET_HashCode * pid, void *value)
{ {
struct Peer *pos = value; struct Peer *pos = value;
GNUNET_break (GNUNET_NO == pos->is_connected);
GNUNET_break (GNUNET_OK == GNUNET_break (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_remove (peers, pid, pos)); GNUNET_CONTAINER_multihashmap_remove (peers, pid, pos));
if (pos->hello_req != NULL) if (pos->hello_req != NULL)
GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req); GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (pos->hello_delay_task); GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
if (pos->attempt_connect_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (pos->attempt_connect_task);
if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
GNUNET_free_non_null (pos->hello); GNUNET_free_non_null (pos->hello);
if (pos->filter != NULL) if (pos->filter != NULL)
GNUNET_CONTAINER_bloomfilter_free (pos->filter); GNUNET_CONTAINER_bloomfilter_free (pos->filter);
GNUNET_free (pos); GNUNET_free (pos);
return GNUNET_YES; return GNUNET_YES;
} }
/** /**
skipping to change at line 365 skipping to change at line 379
if (pos->connect_attempts > 30) if (pos->connect_attempts > 30)
pos->connect_attempts = 30; pos->connect_attempts = 30;
rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts)) ; rem = GNUNET_TIME_relative_multiply (rem, 1 << (++pos->connect_attempts)) ;
rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN); rem = GNUNET_TIME_relative_max (rem, GREYLIST_AFTER_ATTEMPT_MIN);
rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX); rem = GNUNET_TIME_relative_min (rem, GREYLIST_AFTER_ATTEMPT_MAX);
pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem); pos->greylisted_until = GNUNET_TIME_relative_to_absolute (rem);
if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK) if (pos->greylist_clean_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (pos->greylist_clean_task); GNUNET_SCHEDULER_cancel (pos->greylist_clean_task);
pos->greylist_clean_task = pos->greylist_clean_task =
GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos);
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n", GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking to connect to `%s'\n",
GNUNET_i2s (&pos->pid)); GNUNET_i2s (&pos->pid));
#endif
GNUNET_STATISTICS_update (stats, GNUNET_STATISTICS_update (stats,
gettext_noop gettext_noop
("# connect requests issued to transport"), 1, ("# connect requests issued to transport"), 1,
GNUNET_NO); GNUNET_NO);
GNUNET_TRANSPORT_try_connect (transport, &pos->pid); GNUNET_TRANSPORT_try_connect (transport, &pos->pid);
} }
/** /**
* Try to connect to the specified peer.
*
* @param cls peer to connect to
* @param tc scheduler context
*/
static void
do_attempt_connect (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct Peer *pos = cls;
struct GNUNET_TIME_Relative delay;
pos->attempt_connect_task = GNUNET_SCHEDULER_NO_TASK;
if (GNUNET_YES == pos->is_connected)
return;
delay = GNUNET_TIME_absolute_get_remaining (next_connect_attempt);
if (delay.rel_value > 0)
{
pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (delay,
&do_attempt_co
nnect,
pos);
return;
}
next_connect_attempt = GNUNET_TIME_relative_to_absolute (MAX_CONNECT_FREQ
UENCY_DELAY);
attempt_connect (pos);
}
/**
* Schedule a task to try to connect to the specified peer.
*
* @param pos peer to connect to
*/
static void
schedule_attempt_connect (struct Peer *pos)
{
if (GNUNET_SCHEDULER_NO_TASK != pos->attempt_connect_task)
return;
pos->attempt_connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_abs
olute_get_remaining (next_connect_attempt),
&do_attempt_conn
ect,
pos);
}
/**
* Discard peer entries for greylisted peers * Discard peer entries for greylisted peers
* where the greylisting has expired. * where the greylisting has expired.
* *
* @param cls 'struct Peer' to greylist * @param cls 'struct Peer' to greylist
* @param tc scheduler context * @param tc scheduler context
*/ */
static void static void
remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) remove_from_greylist (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{ {
struct Peer *pos = cls; struct Peer *pos = cls;
struct GNUNET_TIME_Relative rem; struct GNUNET_TIME_Relative rem;
pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK; pos->greylist_clean_task = GNUNET_SCHEDULER_NO_TASK;
rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until); rem = GNUNET_TIME_absolute_get_remaining (pos->greylisted_until);
if (rem.rel_value == 0) if (rem.rel_value == 0)
{ {
attempt_connect (pos); schedule_attempt_connect (pos);
} }
else else
{ {
pos->greylist_clean_task = pos->greylist_clean_task =
GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos); GNUNET_SCHEDULER_add_delayed (rem, &remove_from_greylist, pos);
} }
if ((GNUNET_NO == pos->is_friend) && (GNUNET_NO == pos->is_connected) && if ((GNUNET_NO == pos->is_friend) && (GNUNET_NO == pos->is_connected) &&
(NULL == pos->hello)) (NULL == pos->hello))
{ {
free_peer (NULL, &pos->pid.hashPubKey, pos); free_peer (NULL, &pos->pid.hashPubKey, pos);
skipping to change at line 627 skipping to change at line 682
* @param atsi performance data * @param atsi performance data
* @param atsi_count number of records in 'atsi' * @param atsi_count number of records in 'atsi'
*/ */
static void static void
connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_ATS_Information *atsi, const struct GNUNET_ATS_Information *atsi,
unsigned int atsi_count) unsigned int atsi_count)
{ {
struct Peer *pos; struct Peer *pos;
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core told us that we are connecting to `%s'\n", "Core told us that we are connecting to `%s'\n",
GNUNET_i2s (peer)); GNUNET_i2s (peer));
#endif
if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)) ) if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)) )
return; return;
connection_count++; connection_count++;
GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"), GNUNET_STATISTICS_set (stats, gettext_noop ("# peers connected"),
connection_count, GNUNET_NO); connection_count, GNUNET_NO);
pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
if (pos == NULL) if (NULL == pos)
{ {
pos = make_peer (peer, NULL, GNUNET_NO); pos = make_peer (peer, NULL, GNUNET_NO);
GNUNET_break (GNUNET_OK == is_connection_allowed (pos)); GNUNET_break (GNUNET_OK == is_connection_allowed (pos));
} }
else else
{ {
GNUNET_assert (GNUNET_NO == pos->is_connected); GNUNET_assert (GNUNET_NO == pos->is_connected);
pos->greylisted_until.abs_value = 0; /* remove greylisting */ pos->greylisted_until.abs_value = 0; /* remove greylisting */
} }
pos->is_connected = GNUNET_YES; pos->is_connected = GNUNET_YES;
skipping to change at line 676 skipping to change at line 729
* @param cls closure, not used * @param cls closure, not used
* @param pid identity of a peer * @param pid identity of a peer
* @param value 'struct Peer*' for the peer * @param value 'struct Peer*' for the peer
* @return GNUNET_YES (continue to iterate) * @return GNUNET_YES (continue to iterate)
*/ */
static int static int
try_add_peers (void *cls, const GNUNET_HashCode * pid, void *value) try_add_peers (void *cls, const GNUNET_HashCode * pid, void *value)
{ {
struct Peer *pos = value; struct Peer *pos = value;
attempt_connect (pos); schedule_attempt_connect (pos);
return GNUNET_YES; return GNUNET_YES;
} }
/** /**
* Last task run during shutdown. Disconnects us from * Last task run during shutdown. Disconnects us from
* the transport and core. * the transport and core.
* *
* @param cls unused, NULL * @param cls unused, NULL
* @param tc scheduler context * @param tc scheduler context
*/ */
skipping to change at line 708 skipping to change at line 761
* @param cls closure * @param cls closure
* @param peer peer identity this notification is about * @param peer peer identity this notification is about
*/ */
static void static void
disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer) disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
{ {
struct Peer *pos; struct Peer *pos;
if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)) ) if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)) )
return; return;
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Core told us that we disconnected from `%s'\n", "Core told us that we disconnected from `%s'\n",
GNUNET_i2s (peer)); GNUNET_i2s (peer));
#endif
pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
if (pos == NULL) if (NULL == pos)
{ {
GNUNET_break (0); GNUNET_break (0);
return; return;
} }
if (pos->is_connected != GNUNET_YES) if (pos->is_connected != GNUNET_YES)
{ {
GNUNET_break (0); GNUNET_break (0);
return; return;
} }
pos->is_connected = GNUNET_NO; pos->is_connected = GNUNET_NO;
skipping to change at line 799 skipping to change at line 850
return; return;
} }
if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)) ) if (0 == memcmp (&pid, &my_identity, sizeof (struct GNUNET_PeerIdentity)) )
return; /* that's me! */ return; /* that's me! */
have_address = GNUNET_NO; have_address = GNUNET_NO;
GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator, GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &address_iterator,
&have_address); &have_address);
if (GNUNET_NO == have_address) if (GNUNET_NO == have_address)
return; /* no point in advertising this one... */ return; /* no point in advertising this one... */
peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey);
if (peer == NULL) if (NULL == peer)
{ {
peer = make_peer (&pid, hello, GNUNET_NO); peer = make_peer (&pid, hello, GNUNET_NO);
} }
else if (peer->hello != NULL) else if (peer->hello != NULL)
{ {
dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ()); dt = GNUNET_HELLO_equals (peer->hello, hello, GNUNET_TIME_absolute_get ());
if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value) if (dt.abs_value == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
return; /* nothing new here */ return; /* nothing new here */
} }
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found `%s' from peer `%s' for advertising\n", "HELLO", "Found `%s' from peer `%s' for advertising\n", "HELLO",
GNUNET_i2s (&pid)); GNUNET_i2s (&pid));
#endif
if (peer->hello != NULL) if (peer->hello != NULL)
{ {
nh = GNUNET_HELLO_merge (peer->hello, hello); nh = GNUNET_HELLO_merge (peer->hello, hello);
GNUNET_free (peer->hello); GNUNET_free (peer->hello);
peer->hello = nh; peer->hello = nh;
} }
else else
{ {
size = GNUNET_HELLO_size (hello); size = GNUNET_HELLO_size (hello);
peer->hello = GNUNET_malloc (size); peer->hello = GNUNET_malloc (size);
skipping to change at line 874 skipping to change at line 923
pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
if (NULL != pos) if (NULL != pos)
{ {
GNUNET_free_non_null (pos->hello); GNUNET_free_non_null (pos->hello);
pos->hello = NULL; pos->hello = NULL;
if (pos->filter != NULL) if (pos->filter != NULL)
{ {
GNUNET_CONTAINER_bloomfilter_free (pos->filter); GNUNET_CONTAINER_bloomfilter_free (pos->filter);
pos->filter = NULL; pos->filter = NULL;
} }
if ((!pos->is_connected) && (!pos->is_friend) && if ((GNUNET_NO == pos->is_connected) && (GNUNET_NO == pos->is_friend) &&
(0 == (0 ==
GNUNET_TIME_absolute_get_remaining (pos-> GNUNET_TIME_absolute_get_remaining (pos->
greylisted_until).rel_value) ) greylisted_until).rel_value) )
free_peer (NULL, &pos->pid.hashPubKey, pos); free_peer (NULL, &pos->pid.hashPubKey, pos);
} }
return; return;
} }
consider_for_advertising (hello); consider_for_advertising (hello);
pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey); pos = GNUNET_CONTAINER_multihashmap_get (peers, &peer->hashPubKey);
if (pos == NULL) if (pos == NULL)
pos = make_peer (peer, hello, GNUNET_NO); pos = make_peer (peer, hello, GNUNET_NO);
GNUNET_assert (NULL != pos); GNUNET_assert (NULL != pos);
if (GNUNET_YES == pos->is_connected) if (GNUNET_YES == pos->is_connected)
{ {
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n" , GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already connected to peer `%s'\n" ,
GNUNET_i2s (peer)); GNUNET_i2s (peer));
#endif
return; return;
} }
if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0) if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).rel_value > 0)
{ {
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\ n", GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Already tried peer `%s' recently\ n",
GNUNET_i2s (peer)); GNUNET_i2s (peer));
#endif
return; /* peer still greylisted */ return; /* peer still greylisted */
} }
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s' \n", GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering connecting to peer `%s' \n",
GNUNET_i2s (peer)); GNUNET_i2s (peer));
#endif schedule_attempt_connect (pos);
attempt_connect (pos);
} }
/** /**
* Function called after GNUNET_CORE_connect has succeeded * Function called after GNUNET_CORE_connect has succeeded
* (or failed for good). * (or failed for good).
* *
* @param cls closure * @param cls closure
* @param server handle to the server, NULL if we failed * @param server handle to the server, NULL if we failed
* @param my_id ID of this peer, NULL if we failed * @param my_id ID of this peer, NULL if we failed
*/ */
skipping to change at line 932 skipping to change at line 975
if (server == NULL) if (server == NULL)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_ _
("Failed to connect to core service, can not manage topolog y!\n")); ("Failed to connect to core service, can not manage topolog y!\n"));
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
handle = server; handle = server;
my_identity = *my_id; my_identity = *my_id;
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s (my_i d)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s (my_i d));
#endif
peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL); peerinfo_notify = GNUNET_PEERINFO_notify (cfg, &process_peer, NULL);
} }
/** /**
* Read the friends file. * Read the friends file.
*/ */
static void static void
read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg) read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
{ {
char *fn; char *fn;
char *data; char *data;
size_t pos; size_t pos;
struct GNUNET_PeerIdentity pid; struct GNUNET_PeerIdentity pid;
struct stat frstat; uint64_t fsize;
struct GNUNET_CRYPTO_HashAsciiEncoded enc; struct GNUNET_CRYPTO_HashAsciiEncoded enc;
unsigned int entries_found; unsigned int entries_found;
struct Peer *fl; struct Peer *fl;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn)) GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Option `%s' in section `%s' not specified!\n"), "FRIENDS ", _("Option `%s' in section `%s' not specified!\n"), "FRIENDS ",
"TOPOLOGY"); "TOPOLOGY");
return; return;
} }
if (GNUNET_OK != GNUNET_DISK_file_test (fn)) if (GNUNET_OK != GNUNET_DISK_file_test (fn))
GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_fn_write (fn, NULL, 0,
GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_READ |
GNUNET_DISK_PERM_USER_WRITE); GNUNET_DISK_PERM_USER_WRITE);
if (0 != STAT (fn, &frstat)) if (GNUNET_OK != GNUNET_DISK_file_size (fn,
&fsize, GNUNET_NO, GNUNET_YES))
{ {
if ((friends_only) || (minimum_friend_count > 0)) if ((friends_only) || (minimum_friend_count > 0))
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not read friends list `%s'\n"), fn); _("Could not read friends list `%s'\n"), fn);
GNUNET_free (fn); GNUNET_free (fn);
return; return;
} }
if (frstat.st_size == 0) if (fsize == 0)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Friends file `%s' is empty.\n "), GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Friends file `%s' is empty.\n "),
fn); fn);
GNUNET_free (fn); GNUNET_free (fn);
return; return;
} }
data = GNUNET_malloc_large (frstat.st_size); data = GNUNET_malloc_large (fsize);
if (data == NULL) if (data == NULL)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Failed to read friends list from `%s': out of memory\n") , _("Failed to read friends list from `%s': out of memory\n") ,
fn); fn);
GNUNET_free (fn); GNUNET_free (fn);
return; return;
} }
if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size)) if (fsize != GNUNET_DISK_fn_read (fn, data, fsize))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Failed to read friends list from `%s'\n"), fn); _("Failed to read friends list from `%s'\n"), fn);
GNUNET_free (fn); GNUNET_free (fn);
GNUNET_free (data); GNUNET_free (data);
return; return;
} }
entries_found = 0; entries_found = 0;
pos = 0; pos = 0;
while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) while ((pos < fsize) && isspace ((unsigned char) data[pos]))
pos++; pos++;
while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
(pos <= (pos <=
frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
{ {
memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded )); memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded ));
if (!isspace if (!isspace
((unsigned char) ((unsigned char)
enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_ _
("Syntax error in topology specification at offset %llu, skipping bytes.\n"), ("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
(unsigned long long) pos); (unsigned long long) pos);
pos++; pos++;
while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos] ))) while ((pos < fsize) && (!isspace ((unsigned char) data[pos])))
pos++; pos++;
continue; continue;
} }
enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0' ; enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0' ;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_ _
("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"), ("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
skipping to change at line 1046 skipping to change at line 1088
GNUNET_i2s (&fl->pid)); GNUNET_i2s (&fl->pid));
} }
else else
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_("Found myself `%s' in friend list (useless, ignored)\ n"), _("Found myself `%s' in friend list (useless, ignored)\ n"),
GNUNET_i2s (&pid)); GNUNET_i2s (&pid));
} }
} }
pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos])) while ((pos < fsize) && isspace ((unsigned char) data[pos]))
pos++; pos++;
} }
GNUNET_free (data); GNUNET_free (data);
GNUNET_free (fn); GNUNET_free (fn);
GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuratio n"), GNUNET_STATISTICS_update (stats, gettext_noop ("# friends in configuratio n"),
entries_found, GNUNET_NO); entries_found, GNUNET_NO);
if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO) ) if ((minimum_friend_count > entries_found) && (friends_only == GNUNET_NO) )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
_ _
skipping to change at line 1090 skipping to change at line 1132
*/ */
static int static int
handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other, handle_encrypted_hello (void *cls, const struct GNUNET_PeerIdentity *other,
const struct GNUNET_MessageHeader *message, const struct GNUNET_MessageHeader *message,
const struct GNUNET_ATS_Information *atsi, const struct GNUNET_ATS_Information *atsi,
unsigned int atsi_count) unsigned int atsi_count)
{ {
struct Peer *peer; struct Peer *peer;
struct GNUNET_PeerIdentity pid; struct GNUNET_PeerIdentity pid;
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer ` %s'", GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received encrypted `%s' from peer ` %s'",
"HELLO", GNUNET_i2s (other)); "HELLO", GNUNET_i2s (other));
#endif
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, & pid)) GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, & pid))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received "), GNUNET_STATISTICS_update (stats, gettext_noop ("# HELLO messages received "),
1, GNUNET_NO); 1, GNUNET_NO);
peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey);
if (peer == NULL) if (NULL == peer)
{ {
if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_coun t)) if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_coun t))
return GNUNET_OK; return GNUNET_OK;
} }
else else
{ {
if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only)) if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only))
return GNUNET_OK; return GNUNET_OK;
if ((GNUNET_YES != peer->is_friend) && if ((GNUNET_YES != peer->is_friend) &&
(friend_count < minimum_friend_count)) (friend_count < minimum_friend_count))
skipping to change at line 1151 skipping to change at line 1191
fah.max_size = size; fah.max_size = size;
fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL; fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, & fah); GNUNET_CONTAINER_multihashmap_iterate (peers, &find_advertisable_hello, & fah);
want = 0; want = 0;
if (fah.result != NULL) if (fah.result != NULL)
{ {
want = GNUNET_HELLO_size (fah.result->hello); want = GNUNET_HELLO_size (fah.result->hello);
GNUNET_assert (want <= size); GNUNET_assert (want <= size);
memcpy (buf, fah.result->hello, want); memcpy (buf, fah.result->hello, want);
GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubK ey); GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &pl->pid.hashPubK ey);
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HEL LO", GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' with %u bytes", "HEL LO",
(unsigned int) want); (unsigned int) want);
#endif
GNUNET_STATISTICS_update (stats, GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLO messages gossipped"), 1, gettext_noop ("# HELLO messages gossipped"), 1,
GNUNET_NO); GNUNET_NO);
} }
if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK) if (pl->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (pl->hello_delay_task); GNUNET_SCHEDULER_cancel (pl->hello_delay_task);
pl->next_hello_allowed = pl->next_hello_allowed =
GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY); GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl ); pl->hello_delay_task = GNUNET_SCHEDULER_add_now (&schedule_next_hello, pl );
skipping to change at line 1183 skipping to change at line 1221
* @param tc scheduler context * @param tc scheduler context
*/ */
static void static void
cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{ {
if (NULL != peerinfo_notify) if (NULL != peerinfo_notify)
{ {
GNUNET_PEERINFO_notify_cancel (peerinfo_notify); GNUNET_PEERINFO_notify_cancel (peerinfo_notify);
peerinfo_notify = NULL; peerinfo_notify = NULL;
} }
if (GNUNET_SCHEDULER_NO_TASK != add_task)
{
GNUNET_SCHEDULER_cancel (add_task);
add_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_TRANSPORT_disconnect (transport); GNUNET_TRANSPORT_disconnect (transport);
transport = NULL; transport = NULL;
GNUNET_CONTAINER_multihashmap_iterate (peers, &free_peer, NULL);
GNUNET_CONTAINER_multihashmap_destroy (peers);
if (handle != NULL) if (handle != NULL)
{ {
GNUNET_CORE_disconnect (handle); GNUNET_CORE_disconnect (handle);
handle = NULL; handle = NULL;
} }
whitelist_peers (); whitelist_peers ();
if (GNUNET_SCHEDULER_NO_TASK != add_task)
{
GNUNET_SCHEDULER_cancel (add_task);
add_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_CONTAINER_multihashmap_iterate (peers, &free_peer, NULL);
GNUNET_CONTAINER_multihashmap_destroy (peers);
peers = NULL;
if (stats != NULL) if (stats != NULL)
{ {
GNUNET_STATISTICS_destroy (stats, GNUNET_NO); GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL; stats = NULL;
} }
} }
/** /**
* Main function that will be run. * Main function that will be run.
* *
skipping to change at line 1243 skipping to change at line 1282
minimum_friend_count = (unsigned int) opt; minimum_friend_count = (unsigned int) opt;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY", GNUNET_CONFIGURATION_get_value_number (cfg, "TOPOLOGY",
"TARGET-CONNECTION-COUNT", &op t)) "TARGET-CONNECTION-COUNT", &op t))
opt = 16; opt = 16;
target_connection_count = (unsigned int) opt; target_connection_count = (unsigned int) opt;
peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2 ); peers = GNUNET_CONTAINER_multihashmap_create (target_connection_count * 2 );
if ((friends_only == GNUNET_YES) || (minimum_friend_count > 0)) if ((friends_only == GNUNET_YES) || (minimum_friend_count > 0))
read_friends_file (cfg); read_friends_file (cfg);
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Topology would like %u connections with at least %u friends (%s)\n", "Topology would like %u connections with at least %u friends (%s)\n",
target_connection_count, minimum_friend_count, target_connection_count, minimum_friend_count,
autoconnect ? "autoconnect enabled" : "autoconnect disabled") ; autoconnect ? "autoconnect enabled" : "autoconnect disabled") ;
#endif
if ((friend_count < minimum_friend_count) && (blacklist == NULL)) if ((friend_count < minimum_friend_count) && (blacklist == NULL))
blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL); blacklist = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_check, NULL);
transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL); transport = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL, NULL, NULL);
handle = handle =
GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_notify, GNUNET_CORE_connect (cfg, 1, NULL, &core_init, &connect_notify,
&disconnect_notify, NULL, GNUNET_NO, NULL, GNUNE T_NO, &disconnect_notify, NULL, GNUNET_NO, NULL, GNUNE T_NO,
handlers); handlers);
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_tas k, GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_tas k,
NULL); NULL);
if (NULL == transport) if (NULL == transport)
 End of changes. 63 change blocks. 
68 lines changed or deleted 112 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/