📄 topology.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2006, 2007 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file topology_default/topology.c * @brief create the GNUnet mesh topology (essentially, * try to connect to a large diverse, random set of peers) * @author Christian Grothoff * * Topology is implemented as both a service and an * application to allow users to force loading it * (which is probably a very good idea -- otherwise * the peer will end up rather disconnected :-) */#include "platform.h"#include "gnunet_core.h"#include "gnunet_directories.h"#include "gnunet_protocols.h"#include "gnunet_identity_service.h"#include "gnunet_state_service.h"#include "gnunet_topology_service.h"#include "gnunet_transport_service.h"#include "gnunet_pingpong_service.h"#define DEBUG_TOPOLOGY GNUNET_NO#define DEBUG_LIVENESS GNUNET_NO/** * After 2 minutes on an inactive connection, probe the other * node with a ping if we have achieved less than 50% of our * connectivity goal. */#define SECONDS_PINGATTEMPT 120/** * How often should the cron-job scan for free slots (to establish * new connections)? */#define LIVE_SCAN_FREQUENCY 500 * GNUNET_CRON_MILLISECONDS/** * Value > 1 that determines the chance (1:LSE) that the cron job * actually tries to do something for a given slot. */#define LIVE_SCAN_EFFECTIVENESS 10/** * Value < 1 that determines the chance (1:LPE) that the cron job * actually tries to ping a peer that is about to time-out. */#define LIVE_PING_EFFECTIVENESS 20static GNUNET_CoreAPIForPlugins *coreAPI;static GNUNET_Identity_ServiceAPI *identity;static GNUNET_Transport_ServiceAPI *transport;static GNUNET_Pingpong_ServiceAPI *pingpong;/** * How many peers are we connected to in relation * to our ideal number? (ideal = 1.0, too few: < 1, * too many: > 1). Maybe 0! */static double saturation = 0.0;/** * Array of our friends. */static GNUNET_PeerIdentity *friends;/** * Number of friends that we have. */static unsigned int friendCount;/** * Minimum number of friends to have in the * connection set. */static unsigned int minimum_friend_count;/** * Flag to disallow non-friend connections (pure F2F mode). */static int friends_only;/** * Record for state maintanance between scanHelperCount, * scanHelperSelect and scanForHosts. */typedef struct{ unsigned int index; unsigned int matchCount; long long costSelector; GNUNET_PeerIdentity match;} IndexMatch;/** * Here in this scanning for applicable hosts, we also want to take * the protocols into account and prefer "cheap" protocols, * i.e. protocols with a low overhead. * * @param id which peer are we currently looking at * @param proto what transport protocol are we looking at * @param im updated structure used to select the peer */static intscanHelperCount (const GNUNET_PeerIdentity * id, unsigned short proto, int confirmed, void *data){ IndexMatch *im = data; if (0 == memcmp (coreAPI->my_identity, id, sizeof (GNUNET_PeerIdentity))) return GNUNET_OK; if (coreAPI->core_slot_index_get (id) != im->index) return GNUNET_OK; if (GNUNET_OK == coreAPI->p2p_connection_status_check (id, NULL, NULL)) return GNUNET_OK; if (GNUNET_YES == transport->test_available (proto)) { im->matchCount++; im->costSelector += transport->cost_get (proto); } return GNUNET_OK;}/** * Select the peer and transport that was selected based on transport * cost. * * @param id the current peer * @param proto the protocol of the current peer * @param im structure responsible for the selection process */static intscanHelperSelect (const GNUNET_PeerIdentity * id, unsigned short proto, int confirmed, void *data){ IndexMatch *im = data; if (0 == memcmp (coreAPI->my_identity, id, sizeof (GNUNET_PeerIdentity))) return GNUNET_OK; if (coreAPI->core_slot_index_get (id) != im->index) return GNUNET_OK; if (GNUNET_OK == coreAPI->p2p_connection_status_check (id, NULL, NULL)) return GNUNET_OK; if (GNUNET_YES == transport->test_available (proto)) { im->costSelector -= transport->cost_get (proto); if ((im->matchCount == 0) || (im->costSelector < 0)) { im->match = *id; return GNUNET_SYSERR; } im->matchCount--; } return GNUNET_OK;}/** * Look in the list for known hosts; pick a random host of minimal * transport cost for the hosttable at index index. When called, the * mutex of at the given index must not be hold. * * @param index for which entry in the connection table * are we looking for peers? */static voidscanForHosts (unsigned int index){ IndexMatch indexMatch; GNUNET_CronTime now;#if DEBUG_TOPOLOGY GNUNET_EncName enc;#endif if (GNUNET_network_monitor_get_load (coreAPI->load_monitor, GNUNET_ND_UPLOAD) > 100) return; /* bandwidth saturated, do not push it higher! */ now = GNUNET_get_time (); indexMatch.index = index; indexMatch.matchCount = 0; indexMatch.costSelector = 0; identity->forEachHost (now, &scanHelperCount, &indexMatch); if (indexMatch.matchCount == 0) {#if DEBUG_TOPOLOGY GNUNET_GE_LOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, "No peers found for slot %u\n", index);#endif return; /* no matching peers found! */ } if (indexMatch.costSelector > 0) indexMatch.costSelector = GNUNET_random_u64 (GNUNET_RANDOM_QUALITY_WEAK, indexMatch.costSelector); indexMatch.match = *(coreAPI->my_identity); identity->forEachHost (now, &scanHelperSelect, &indexMatch); if (0 == memcmp (coreAPI->my_identity, &indexMatch.match, sizeof (GNUNET_PeerIdentity))) return; /* should happen really rarely */ if (coreAPI->core_slot_index_get (&indexMatch.match) != index) { GNUNET_GE_BREAK (NULL, 0); /* should REALLY not happen */ return; } if (GNUNET_OK == coreAPI->p2p_connection_status_check (&indexMatch.match, NULL, NULL)) { GNUNET_GE_BREAK (NULL, 0); /* should REALLY not happen */ return; }#if DEBUG_TOPOLOGY IF_GELOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER | GNUNET_GE_DEVELOPER, GNUNET_hash_to_enc (&indexMatch.match.hashPubKey, &enc)); GNUNET_GE_LOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER | GNUNET_GE_DEVELOPER, "Trying to connect to peer `%s'\n", &enc);#endif if (GNUNET_NO == identity->isBlacklisted (&indexMatch.match, GNUNET_YES)) { coreAPI->ciphertext_send (&indexMatch.match, NULL, 0, 0); identity->blacklistHost (&indexMatch.match, (unsigned int) (saturation * 5 * 60 * 60), /* 5 hours at full saturation */ GNUNET_NO); }}/** * We received a GNUNET_RSA_sign of life from this host. * * @param hostId the peer that gave a GNUNET_RSA_sign of live */static voidnotifyPONG (void *cls){ GNUNET_PeerIdentity *hostId = cls;#if DEBUG_TOPOLOGY || DEBUG_LIVENESS GNUNET_EncName enc; IF_GELOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, GNUNET_hash_to_enc (&hostId->hashPubKey, &enc)); GNUNET_GE_LOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, "Received liveness confirmation from `%s'.\n", &enc);#endif coreAPI->p2p_connection_confirm (hostId); GNUNET_free (hostId);}/** * Check the liveness of the peer and possibly ping it. */static voidcheckNeedForPing (const GNUNET_PeerIdentity * peer, void *unused){ GNUNET_CronTime now; GNUNET_CronTime act; GNUNET_PeerIdentity *hi; int ran; ran = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, LIVE_PING_EFFECTIVENESS); if (ran != 0) return; now = GNUNET_get_time (); if (GNUNET_SYSERR == coreAPI->p2p_connection_last_activity_get (peer, &act)) { GNUNET_GE_BREAK (coreAPI->ectx, 0); return; /* this should not happen... */ } if (now - act > SECONDS_PINGATTEMPT * GNUNET_CRON_SECONDS) { /* if we have less than 75% of the number of connections that we would like to have, try ping-ing the other side to keep the connection open instead of hanging up */#if DEBUG_TOPOLOGY || DEBUG_LIVENESS GNUNET_EncName enc; IF_GELOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, GNUNET_hash_to_enc (&peer->hashPubKey, &enc)); GNUNET_GE_LOG (coreAPI->ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, "Peer `%s' was inactive for %llus. Sending PING.\n", &enc, (now - act) / GNUNET_CRON_SECONDS);#endif hi = GNUNET_malloc (sizeof (GNUNET_PeerIdentity)); *hi = *peer; if (GNUNET_OK != pingpong->ping (peer, ¬ifyPONG, hi, GNUNET_NO, rand ())) GNUNET_free (hi); }}#define MAX_PEERS_PER_SLOT 10/** * Call this method periodically to decrease liveness of hosts. * * @param unused not used, just to make signature type nicely */static voidcronCheckLiveness (void *unused){ int i; int slotCount; int active; unsigned int minint; int autoconnect; autoconnect = GNUNET_GC_get_configuration_value_yesno (coreAPI->cfg, "GNUNETD", "DISABLE-AUTOCONNECT", GNUNET_NO); slotCount = coreAPI->core_slots_count (); if ((GNUNET_NO == autoconnect) && (saturation < 1)) { if (saturation * MAX_PEERS_PER_SLOT >= 1) minint = (unsigned int) (1 / saturation); else minint = MAX_PEERS_PER_SLOT; /* never put more than 10 peers into a slot */ for (i = slotCount - 1; i >= 0; i--) { if (GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, LIVE_SCAN_EFFECTIVENESS) != 0) continue; if (minint > coreAPI->core_slot_test_used (i)) scanForHosts (i); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -