2 // This file is part of aMule Project
4 // Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2003-2011 Barry Dunne ( http://www.emule-project.net )
7 // Copyright (C)2007-2011 Merkur ( strEmail.Format("%s@%s", "devteam", "emule-project.net") / http://www.emule-project.net )
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 // This work is based on the java implementation of the Kademlia protocol.
24 // Kademlia: Peer-to-peer routing based on the XOR metric
25 // Copyright (c) 2002-2011 Petar Maymounkov ( petar@post.harvard.edu )
26 // http://kademlia.scs.cs.nyu.edu
30 Please do not change anything here and release it..
31 There is going to be a new forum created just for the Kademlia side of the client..
32 If you feel there is an error or a way to improve something, please
33 post it in the forum first and let us look at it.. If it is a real improvement,
34 it will be added to the offical client.. Changing something without knowing
35 what all it does can cause great harm to the network if released in mass form..
36 Any mod that changes anything within the Kademlia side will not be allowed to advertise
37 there client on the eMule forum..
41 * The *Zone* is just a node in a binary tree of *Zone*s.
42 * Each zone is either an internal node or a leaf node.
43 * Internal nodes have "bin == null" and "subZones[i] != null",
44 * leaf nodes have "subZones[i] == null" and "bin != null".
46 * All key unique id's are relative to the center (self), which
47 * is considered to be 000..000
49 #include "RoutingZone.h"
51 #include <protocol/kad/Client2Client/UDP.h>
52 #include <protocol/kad2/Client2Client/UDP.h>
53 #include <common/Macros.h>
56 #include "RoutingBin.h"
57 #include "../kademlia/Defines.h"
58 #include "../kademlia/SearchManager.h"
59 #include "../kademlia/UDPFirewallTester.h"
60 #include "../net/KademliaUDPListener.h"
61 #include "../utils/KadUDPKey.h"
62 #include "../../amule.h"
63 #include "../../CFile.h"
64 #include "../../Logger.h"
65 #include "../../NetworkFunctions.h"
66 #include "../../IPFilter.h"
67 #include "../../RandomFunctions.h"
71 ////////////////////////////////////////
72 using namespace Kademlia
;
73 ////////////////////////////////////////
75 // This is just a safety precaution
76 #define CONTACT_FILE_LIMIT 500
78 wxString
CRoutingZone::m_filename
;
79 CUInt128
CRoutingZone::me((uint32_t)0);
81 CRoutingZone::CRoutingZone()
83 // Can only create routing zone after prefs
84 // Set our KadID for creating the contact tree
85 me
= CKademlia::GetPrefs()->GetKadID();
86 // Set the preference file name.
87 m_filename
= theApp
->ConfigDir
+ wxT("nodes.dat");
88 Init(NULL
, 0, CUInt128((uint32_t)0));
91 void CRoutingZone::Init(CRoutingZone
*super_zone
, int level
, const CUInt128
& zone_index
)
94 // Set this zone's parent
95 m_superZone
= super_zone
;
96 // Set this zone's level
98 // Set this zone's CUInt128 index
99 m_zoneIndex
= zone_index
;
100 // Mark this zone as having no leafs.
101 m_subZones
[0] = NULL
;
102 m_subZones
[1] = NULL
;
103 // Create a new contact bin as this is a leaf.
104 m_bin
= new CRoutingBin();
106 // Set timer so that zones closer to the root are processed earlier.
107 m_nextSmallTimer
= time(NULL
) + m_zoneIndex
.Get32BitChunk(3);
112 // If we are initializing the root node, read in our saved contact list.
113 if ((m_superZone
== NULL
) && (m_filename
.Length() > 0)) {
118 CRoutingZone::~CRoutingZone()
120 // Root node is processed first so that we can write our contact list and delete all branches.
121 if ((m_superZone
== NULL
) && (m_filename
.Length() > 0)) {
125 // If this zone is a leaf, delete our contact bin.
129 // If this zone is a branch, delete its leafs.
130 delete m_subZones
[0];
131 delete m_subZones
[1];
135 void CRoutingZone::ReadFile(const wxString
& specialNodesdat
)
137 if (m_superZone
!= NULL
|| (m_filename
.IsEmpty() && specialNodesdat
.IsEmpty())) {
142 bool doHaveVerifiedContacts
= false;
143 // Read in the saved contact list
145 uint32_t numContacts
= 0;
146 uint32_t validContacts
= 0;
148 if (CPath::FileExists(specialNodesdat
.IsEmpty() ? m_filename
: specialNodesdat
) && file
.Open(m_filename
, CFile::read
)) {
149 // Get how many contacts in the saved list.
150 // NOTE: Older clients put the number of contacts here...
151 // Newer clients always have 0 here to prevent older clients from reading it.
152 numContacts
= file
.ReadUInt32();
153 uint32_t fileVersion
= 0;
154 if (numContacts
== 0) {
155 if (file
.GetLength() >= 8) {
156 fileVersion
= file
.ReadUInt32();
157 if (fileVersion
== 3) {
158 uint32_t bootstrapEdition
= file
.ReadUInt32();
159 if (bootstrapEdition
== 1) {
160 // this is a special bootstrap-only nodes.dat, handle it in a separate reading function
161 ReadBootstrapNodesDat(file
);
166 if (fileVersion
>= 1 && fileVersion
<= 3) {
167 numContacts
= file
.ReadUInt32();
171 // Don't read version 0 nodes.dat files, because they can't tell the kad version of the contacts stored.
172 AddLogLineC(_("Failed to read nodes.dat file - too old. This version (0) is not supported anymore."));
175 DEBUG_ONLY( unsigned kad1Count
= 0; )
176 if (numContacts
!= 0 && numContacts
* 25 <= (file
.GetLength() - file
.GetPosition())) {
177 for (uint32_t i
= 0; i
< numContacts
; i
++) {
178 CUInt128 id
= file
.ReadUInt128();
179 uint32_t ip
= file
.ReadUInt32();
180 uint16_t udpPort
= file
.ReadUInt16();
181 uint16_t tcpPort
= file
.ReadUInt16();
182 uint8_t contactVersion
= 0;
183 contactVersion
= file
.ReadUInt8();
184 CKadUDPKey kadUDPKey
;
185 bool verified
= false;
186 if (fileVersion
>= 2) {
187 kadUDPKey
.ReadFromFile(file
);
188 verified
= file
.ReadUInt8() != 0;
190 doHaveVerifiedContacts
= true;
194 if (contactVersion
> 1) {
195 if(IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip
),udpPort
)) {
196 if (!theApp
->ipfilter
->IsFiltered(wxUINT32_SWAP_ALWAYS(ip
)) &&
197 !(udpPort
== 53 && contactVersion
<= 5 /*No DNS Port without encryption*/)) {
198 // This was not a dead contact, inc counter if add was successful
199 if (AddUnfiltered(id
, ip
, udpPort
, tcpPort
, contactVersion
, kadUDPKey
, verified
, false, false)) {
205 DEBUG_ONLY( kad1Count
++; )
210 AddLogLineN(CFormat(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", validContacts
)) % validContacts
);
213 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Ignored %u kad1 %s in nodes.dat file.")) % kad1Count
% (kad1Count
> 1 ? wxT("contacts"): wxT("contact")));
216 if (!doHaveVerifiedContacts
) {
217 AddDebugLogLineN(logKadRouting
, wxT("No verified contacts found in nodes.dat - might be an old file version. Setting all contacts verified for this time to speed up Kad bootstrapping."));
218 SetAllContactsVerified();
221 if (validContacts
== 0) {
222 AddLogLineC(_("No contacts found, please bootstrap, or download a nodes.dat file."));
224 } catch (const CSafeIOException
& DEBUG_ONLY(e
)) {
225 AddDebugLogLineN(logKadRouting
, wxT("IO error in CRoutingZone::readFile: ") + e
.what());
229 void CRoutingZone::ReadBootstrapNodesDat(CFileDataIO
& file
)
231 // Bootstrap versions of nodes.dat files are in the style of version 1 nodes.dats. The difference is that
232 // they will contain more contacts, 500-1000 instead of 50, and those contacts are not added into the routing table
233 // but used to sent Bootstrap packets to. The advantage is that on a list with a high ratio of dead nodes,
234 // we will be able to bootstrap faster than on a normal nodes.dat and more important, if we would deliver
235 // a normal nodes.dat with eMule, those 50 nodes would be kinda DDOSed because everyone adds them to their routing
236 // table, while with this style, we don't actually add any of the contacts to our routing table in the end and we
237 // ask only one of those 1000 contacts one time (well or more until we find an alive one).
238 if (!CKademlia::s_bootstrapList
.empty()){
242 uint32_t numContacts
= file
.ReadUInt32();
243 if (numContacts
!= 0 && numContacts
* 25 == (file
.GetLength() - file
.GetPosition())) {
244 uint32_t validContacts
= 0;
245 while (numContacts
) {
246 CUInt128 id
= file
.ReadUInt128();
247 uint32_t ip
= file
.ReadUInt32();
248 uint16_t udpPort
= file
.ReadUInt16();
249 uint16_t tcpPort
= file
.ReadUInt16();
250 uint8_t contactVersion
= file
.ReadUInt8();
252 if (::IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip
), udpPort
)) {
253 if (!theApp
->ipfilter
->IsFiltered(wxUINT32_SWAP_ALWAYS(ip
)) &&
254 !(udpPort
== 53 && contactVersion
<= 5) &&
255 (contactVersion
> 1)) // only kad2 nodes
257 // we want the 50 nodes closest to our own ID (provides randomness between different users and gets has good chances to get a bootstrap with close Nodes which is a nice start for our routing table)
258 CUInt128 distance
= me
;
261 // don't bother if we already have 50 and the farest distance is smaller than this contact
262 if (CKademlia::s_bootstrapList
.size() < 50 || CKademlia::s_bootstrapList
.back()->GetDistance() > distance
) {
263 // look where to put this contact into the proper position
264 bool inserted
= false;
265 CContact
* contact
= new CContact(id
, ip
, udpPort
, tcpPort
, contactVersion
, 0, false, me
);
266 for (ContactList::iterator it
= CKademlia::s_bootstrapList
.begin(); it
!= CKademlia::s_bootstrapList
.end(); ++it
) {
267 if ((*it
)->GetDistance() > distance
) {
268 CKademlia::s_bootstrapList
.insert(it
, contact
);
274 wxASSERT(CKademlia::s_bootstrapList
.size() < 50);
275 CKademlia::s_bootstrapList
.push_back(contact
);
276 } else if (CKademlia::s_bootstrapList
.size() > 50) {
277 delete CKademlia::s_bootstrapList
.back();
278 CKademlia::s_bootstrapList
.pop_back();
285 AddLogLineN(CFormat(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", CKademlia::s_bootstrapList
.size())) % CKademlia::s_bootstrapList
.size());
286 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Loaded Bootstrap nodes.dat, selected %u out of %u valid contacts")) % CKademlia::s_bootstrapList
.size() % validContacts
);
288 if (CKademlia::s_bootstrapList
.size() == 0) {
289 AddLogLineC(_("No contacts found, please bootstrap, or download a nodes.dat file."));
293 void CRoutingZone::WriteFile()
295 // don't overwrite a bootstrap nodes.dat with an empty one, if we didn't finish probing
296 if (!CKademlia::s_bootstrapList
.empty() && GetNumContacts() == 0) {
297 AddDebugLogLineN(logKadRouting
, wxT("Skipped storing nodes.dat, because we have an unfinished bootstrap of the nodes.dat version and no contacts in our routing table"));
301 // The bootstrap method gets a very nice sample of contacts to save.
302 ContactList contacts
;
303 GetBootstrapContacts(&contacts
, 200);
304 ContactList::size_type numContacts
= contacts
.size();
305 numContacts
= std::min
<ContactList::size_type
>(numContacts
, CONTACT_FILE_LIMIT
); // safety precaution, should not be above
306 if (numContacts
< 25) {
307 AddLogLineN(CFormat(wxPLURAL("Only %d Kad contact available, nodes.dat not written", "Only %d Kad contacts available, nodes.dat not written", numContacts
)) % numContacts
);
311 unsigned int count
= 0;
313 if (file
.Open(m_filename
, CFile::write_safe
)) {
314 // Start file with 0 to prevent older clients from reading it.
316 // Now tag it with a version which happens to be 2.
318 // file.WriteUInt32(0); // if we would use version >= 3 this would mean that this is a normal nodes.dat
319 file
.WriteUInt32(numContacts
);
320 for (ContactList::const_iterator it
= contacts
.begin(); it
!= contacts
.end(); ++it
) {
323 if (count
> CONTACT_FILE_LIMIT
) {
324 // This should never happen
328 file
.WriteUInt128(c
->GetClientID());
329 file
.WriteUInt32(c
->GetIPAddress());
330 file
.WriteUInt16(c
->GetUDPPort());
331 file
.WriteUInt16(c
->GetTCPPort());
332 file
.WriteUInt8(c
->GetVersion());
333 c
->GetUDPKey().StoreToFile(file
);
334 file
.WriteUInt8(c
->IsIPVerified() ? 1 : 0);
338 AddLogLineN(CFormat(wxPLURAL("Wrote %d Kad contact", "Wrote %d Kad contacts", count
)) % count
);
339 } catch (const CIOFailureException
& e
) {
340 AddDebugLogLineC(logKadRouting
, wxT("IO failure in CRoutingZone::writeFile: ") + e
.what());
345 void CRoutingZone::WriteBootstrapFile()
347 AddDebugLogLineC(logKadRouting
, wxT("Writing special bootstrap nodes.dat - not intended for normal use"));
349 // Write a saved contact list.
352 if (file
.Open(m_filename
, CFile::write
)) {
353 // The bootstrap method gets a very nice sample of contacts to save.
354 ContactMap mapContacts
;
355 CUInt128
random(CUInt128((uint32_t)0), 0);
356 CUInt128 distance
= random
;
358 GetClosestTo(2, random
, distance
, 1200, &mapContacts
, false, false);
359 // filter out Kad1 nodes
360 for (ContactMap::iterator it
= mapContacts
.begin(); it
!= mapContacts
.end(); ) {
361 ContactMap::iterator itCur
= it
++;
362 CContact
* contact
= itCur
->second
;
363 if (contact
->GetVersion() <= 1) {
364 mapContacts
.erase(itCur
);
367 // Start file with 0 to prevent older clients from reading it.
369 // Now tag it with a version which happens to be 3.
371 file
.WriteUInt32(1); // using version >= 3, this means that this is not a normal nodes.dat
372 file
.WriteUInt32((uint32_t)mapContacts
.size());
373 for (ContactMap::const_iterator it
= mapContacts
.begin(); it
!= mapContacts
.end(); ++it
)
375 CContact
* contact
= it
->second
;
376 file
.WriteUInt128(contact
->GetClientID());
377 file
.WriteUInt32(contact
->GetIPAddress());
378 file
.WriteUInt16(contact
->GetUDPPort());
379 file
.WriteUInt16(contact
->GetTCPPort());
380 file
.WriteUInt8(contact
->GetVersion());
383 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Wrote %u contacts to bootstrap file.")) % mapContacts
.size());
385 AddDebugLogLineC(logKadRouting
, wxT("Unable to store Kad file: ") + m_filename
);
387 } catch (const CIOFailureException
& e
) {
388 AddDebugLogLineC(logKadRouting
, wxT("CFileException in CRoutingZone::writeFile") + e
.what());
393 bool CRoutingZone::CanSplit() const throw()
395 // Max levels allowed.
396 if (m_level
>= 127) {
400 // Check if this zone is allowed to split.
401 return ((m_zoneIndex
< KK
|| m_level
< KBASE
) && m_bin
->GetSize() == K
);
404 // Returns true if a contact was added or updated, false if the routing table was not touched.
405 bool CRoutingZone::Add(const CUInt128
& id
, uint32_t ip
, uint16_t port
, uint16_t tport
, uint8_t version
, const CKadUDPKey
& key
, bool& ipVerified
, bool update
, bool fromHello
)
407 if (IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip
), port
)) {
408 if (!theApp
->ipfilter
->IsFiltered(wxUINT32_SWAP_ALWAYS(ip
)) && !(port
== 53 && version
<= 5) /*No DNS Port without encryption*/) {
409 return AddUnfiltered(id
, ip
, port
, tport
, version
, key
, ipVerified
, update
, fromHello
);
415 // Returns true if a contact was added or updated, false if the routing table was not touched.
416 bool CRoutingZone::AddUnfiltered(const CUInt128
& id
, uint32_t ip
, uint16_t port
, uint16_t tport
, uint8_t version
, const CKadUDPKey
& key
, bool& ipVerified
, bool update
, bool fromHello
)
419 CContact
*contact
= new CContact(id
, ip
, port
, tport
, version
, key
, ipVerified
);
421 contact
->SetReceivedHelloPacket();
423 if (Add(contact
, update
, ipVerified
)) {
434 bool CRoutingZone::Add(CContact
*contact
, bool& update
, bool& outIpVerified
)
436 // If we're not a leaf, call add on the correct branch.
438 return m_subZones
[contact
->GetDistance().GetBitNumber(m_level
)]->Add(contact
, update
, outIpVerified
);
440 // Do we already have a contact with this KadID?
441 CContact
*contactUpdate
= m_bin
->GetContact(contact
->GetClientID());
444 if (contactUpdate
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) != 0 && contactUpdate
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) != contact
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false))) {
445 // if our existing contact has a UDPSender-Key (which should be the case for all > = 0.49a clients)
446 // except if our IP has changed recently, we demand that the key is the same as the key we received
447 // from the packet which wants to update this contact in order to make sure this is not a try to
449 AddDebugLogLineN(logKadRouting
, wxT("Sender (") + KadIPToString(contact
->GetIPAddress()) + wxT(") tried to update contact entry but failed to provide the proper sender key (Sent Empty: ") + (contact
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) == 0 ? wxT("Yes") : wxT("No")) + wxT(") for the entry (") + KadIPToString(contactUpdate
->GetIPAddress()) + wxT(") - denying update"));
451 } else if (contactUpdate
->GetVersion() >= 1 && contactUpdate
->GetVersion() < 6 && contactUpdate
->GetReceivedHelloPacket()) {
452 // legacy kad2 contacts are allowed only to update their RefreshTimer to avoid having them hijacked/corrupted by an attacker
453 // (kad1 contacts do not have this restriction as they might turn out as kad2 later on)
454 // only exception is if we didn't received a HELLO packet from this client yet
455 if (contactUpdate
->GetIPAddress() == contact
->GetIPAddress() && contactUpdate
->GetTCPPort() == contact
->GetTCPPort() && contactUpdate
->GetVersion() == contact
->GetVersion() && contactUpdate
->GetUDPPort() == contact
->GetUDPPort()) {
456 wxASSERT(!contact
->IsIPVerified()); // legacy kad2 nodes should be unable to verify their IP on a HELLO
457 outIpVerified
= contactUpdate
->IsIPVerified();
458 m_bin
->SetAlive(contactUpdate
);
459 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Updated kad contact refreshtimer only for legacy kad2 contact (%s, %u)")) % KadIPToString(contactUpdate
->GetIPAddress()) % contactUpdate
->GetVersion());
461 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Rejected value update for legacy kad2 contact (%s -> %s, %u -> %u)"))
462 % KadIPToString(contactUpdate
->GetIPAddress()) % KadIPToString(contact
->GetIPAddress()) % contactUpdate
->GetVersion() % contact
->GetVersion());
467 // just for outlining, get removed anyway
468 //debug logging stuff - remove later
469 if (contact
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) == 0) {
470 if (contact
->GetVersion() >= 6 && contact
->GetType() < 2) {
471 AddDebugLogLineN(logKadRouting
, wxT("Updating > 0.49a + type < 2 contact without valid key stored ") + KadIPToString(contact
->GetIPAddress()));
474 AddDebugLogLineN(logKadRouting
, wxT("Updating contact, passed key check ") + KadIPToString(contact
->GetIPAddress()));
477 if (contactUpdate
->GetVersion() >= 1 && contactUpdate
->GetVersion() < 6) {
478 wxASSERT(!contactUpdate
->GetReceivedHelloPacket());
479 AddDebugLogLineN(logKadRouting
, CFormat(wxT("Accepted update for legacy kad2 contact, because of first HELLO (%s -> %s, %u -> %u)"))
480 % KadIPToString(contactUpdate
->GetIPAddress()) % KadIPToString(contact
->GetIPAddress()) % contactUpdate
->GetVersion() % contact
->GetVersion());
483 // All other nodes (Kad1, Kad2 > 0.49a with UDPKey checked or not set, first hello updates) are allowed to do full updates
484 // do not let Kad1 responses overwrite Kad2 ones
485 if (m_bin
->ChangeContactIPAddress(contactUpdate
, contact
->GetIPAddress()) && contact
->GetVersion() >= contactUpdate
->GetVersion()) {
486 contactUpdate
->SetUDPPort(contact
->GetUDPPort());
487 contactUpdate
->SetTCPPort(contact
->GetTCPPort());
488 contactUpdate
->SetVersion(contact
->GetVersion());
489 contactUpdate
->SetUDPKey(contact
->GetUDPKey());
490 // don't unset the verified flag (will clear itself on ipchanges)
491 if (!contactUpdate
->IsIPVerified()) {
492 contactUpdate
->SetIPVerified(contact
->IsIPVerified());
494 outIpVerified
= contactUpdate
->IsIPVerified();
495 m_bin
->SetAlive(contactUpdate
);
496 if (contact
->GetReceivedHelloPacket()) {
497 contactUpdate
->SetReceivedHelloPacket();
505 } else if (m_bin
->GetRemaining()) {
507 // This bin is not full, so add the new contact
508 return m_bin
->AddContact(contact
);
509 } else if (CanSplit()) {
510 // This bin was full and split, call add on the correct branch.
512 return m_subZones
[contact
->GetDistance().GetBitNumber(m_level
)]->Add(contact
, update
, outIpVerified
);
520 CContact
*CRoutingZone::GetContact(const CUInt128
& id
) const throw()
523 return m_bin
->GetContact(id
);
525 CUInt128 distance
= CKademlia::GetPrefs()->GetKadID();
527 return m_subZones
[distance
.GetBitNumber(m_level
)]->GetContact(id
);
531 CContact
*CRoutingZone::GetContact(uint32_t ip
, uint16_t port
, bool tcpPort
) const throw()
534 return m_bin
->GetContact(ip
, port
, tcpPort
);
536 CContact
*contact
= m_subZones
[0]->GetContact(ip
, port
, tcpPort
);
537 return (contact
!= NULL
) ? contact
: m_subZones
[1]->GetContact(ip
, port
, tcpPort
);
541 CContact
*CRoutingZone::GetRandomContact(uint32_t maxType
, uint32_t minKadVersion
) const
544 return m_bin
->GetRandomContact(maxType
, minKadVersion
);
546 unsigned zone
= GetRandomUint16() & 1 /* GetRandomUint16() % 2 */;
547 CContact
*contact
= m_subZones
[zone
]->GetRandomContact(maxType
, minKadVersion
);
548 return (contact
!= NULL
) ? contact
: m_subZones
[1 - zone
]->GetRandomContact(maxType
, minKadVersion
);
552 void CRoutingZone::GetClosestTo(uint32_t maxType
, const CUInt128
& target
, const CUInt128
& distance
, uint32_t maxRequired
, ContactMap
*result
, bool emptyFirst
, bool inUse
) const
554 // If leaf zone, do it here
556 m_bin
->GetClosestTo(maxType
, target
, maxRequired
, result
, emptyFirst
, inUse
);
560 // otherwise, recurse in the closer-to-the-target subzone first
561 int closer
= distance
.GetBitNumber(m_level
);
562 m_subZones
[closer
]->GetClosestTo(maxType
, target
, distance
, maxRequired
, result
, emptyFirst
, inUse
);
564 // if still not enough tokens found, recurse in the other subzone too
565 if (result
->size() < maxRequired
) {
566 m_subZones
[1-closer
]->GetClosestTo(maxType
, target
, distance
, maxRequired
, result
, false, inUse
);
570 void CRoutingZone::GetAllEntries(ContactList
*result
, bool emptyFirst
) const
573 m_bin
->GetEntries(result
, emptyFirst
);
575 m_subZones
[0]->GetAllEntries(result
, emptyFirst
);
576 m_subZones
[1]->GetAllEntries(result
, false);
580 void CRoutingZone::TopDepth(int depth
, ContactList
*result
, bool emptyFirst
) const
583 m_bin
->GetEntries(result
, emptyFirst
);
584 } else if (depth
<= 0) {
585 RandomBin(result
, emptyFirst
);
587 m_subZones
[0]->TopDepth(depth
-1, result
, emptyFirst
);
588 m_subZones
[1]->TopDepth(depth
-1, result
, false);
592 void CRoutingZone::RandomBin(ContactList
*result
, bool emptyFirst
) const
595 m_bin
->GetEntries(result
, emptyFirst
);
597 m_subZones
[rand()&1]->RandomBin(result
, emptyFirst
);
601 uint32_t CRoutingZone::GetMaxDepth() const throw()
606 return 1 + std::max(m_subZones
[0]->GetMaxDepth(), m_subZones
[1]->GetMaxDepth());
609 void CRoutingZone::Split()
613 m_subZones
[0] = GenSubZone(0);
614 m_subZones
[1] = GenSubZone(1);
617 m_bin
->GetEntries(&entries
);
618 m_bin
->m_dontDeleteContacts
= true;
622 for (ContactList::const_iterator it
= entries
.begin(); it
!= entries
.end(); ++it
) {
623 if (!m_subZones
[(*it
)->GetDistance().GetBitNumber(m_level
)]->m_bin
->AddContact(*it
)) {
629 uint32_t CRoutingZone::Consolidate()
631 uint32_t mergeCount
= 0;
637 wxASSERT(m_bin
== NULL
);
639 if (!m_subZones
[0]->IsLeaf()) {
640 mergeCount
+= m_subZones
[0]->Consolidate();
642 if (!m_subZones
[1]->IsLeaf()) {
643 mergeCount
+= m_subZones
[1]->Consolidate();
646 if (m_subZones
[0]->IsLeaf() && m_subZones
[1]->IsLeaf() && GetNumContacts() < K
/ 2) {
647 m_bin
= new CRoutingBin();
649 m_subZones
[0]->StopTimer();
650 m_subZones
[1]->StopTimer();
654 m_subZones
[0]->m_bin
->GetEntries(&list0
);
655 m_subZones
[1]->m_bin
->GetEntries(&list1
);
657 m_subZones
[0]->m_bin
->m_dontDeleteContacts
= true;
658 m_subZones
[1]->m_bin
->m_dontDeleteContacts
= true;
660 delete m_subZones
[0];
661 delete m_subZones
[1];
663 m_subZones
[0] = NULL
;
664 m_subZones
[1] = NULL
;
666 for (ContactList::const_iterator it
= list0
.begin(); it
!= list0
.end(); ++it
) {
667 m_bin
->AddContact(*it
);
669 for (ContactList::const_iterator it
= list1
.begin(); it
!= list1
.end(); ++it
) {
670 m_bin
->AddContact(*it
);
680 CRoutingZone
*CRoutingZone::GenSubZone(unsigned side
)
684 CUInt128
newIndex(m_zoneIndex
);
687 return new CRoutingZone(this, m_level
+ 1, newIndex
);
690 void CRoutingZone::StartTimer()
692 // Start filling the tree, closest bins first.
693 m_nextBigTimer
= time(NULL
) + SEC(10);
694 CKademlia::AddEvent(this);
697 void CRoutingZone::StopTimer()
699 CKademlia::RemoveEvent(this);
702 bool CRoutingZone::OnBigTimer() const
704 if (IsLeaf() && (m_zoneIndex
< KK
|| m_level
< KBASE
|| m_bin
->GetRemaining() >= (K
* 0.8))) {
712 //This is used when we find a leaf and want to know what this sample looks like.
713 //We fall back two levels and take a sample to try to minimize any areas of the
714 //tree that will give very bad results.
715 uint32_t CRoutingZone::EstimateCount() const
721 if (m_level
< KBASE
) {
722 return (uint32_t)(pow(2.0, (int)m_level
) * K
);
725 CRoutingZone
* curZone
= m_superZone
->m_superZone
->m_superZone
;
727 // Find out how full this part of the tree is.
728 float modify
= ((float)curZone
->GetNumContacts()) / (float)(K
* 2);
730 // First calculate users assuming the tree is full.
731 // Modify count by bin size.
732 // Modify count by how full the tree is.
735 // Modify count by assuming 20% of the users are firewalled and can't be a contact for < 0.49b nodes
736 // Modify count by actual statistics of Firewalled ratio for >= 0.49b if we are not firewalled ourself
737 // Modify count by 40% for >= 0.49b if we are firewalled ourself (the actual Firewalled count at this date on kad is 35-55%)
738 const float firewalledModifyOld
= 1.20f
;
739 float firewalledModifyNew
= 0;
740 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
741 firewalledModifyNew
= 1.40f
; // we are firewalled and can't get the real statistics, assume 40% firewalled >=0.49b nodes
742 } else if (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true) > 0) {
743 firewalledModifyNew
= 1.0 + (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true)); // apply the firewalled ratio to the modify
744 wxASSERT(firewalledModifyNew
> 1.0 && firewalledModifyNew
< 1.90);
746 float newRatio
= CKademlia::GetPrefs()->StatsGetKadV8Ratio();
747 float firewalledModifyTotal
= 0;
748 if (newRatio
> 0 && firewalledModifyNew
> 0) { // weight the old and the new modifier based on how many new contacts we have
749 firewalledModifyTotal
= (newRatio
* firewalledModifyNew
) + ((1 - newRatio
) * firewalledModifyOld
);
751 firewalledModifyTotal
= firewalledModifyOld
;
753 wxASSERT(firewalledModifyTotal
> 1.0 && firewalledModifyTotal
< 1.90);
755 return (uint32_t)(pow(2.0, (int)m_level
- 2) * (float)K
* modify
* firewalledModifyTotal
);
758 void CRoutingZone::OnSmallTimer()
765 time_t now
= time(NULL
);
768 // Remove dead entries
769 m_bin
->GetEntries(&entries
);
770 for (ContactList::iterator it
= entries
.begin(); it
!= entries
.end(); ++it
) {
772 if (c
->GetType() == 4) {
773 if ((c
->GetExpireTime() > 0) && (c
->GetExpireTime() <= now
)) {
775 m_bin
->RemoveContact(c
);
781 if(c
->GetExpireTime() == 0) {
782 c
->SetExpireTime(now
);
786 c
= m_bin
->GetOldest();
788 if (c
->GetExpireTime() >= now
|| c
->GetType() == 4) {
789 m_bin
->PushToBottom(c
);
796 if (c
->GetVersion() >= 6) {
797 DebugSend(Kad2HelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
798 CUInt128 clientID
= c
->GetClientID();
799 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), c
->GetVersion(), c
->GetUDPKey(), &clientID
, false);
800 if (c
->GetVersion() >= 8) {
802 // This is a bit of a work around for statistic values. Normally we only count values from incoming HELLO_REQs for
803 // the firewalled statistics in order to get numbers from nodes which have us on their routing table,
804 // however if we send a HELLO due to the timer, the remote node won't send a HELLO_REQ itself anymore (but
805 // a HELLO_RES which we don't count), so count those statistics here. This isn't really accurate, but it should
806 // do fair enough. Maybe improve it later for example by putting a flag into the contact and make the answer count
807 CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(false);
808 CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(false);
810 } else if (c
->GetVersion() >= 2) {
811 DebugSend(Kad2HelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
812 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), c
->GetVersion(), 0, NULL
, false);
813 wxASSERT(c
->GetUDPKey() == CKadUDPKey(0));
820 void CRoutingZone::RandomLookup() const
822 // Look-up a random client in this zone
823 CUInt128
prefix(m_zoneIndex
);
824 prefix
<<= 128 - m_level
;
825 CUInt128
random(prefix
, m_level
);
827 CSearchManager::FindNode(random
, false);
830 uint32_t CRoutingZone::GetNumContacts() const throw()
833 return m_bin
->GetSize();
835 return m_subZones
[0]->GetNumContacts() + m_subZones
[1]->GetNumContacts();
839 void CRoutingZone::GetNumContacts(uint32_t& nInOutContacts
, uint32_t& nInOutFilteredContacts
, uint8_t minVersion
) const throw()
842 m_bin
->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
844 m_subZones
[0]->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
845 m_subZones
[1]->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
849 uint32_t CRoutingZone::GetBootstrapContacts(ContactList
*results
, uint32_t maxRequired
) const
851 wxASSERT(m_superZone
== NULL
);
857 TopDepth(LOG_BASE_EXPONENT
, &top
);
858 if (top
.size() > 0) {
859 for (ContactList::const_iterator it
= top
.begin(); it
!= top
.end(); ++it
) {
860 results
->push_back(*it
);
862 if (count
== maxRequired
) {
871 bool CRoutingZone::VerifyContact(const CUInt128
& id
, uint32_t ip
)
873 CContact
* contact
= GetContact(id
);
874 if (contact
== NULL
) {
876 } else if (ip
!= contact
->GetIPAddress()) {
879 if (contact
->IsIPVerified()) {
880 AddDebugLogLineN(logKadRouting
, wxT("Sender already verified (sender: ") + KadIPToString(ip
) + wxT(")"));
882 contact
->SetIPVerified(true);
888 void CRoutingZone::SetAllContactsVerified()
891 m_bin
->SetAllContactsVerified();
893 m_subZones
[0]->SetAllContactsVerified();
894 m_subZones
[1]->SetAllContactsVerified();
898 bool CRoutingZone::IsAcceptableContact(const CContact
*toCheck
) const
900 // Check if we know a contact with the same ID or IP but notmatching IP/ID and other limitations, similar checks like when adding a node to the table except allowing duplicates
901 // we use this to check KADEMLIA_RES routing answers on searches
902 if (toCheck
->GetVersion() <= 1) {
903 // No Kad1 contacts allowed
906 CContact
*duplicate
= GetContact(toCheck
->GetClientID());
907 if (duplicate
!= NULL
) {
908 if ((duplicate
->IsIPVerified() && duplicate
->GetIPAddress() != toCheck
->GetIPAddress()) || duplicate
->GetUDPPort() != toCheck
->GetUDPPort()) {
909 // already existing verified node with different IP
912 // node exists already in our routing table, that's fine
916 // if the node is not yet known, check if our IP limitations would hit
917 return CRoutingBin::CheckGlobalIPLimits(toCheck
->GetIPAddress(), toCheck
->GetUDPPort());
920 bool CRoutingZone::HasOnlyLANNodes() const throw()
923 return m_bin
->HasOnlyLANNodes();
925 return m_subZones
[0]->HasOnlyLANNodes() && m_subZones
[1]->HasOnlyLANNodes();