2 // This file is part of aMule Project
4 // Copyright (c) 2004-2008 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2004-2008 aMule Project ( http://www.amule-project.net )
6 // Copyright (C)2003 Barry Dunne (http://www.emule-project.net)
7 // Copyright (C)2007-2008 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 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 if (numContacts
!= 0 && numContacts
* 25 <= (file
.GetLength() - file
.GetPosition())) {
172 for (uint32_t i
= 0; i
< numContacts
; i
++) {
173 CUInt128 id
= file
.ReadUInt128();
174 uint32_t ip
= file
.ReadUInt32();
175 uint16_t udpPort
= file
.ReadUInt16();
176 uint16_t tcpPort
= file
.ReadUInt16();
178 uint8_t contactVersion
= 0;
179 if (fileVersion
>= 1) {
180 contactVersion
= file
.ReadUInt8();
182 type
= 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;
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, true, false)) {
208 AddLogLineM(false, wxString::Format(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", validContacts
), validContacts
));
209 if (!doHaveVerifiedContacts
) {
210 AddDebugLogLineM(false, 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."));
211 SetAllContactsVerified();
214 if (validContacts
== 0) {
215 AddLogLineM(true, _("No contacts found, please bootstrap, or download a nodes.dat file."));
217 } catch (const CSafeIOException
& e
) {
218 AddDebugLogLineM(false, logKadRouting
, wxT("IO error in CRoutingZone::readFile: ") + e
.what());
222 void CRoutingZone::ReadBootstrapNodesDat(CFileDataIO
& file
)
224 // Bootstrap versions of nodes.dat files are in the style of version 1 nodes.dats. The difference is that
225 // they will contain more contacts, 500-1000 instead of 50, and those contacts are not added into the routing table
226 // but used to sent Bootstrap packets to. The advantage is that on a list with a high ratio of dead nodes,
227 // we will be able to bootstrap faster than on a normal nodes.dat and more important, if we would deliver
228 // a normal nodes.dat with eMule, those 50 nodes would be kinda DDOSed because everyone adds them to their routing
229 // table, while with this style, we don't actually add any of the contacts to our routing table in the end and we
230 // ask only one of those 1000 contacts one time (well or more until we find an alive one).
231 if (!CKademlia::s_bootstrapList
.empty()){
235 uint32_t numContacts
= file
.ReadUInt32();
236 if (numContacts
!= 0 && numContacts
* 25 == (file
.GetLength() - file
.GetPosition())) {
237 uint32_t validContacts
= 0;
238 while (numContacts
) {
239 CUInt128 id
= file
.ReadUInt128();
240 uint32_t ip
= file
.ReadUInt32();
241 uint16_t udpPort
= file
.ReadUInt16();
242 uint16_t tcpPort
= file
.ReadUInt16();
243 uint8_t contactVersion
= file
.ReadUInt8();
245 if (::IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip
), udpPort
)) {
246 if (!theApp
->ipfilter
->IsFiltered(wxUINT32_SWAP_ALWAYS(ip
)) &&
247 !(udpPort
== 53 && contactVersion
<= 5) &&
248 (contactVersion
> 1)) // only kad2 nodes
250 // 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)
251 CUInt128 distance
= me
;
254 // don't bother if we already have 50 and the farest distance is smaller than this contact
255 if (CKademlia::s_bootstrapList
.size() < 50 || CKademlia::s_bootstrapList
.back()->GetDistance() > distance
) {
256 // look where to put this contact into the proper position
257 bool inserted
= false;
258 CContact
* contact
= new CContact(id
, ip
, udpPort
, tcpPort
, contactVersion
, 0, false, me
);
259 for (ContactList::iterator it
= CKademlia::s_bootstrapList
.begin(); it
!= CKademlia::s_bootstrapList
.end(); ++it
) {
260 if ((*it
)->GetDistance() > distance
) {
261 CKademlia::s_bootstrapList
.insert(it
, contact
);
267 wxASSERT(CKademlia::s_bootstrapList
.size() < 50);
268 CKademlia::s_bootstrapList
.push_back(contact
);
269 } else if (CKademlia::s_bootstrapList
.size() > 50) {
270 delete CKademlia::s_bootstrapList
.back();
271 CKademlia::s_bootstrapList
.pop_back();
278 AddLogLineM(false, wxString::Format(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", CKademlia::s_bootstrapList
.size()), CKademlia::s_bootstrapList
.size()));
279 AddDebugLogLineM(false, logKadRouting
, wxString::Format(wxT("Loaded Bootstrap nodes.dat, selected %u out of %u valid contacts"), CKademlia::s_bootstrapList
.size(), validContacts
));
281 if (CKademlia::s_bootstrapList
.size() == 0) {
282 AddLogLineM(true, _("No contacts found, please bootstrap, or download a nodes.dat file."));
286 void CRoutingZone::WriteFile()
288 // don't overwrite a bootstrap nodes.dat with an empty one, if we didn't finish probing
289 if (!CKademlia::s_bootstrapList
.empty() && GetNumContacts() == 0) {
290 AddDebugLogLineM(false, logKadRouting
, wxT("Skipped storing nodes.dat, because we have an unfinished bootstrap of the nodes.dat version and no contacts in our routing table"));
294 // The bootstrap method gets a very nice sample of contacts to save.
295 ContactList contacts
;
296 GetBootstrapContacts(&contacts
, 200);
297 ContactList::size_type numContacts
= contacts
.size();
298 numContacts
= std::min
<ContactList::size_type
>(numContacts
, CONTACT_FILE_LIMIT
); // safety precaution, should not be above
299 if (numContacts
< 25) {
300 AddLogLineM(false, wxString::Format(wxPLURAL("Only %d Kad contact available, nodes.dat not written", "Only %d Kad contacts available, nodes.dat not written", numContacts
), numContacts
));
304 unsigned int count
= 0;
306 if (file
.Open(m_filename
, CFile::write
)) {
307 // Start file with 0 to prevent older clients from reading it.
309 // Now tag it with a version which happens to be 2.
311 // file.WriteUInt32(0); // if we would use version >= 3 this would mean that this is a normal nodes.dat
312 file
.WriteUInt32(numContacts
);
313 for (ContactList::const_iterator it
= contacts
.begin(); it
!= contacts
.end(); ++it
) {
316 if (count
> CONTACT_FILE_LIMIT
) {
317 // This should never happen
321 file
.WriteUInt128(c
->GetClientID());
322 file
.WriteUInt32(c
->GetIPAddress());
323 file
.WriteUInt16(c
->GetUDPPort());
324 file
.WriteUInt16(c
->GetTCPPort());
325 file
.WriteUInt8(c
->GetVersion());
326 c
->GetUDPKey().StoreToFile(file
);
327 file
.WriteUInt8(c
->IsIPVerified() ? 1 : 0);
330 AddLogLineM(false, wxString::Format(wxPLURAL("Wrote %d Kad contact", "Wrote %d Kad contacts", count
), count
));
331 } catch (const CIOFailureException
& e
) {
332 AddDebugLogLineM(true, logKadRouting
, wxT("IO failure in CRoutingZone::writeFile: ") + e
.what());
337 void CRoutingZone::WriteBootstrapFile()
339 AddDebugLogLineM(true, logKadRouting
, wxT("Writing special bootstrap nodes.dat - not intended for normal use"));
341 // Write a saved contact list.
344 if (file
.Open(m_filename
, CFile::write
)) {
345 // The bootstrap method gets a very nice sample of contacts to save.
346 ContactMap mapContacts
;
347 CUInt128
random(CUInt128((uint32_t)0), 0);
348 CUInt128 distance
= random
;
350 GetClosestTo(2, random
, distance
, 1200, &mapContacts
, false, false);
351 // filter out Kad1 nodes
352 for (ContactMap::iterator it
= mapContacts
.begin(); it
!= mapContacts
.end(); ) {
353 ContactMap::iterator itCur
= it
++;
354 CContact
* contact
= itCur
->second
;
355 if (contact
->GetVersion() <= 1) {
356 mapContacts
.erase(itCur
);
359 // Start file with 0 to prevent older clients from reading it.
361 // Now tag it with a version which happens to be 3.
363 file
.WriteUInt32(1); // using version >= 3, this means that this is not a normal nodes.dat
364 file
.WriteUInt32((uint32_t)mapContacts
.size());
365 for (ContactMap::const_iterator it
= mapContacts
.begin(); it
!= mapContacts
.end(); ++it
)
367 CContact
* contact
= it
->second
;
368 file
.WriteUInt128(contact
->GetClientID());
369 file
.WriteUInt32(contact
->GetIPAddress());
370 file
.WriteUInt16(contact
->GetUDPPort());
371 file
.WriteUInt16(contact
->GetTCPPort());
372 file
.WriteUInt8(contact
->GetVersion());
375 AddDebugLogLineM(false, logKadRouting
, wxString::Format(wxT("Wrote %u contacts to bootstrap file."), mapContacts
.size()));
377 AddDebugLogLineM(true, logKadRouting
, wxT("Unable to store Kad file: ") + m_filename
);
379 } catch (const CIOFailureException
& e
) {
380 AddDebugLogLineM(false, logKadRouting
, wxT("CFileException in CRoutingZone::writeFile") + e
.what());
385 bool CRoutingZone::CanSplit() const throw()
387 // Max levels allowed.
388 if (m_level
>= 127) {
392 // Check if this zone is allowed to split.
393 return ((m_zoneIndex
< KK
|| m_level
< KBASE
) && m_bin
->GetSize() == K
);
396 // Returns true if a contact was added or updated, false if the routing table was not touched.
397 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 fromNodesDat
, bool fromHello
)
399 if (IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip
), port
)) {
400 if (!theApp
->ipfilter
->IsFiltered(wxUINT32_SWAP_ALWAYS(ip
)) && !(port
== 53 && version
<= 5) /*No DNS Port without encryption*/) {
401 return AddUnfiltered(id
, ip
, port
, tport
, version
, key
, ipVerified
, update
, fromNodesDat
, fromHello
);
407 // Returns true if a contact was added or updated, false if the routing table was not touched.
408 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 fromNodesDat
, bool fromHello
)
411 CContact
*contact
= new CContact(id
, ip
, port
, tport
, version
, key
, ipVerified
);
413 contact
->CheckIfKad2(); // do not test nodes which we loaded from our nodes.dat for Kad2 again
414 } else if (fromHello
) {
415 contact
->SetReceivedHelloPacket();
417 if (Add(contact
, update
, ipVerified
)) {
428 bool CRoutingZone::Add(CContact
*contact
, bool& update
, bool& outIpVerified
)
430 // If we're not a leaf, call add on the correct branch.
432 return m_subZones
[contact
->GetDistance().GetBitNumber(m_level
)]->Add(contact
, update
, outIpVerified
);
434 // Do we already have a contact with this KadID?
435 CContact
*contactUpdate
= m_bin
->GetContact(contact
->GetClientID());
438 if (contactUpdate
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) != 0 && contactUpdate
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) != contact
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false))) {
439 // if our existing contact has a UDPSender-Key (which should be the case for all > = 0.49a clients)
440 // except if our IP has changed recently, we demand that the key is the same as the key we received
441 // from the packet which wants to update this contact in order to make sure this is not a try to
443 AddDebugLogLineM(false, logKadRouting
, wxT("Sender (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(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 (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contactUpdate
->GetIPAddress())) + wxT(") - denying update"));
445 } else if (contactUpdate
->GetVersion() >= 1 && contactUpdate
->GetVersion() < 6 && contactUpdate
->GetReceivedHelloPacket()) {
446 // legacy kad2 contacts are allowed only to update their RefreshTimer to avoid having them hijacked/corrupted by an attacker
447 // (kad1 contacts do not have this restriction as they might turn out as kad2 later on)
448 // only exception is if we didn't received a HELLO packet from this client yet
449 if (contactUpdate
->GetIPAddress() == contact
->GetIPAddress() && contactUpdate
->GetTCPPort() == contact
->GetTCPPort() && contactUpdate
->GetVersion() == contact
->GetVersion() && contactUpdate
->GetUDPPort() == contact
->GetUDPPort()) {
450 wxASSERT(!contact
->IsIPVerified()); // legacy kad2 nodes should be unable to verify their IP on a HELLO
451 outIpVerified
= contactUpdate
->IsIPVerified();
452 m_bin
->SetAlive(contactUpdate
);
453 AddDebugLogLineM(false, logKadRouting
, wxString::Format(wxT("Updated kad contact refreshtimer only for legacy kad2 contact (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contactUpdate
->GetIPAddress())) + wxT(", %u)"), contactUpdate
->GetVersion()));
455 AddDebugLogLineM(false, logKadRouting
, wxString::Format(wxT("Rejected value update for legacy kad2 contact (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contactUpdate
->GetIPAddress())) + wxT(" -> ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contact
->GetIPAddress())) + wxT(", %u -> %u)"), contactUpdate
->GetVersion(), contact
->GetVersion()));
460 // just for outlining, get removed anyway
461 //debug logging stuff - remove later
462 if (contact
->GetUDPKey().GetKeyValue(theApp
->GetPublicIP(false)) == 0) {
463 if (contact
->GetVersion() >= 6 && contact
->GetType() < 2) {
464 AddDebugLogLineM(false, logKadRouting
, wxT("Updating > 0.49a + type < 2 contact without valid key stored ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contact
->GetIPAddress())));
467 AddDebugLogLineM(false, logKadRouting
, wxT("Updating contact, passed key check ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contact
->GetIPAddress())));
470 if (contactUpdate
->GetVersion() >= 1 && contactUpdate
->GetVersion() < 6) {
471 wxASSERT(!contactUpdate
->GetReceivedHelloPacket());
472 AddDebugLogLineM(false, logKadRouting
, wxString::Format(wxT("Accepted update for legacy kad2 contact, because of first HELLO (") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contactUpdate
->GetIPAddress())) + wxT(" -> ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(contact
->GetIPAddress())) + wxT(", %u -> %u)"), contactUpdate
->GetVersion(), contact
->GetVersion()));
475 // All other nodes (Kad1, Kad2 > 0.49a with UDPKey checked or not set, first hello updates) are allowed to do full updates
476 // do not let Kad1 responses overwrite Kad2 ones
477 if (m_bin
->ChangeContactIPAddress(contactUpdate
, contact
->GetIPAddress()) && contact
->GetVersion() >= contactUpdate
->GetVersion()) {
478 contactUpdate
->SetUDPPort(contact
->GetUDPPort());
479 contactUpdate
->SetTCPPort(contact
->GetTCPPort());
480 contactUpdate
->SetVersion(contact
->GetVersion());
481 contactUpdate
->SetUDPKey(contact
->GetUDPKey());
482 // don't unset the verified flag (will clear itself on ipchanges)
483 if (!contactUpdate
->IsIPVerified()) {
484 contactUpdate
->SetIPVerified(contact
->IsIPVerified());
486 outIpVerified
= contactUpdate
->IsIPVerified();
487 m_bin
->SetAlive(contactUpdate
);
488 if (contact
->GetReceivedHelloPacket()) {
489 contactUpdate
->SetReceivedHelloPacket();
497 } else if (m_bin
->GetRemaining()) {
499 // This bin is not full, so add the new contact
500 return m_bin
->AddContact(contact
);
501 } else if (CanSplit()) {
502 // This bin was full and split, call add on the correct branch.
504 return m_subZones
[contact
->GetDistance().GetBitNumber(m_level
)]->Add(contact
, update
, outIpVerified
);
512 CContact
*CRoutingZone::GetContact(const CUInt128
& id
) const throw()
515 return m_bin
->GetContact(id
);
517 CUInt128 distance
= CKademlia::GetPrefs()->GetKadID();
519 return m_subZones
[distance
.GetBitNumber(m_level
)]->GetContact(id
);
523 CContact
*CRoutingZone::GetContact(uint32_t ip
, uint16_t port
, bool tcpPort
) const throw()
526 return m_bin
->GetContact(ip
, port
, tcpPort
);
528 CContact
*contact
= m_subZones
[0]->GetContact(ip
, port
, tcpPort
);
529 return (contact
!= NULL
) ? contact
: m_subZones
[1]->GetContact(ip
, port
, tcpPort
);
533 CContact
*CRoutingZone::GetRandomContact(uint32_t maxType
, uint32_t minKadVersion
) const throw()
536 return m_bin
->GetRandomContact(maxType
, minKadVersion
);
538 unsigned zone
= GetRandomUint16() & 1 /* GetRandomUint16() % 2 */;
539 CContact
*contact
= m_subZones
[zone
]->GetRandomContact(maxType
, minKadVersion
);
540 return (contact
!= NULL
) ? contact
: m_subZones
[1 - zone
]->GetRandomContact(maxType
, minKadVersion
);
544 void CRoutingZone::GetClosestTo(uint32_t maxType
, const CUInt128
& target
, const CUInt128
& distance
, uint32_t maxRequired
, ContactMap
*result
, bool emptyFirst
, bool inUse
) const
546 // If leaf zone, do it here
548 m_bin
->GetClosestTo(maxType
, target
, maxRequired
, result
, emptyFirst
, inUse
);
552 // otherwise, recurse in the closer-to-the-target subzone first
553 int closer
= distance
.GetBitNumber(m_level
);
554 m_subZones
[closer
]->GetClosestTo(maxType
, target
, distance
, maxRequired
, result
, emptyFirst
, inUse
);
556 // if still not enough tokens found, recurse in the other subzone too
557 if (result
->size() < maxRequired
) {
558 m_subZones
[1-closer
]->GetClosestTo(maxType
, target
, distance
, maxRequired
, result
, false, inUse
);
562 void CRoutingZone::GetAllEntries(ContactList
*result
, bool emptyFirst
) const
565 m_bin
->GetEntries(result
, emptyFirst
);
567 m_subZones
[0]->GetAllEntries(result
, emptyFirst
);
568 m_subZones
[1]->GetAllEntries(result
, false);
572 void CRoutingZone::TopDepth(int depth
, ContactList
*result
, bool emptyFirst
) const
575 m_bin
->GetEntries(result
, emptyFirst
);
576 } else if (depth
<= 0) {
577 RandomBin(result
, emptyFirst
);
579 m_subZones
[0]->TopDepth(depth
-1, result
, emptyFirst
);
580 m_subZones
[1]->TopDepth(depth
-1, result
, false);
584 void CRoutingZone::RandomBin(ContactList
*result
, bool emptyFirst
) const
587 m_bin
->GetEntries(result
, emptyFirst
);
589 m_subZones
[rand()&1]->RandomBin(result
, emptyFirst
);
593 uint32_t CRoutingZone::GetMaxDepth() const throw()
598 return 1 + std::max(m_subZones
[0]->GetMaxDepth(), m_subZones
[1]->GetMaxDepth());
601 void CRoutingZone::Split()
605 m_subZones
[0] = GenSubZone(0);
606 m_subZones
[1] = GenSubZone(1);
609 m_bin
->GetEntries(&entries
);
610 m_bin
->m_dontDeleteContacts
= true;
614 for (ContactList::const_iterator it
= entries
.begin(); it
!= entries
.end(); ++it
) {
615 if (!m_subZones
[(*it
)->GetDistance().GetBitNumber(m_level
)]->m_bin
->AddContact(*it
)) {
621 uint32_t CRoutingZone::Consolidate()
623 uint32_t mergeCount
= 0;
629 wxASSERT(m_bin
== NULL
);
631 if (!m_subZones
[0]->IsLeaf()) {
632 mergeCount
+= m_subZones
[0]->Consolidate();
634 if (!m_subZones
[1]->IsLeaf()) {
635 mergeCount
+= m_subZones
[1]->Consolidate();
638 if (m_subZones
[0]->IsLeaf() && m_subZones
[1]->IsLeaf() && GetNumContacts() < K
/ 2) {
639 m_bin
= new CRoutingBin();
641 m_subZones
[0]->StopTimer();
642 m_subZones
[1]->StopTimer();
646 m_subZones
[0]->m_bin
->GetEntries(&list0
);
647 m_subZones
[1]->m_bin
->GetEntries(&list1
);
649 m_subZones
[0]->m_bin
->m_dontDeleteContacts
= true;
650 m_subZones
[1]->m_bin
->m_dontDeleteContacts
= true;
652 delete m_subZones
[0];
653 delete m_subZones
[1];
655 m_subZones
[0] = NULL
;
656 m_subZones
[1] = NULL
;
658 for (ContactList::const_iterator it
= list0
.begin(); it
!= list0
.end(); ++it
) {
659 m_bin
->AddContact(*it
);
661 for (ContactList::const_iterator it
= list1
.begin(); it
!= list1
.end(); ++it
) {
662 m_bin
->AddContact(*it
);
672 CRoutingZone
*CRoutingZone::GenSubZone(unsigned side
)
676 CUInt128
newIndex(m_zoneIndex
);
679 return new CRoutingZone(this, m_level
+ 1, newIndex
);
682 void CRoutingZone::StartTimer()
684 // Start filling the tree, closest bins first.
685 m_nextBigTimer
= time(NULL
) + SEC(10);
686 CKademlia::AddEvent(this);
689 void CRoutingZone::StopTimer()
691 CKademlia::RemoveEvent(this);
694 bool CRoutingZone::OnBigTimer() const
696 if (IsLeaf() && (m_zoneIndex
< KK
|| m_level
< KBASE
|| m_bin
->GetRemaining() >= (K
* 0.8))) {
704 //This is used when we find a leaf and want to know what this sample looks like.
705 //We fall back two levels and take a sample to try to minimize any areas of the
706 //tree that will give very bad results.
707 uint32_t CRoutingZone::EstimateCount() const throw()
713 if (m_level
< KBASE
) {
714 return (uint32_t)(pow(2.0, (int)m_level
) * K
);
717 CRoutingZone
* curZone
= m_superZone
->m_superZone
->m_superZone
;
719 // Find out how full this part of the tree is.
720 float modify
= ((float)curZone
->GetNumContacts()) / (float)(K
* 2);
722 // First calculate users assuming the tree is full.
723 // Modify count by bin size.
724 // Modify count by how full the tree is.
727 // Modify count by assuming 20% of the users are firewalled and can't be a contact for < 0.49b nodes
728 // Modify count by actual statistics of Firewalled ratio for >= 0.49b if we are not firewalled ourself
729 // Modify count by 40% for >= 0.49b if we are firewalled ourself (the actual Firewalled count at this date on kad is 35-55%)
730 const float firewalledModifyOld
= 1.20;
731 float firewalledModifyNew
= 0;
732 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
733 firewalledModifyNew
= 1.40; // we are firewalled and can't get the real statistics, assume 40% firewalled >=0.49b nodes
734 } else if (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true) > 0) {
735 firewalledModifyNew
= 1.0 + (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true)); // apply the firewalled ratio to the modify
736 wxASSERT(firewalledModifyNew
> 1.0 && firewalledModifyNew
< 1.90);
738 float newRatio
= CKademlia::GetPrefs()->StatsGetKadV8Ratio();
739 float firewalledModifyTotal
= 0;
740 if (newRatio
> 0 && firewalledModifyNew
> 0) { // weight the old and the new modifier based on how many new contacts we have
741 firewalledModifyTotal
= (newRatio
* firewalledModifyNew
) + ((1 - newRatio
) * firewalledModifyOld
);
743 firewalledModifyTotal
= firewalledModifyOld
;
745 wxASSERT(firewalledModifyTotal
> 1.0 && firewalledModifyTotal
< 1.90);
747 return (uint32_t)(pow(2.0, (int)m_level
- 2) * (float)K
* modify
* firewalledModifyTotal
);
750 void CRoutingZone::OnSmallTimer()
757 time_t now
= time(NULL
);
760 // Remove dead entries
761 m_bin
->GetEntries(&entries
);
762 for (ContactList::iterator it
= entries
.begin(); it
!= entries
.end(); ++it
) {
764 if (c
->GetType() == 4) {
765 if ((c
->GetExpireTime() > 0) && (c
->GetExpireTime() <= now
)) {
767 m_bin
->RemoveContact(c
);
773 if(c
->GetExpireTime() == 0) {
774 c
->SetExpireTime(now
);
778 c
= m_bin
->GetOldest();
780 if (c
->GetExpireTime() >= now
|| c
->GetType() == 4) {
781 m_bin
->PushToBottom(c
);
788 if (c
->GetVersion() >= 6) {
789 DebugSend(Kad2HelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
790 CUInt128 clientID
= c
->GetClientID();
791 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), c
->GetVersion(), c
->GetUDPKey(), &clientID
, false);
792 if (c
->GetVersion() >= 8) {
794 // This is a bit of a work around for statistic values. Normally we only count values from incoming HELLO_REQs for
795 // the firewalled statistics in order to get numbers from nodes which have us on their routing table,
796 // however if we send a HELLO due to the timer, the remote node won't send a HELLO_REQ itself anymore (but
797 // a HELLO_RES which we don't count), so count those statistics here. This isn't really accurate, but it should
798 // do fair enough. Maybe improve it later for example by putting a flag into the contact and make the answer count
799 CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(false);
800 CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(false);
802 } else if (c
->GetVersion() >= 2) {
803 DebugSend(Kad2HelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
804 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), c
->GetVersion(), 0, NULL
, false);
805 wxASSERT(c
->GetUDPKey() == CKadUDPKey(0));
807 DebugSend(KadHelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
808 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), 0, 0, NULL
, false);
809 if (c
->CheckIfKad2()) {
810 DebugSend(Kad2HelloReq
, c
->GetIPAddress(), c
->GetUDPPort());
811 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ
, c
->GetIPAddress(), c
->GetUDPPort(), 1, 0, NULL
, false);
817 void CRoutingZone::RandomLookup() const
819 // Look-up a random client in this zone
820 CUInt128
prefix(m_zoneIndex
);
821 prefix
<<= 128 - m_level
;
822 CUInt128
random(prefix
, m_level
);
824 CSearchManager::FindNode(random
, false);
827 uint32_t CRoutingZone::GetNumContacts() const throw()
830 return m_bin
->GetSize();
832 return m_subZones
[0]->GetNumContacts() + m_subZones
[1]->GetNumContacts();
836 void CRoutingZone::GetNumContacts(uint32_t& nInOutContacts
, uint32_t& nInOutFilteredContacts
, uint8_t minVersion
) const
839 m_bin
->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
841 m_subZones
[0]->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
842 m_subZones
[1]->GetNumContacts(nInOutContacts
, nInOutFilteredContacts
, minVersion
);
846 uint32_t CRoutingZone::GetBootstrapContacts(ContactList
*results
, uint32_t maxRequired
) const
848 wxASSERT(m_superZone
== NULL
);
854 TopDepth(LOG_BASE_EXPONENT
, &top
);
855 if (top
.size() > 0) {
856 for (ContactList::const_iterator it
= top
.begin(); it
!= top
.end(); ++it
) {
857 results
->push_back(*it
);
859 if (count
== maxRequired
) {
868 bool CRoutingZone::VerifyContact(const CUInt128
& id
, uint32_t ip
)
870 CContact
* contact
= GetContact(id
);
871 if (contact
== NULL
) {
873 } else if (ip
!= contact
->GetIPAddress()) {
876 if (contact
->IsIPVerified()) {
877 AddDebugLogLineM(false, logKadRouting
, wxT("Sender already verified (sender: ") + Uint32toStringIP(wxUINT32_SWAP_ALWAYS(ip
)) + wxT(")"));
879 contact
->SetIPVerified(true);
885 void CRoutingZone::SetAllContactsVerified()
888 m_bin
->SetAllContactsVerified();
890 m_subZones
[0]->SetAllContactsVerified();
891 m_subZones
[1]->SetAllContactsVerified();