1 //
2 // This file is part of aMule Project
3 //
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 )
8
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.
13
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
test_incremental_pca()17 // GNU General Public License for more details.
18
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
22
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
27
28 // Note To Mods //
29 /*
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..
38 */
39
40 /**
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".
45 *
46 * All key unique id's are relative to the center (self), which
47 * is considered to be 000..000
48 */
49 #include "RoutingZone.h"
50
51 #include <protocol/kad/Client2Client/UDP.h>
52 #include <protocol/kad2/Client2Client/UDP.h>
53 #include <common/Macros.h>
54
55 #include "Contact.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"
68
69 #include <cmath>
70
71 ////////////////////////////////////////
72 using namespace Kademlia;
73 ////////////////////////////////////////
74
75 // This is just a safety precaution
76 #define CONTACT_FILE_LIMIT 500
77
78 wxString CRoutingZone::m_filename;
79 CUInt128 CRoutingZone::me((uint32_t)0);
80
81 CRoutingZone::CRoutingZone()
82 {
83 // Can only create routing zone after prefs
84 // Set our KadID for creating the contact tree
test_incremental_pca_check_projection()85 me = CKademlia::GetPrefs()->GetKadID();
86 // Set the preference file name.
87 m_filename = thePrefs::GetConfigDir() + wxT("nodes.dat");
88 Init(NULL, 0, CUInt128((uint32_t)0));
89 }
90
91 void CRoutingZone::Init(CRoutingZone *super_zone, int level, const CUInt128& zone_index)
92 {
93 // Init all Zone vars
94 // Set this zone's parent
95 m_superZone = super_zone;
96 // Set this zone's level
97 m_level = 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();
105
test_incremental_pca_inverse()106 // Set timer so that zones closer to the root are processed earlier.
107 m_nextSmallTimer = time(NULL) + m_zoneIndex.Get32BitChunk(3);
108
109 // Start this zone.
110 StartTimer();
111
112 // If we are initializing the root node, read in our saved contact list.
113 if ((m_superZone == NULL) && (m_filename.Length() > 0)) {
114 ReadFile();
115 }
116 }
117
118 CRoutingZone::~CRoutingZone()
119 {
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)) {
test_incremental_pca_validation()122 WriteFile();
123 }
124
125 // If this zone is a leaf, delete our contact bin.
126 if (IsLeaf()) {
127 delete m_bin;
128 } else {
129 // If this zone is a branch, delete its leafs.
130 delete m_subZones[0];
131 delete m_subZones[1];
132 }
133 }
134
135 void CRoutingZone::ReadFile(const wxString& specialNodesdat)
136 {
137 if (m_superZone != NULL || (m_filename.IsEmpty() && specialNodesdat.IsEmpty())) {
138 wxFAIL;
139 return;
140 }
141
142 bool doHaveVerifiedContacts = false;
143 // Read in the saved contact list
144 try {
145 uint32_t validContacts = 0;
146 CFile file;
147 if (CPath::FileExists(specialNodesdat.IsEmpty() ? m_filename : specialNodesdat) && file.Open(m_filename, CFile::read)) {
148 // Get how many contacts in the saved list.
149 // NOTE: Older clients put the number of contacts here...
150 // Newer clients always have 0 here to prevent older clients from reading it.
test_n_components_none()151 uint32_t numContacts = file.ReadUInt32();
152 uint32_t fileVersion = 0;
153 if (numContacts == 0) {
154 if (file.GetLength() >= 8) {
155 fileVersion = file.ReadUInt32();
156 if (fileVersion == 3) {
157 uint32_t bootstrapEdition = file.ReadUInt32();
158 if (bootstrapEdition == 1) {
159 // this is a special bootstrap-only nodes.dat, handle it in a separate reading function
160 ReadBootstrapNodesDat(file);
161 file.Close();
162 return;
163 }
164 }
165 if (fileVersion >= 1 && fileVersion <= 3) {
166 numContacts = file.ReadUInt32();
167 }
168 }
test_incremental_pca_set_params()169 } else {
170 // Don't read version 0 nodes.dat files, because they can't tell the kad version of the contacts stored.
171 AddLogLineC(_("Failed to read nodes.dat file - too old. This version (0) is not supported anymore."));
172 numContacts = 0;
173 }
174 DEBUG_ONLY( unsigned kad1Count = 0; )
175 if (numContacts != 0 && numContacts * 25 <= (file.GetLength() - file.GetPosition())) {
176 for (uint32_t i = 0; i < numContacts; i++) {
177 CUInt128 id = file.ReadUInt128();
178 uint32_t ip = file.ReadUInt32();
179 uint16_t udpPort = file.ReadUInt16();
180 uint16_t tcpPort = file.ReadUInt16();
181 uint8_t contactVersion = 0;
182 contactVersion = file.ReadUInt8();
183 CKadUDPKey kadUDPKey;
184 bool verified = false;
185 if (fileVersion >= 2) {
186 kadUDPKey.ReadFromFile(file);
187 verified = file.ReadUInt8() != 0;
188 if (verified) {
189 doHaveVerifiedContacts = true;
190 }
191 }
test_incremental_pca_num_features_change()192 // IP appears valid
193 if (contactVersion > 1) {
194 if(IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip),udpPort)) {
195 if (!theApp->ipfilter->IsFiltered(wxUINT32_SWAP_ALWAYS(ip)) &&
196 !(udpPort == 53 && contactVersion <= 5 /*No DNS Port without encryption*/)) {
197 // This was not a dead contact, inc counter if add was successful
198 if (AddUnfiltered(id, ip, udpPort, tcpPort, contactVersion, kadUDPKey, verified, false, false)) {
199 validContacts++;
200 }
201 }
202 }
203 } else {
test_incremental_pca_batch_signs()204 DEBUG_ONLY( kad1Count++; )
205 }
206 }
207 }
208 file.Close();
209 AddLogLineN(CFormat(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", validContacts)) % validContacts);
210 #ifdef __DEBUG__
211 if (kad1Count > 0) {
212 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignored %u kad1 %s in nodes.dat file.")) % kad1Count % (kad1Count > 1 ? wxT("contacts"): wxT("contact")));
213 }
214 #endif
215 if (!doHaveVerifiedContacts) {
216 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."));
217 SetAllContactsVerified();
218 }
219 }
test_incremental_pca_batch_values()220 if (validContacts == 0) {
221 AddLogLineC(_("No contacts found, please bootstrap, or download a nodes.dat file."));
222 }
223 } catch (const CSafeIOException& DEBUG_ONLY(e)) {
224 AddDebugLogLineN(logKadRouting, wxT("IO error in CRoutingZone::readFile: ") + e.what());
225 }
226 }
227
228 void CRoutingZone::ReadBootstrapNodesDat(CFileDataIO& file)
229 {
230 // Bootstrap versions of nodes.dat files are in the style of version 1 nodes.dats. The difference is that
231 // they will contain more contacts, 500-1000 instead of 50, and those contacts are not added into the routing table
232 // but used to sent Bootstrap packets to. The advantage is that on a list with a high ratio of dead nodes,
233 // we will be able to bootstrap faster than on a normal nodes.dat and more important, if we would deliver
234 // a normal nodes.dat with eMule, those 50 nodes would be kinda DDOSed because everyone adds them to their routing
235 // table, while with this style, we don't actually add any of the contacts to our routing table in the end and we
test_incremental_pca_batch_rank()236 // ask only one of those 1000 contacts one time (well or more until we find an alive one).
237 if (!CKademlia::s_bootstrapList.empty()){
238 wxFAIL;
239 return;
240 }
241 uint32_t numContacts = file.ReadUInt32();
242 if (numContacts != 0 && numContacts * 25 == (file.GetLength() - file.GetPosition())) {
243 uint32_t validContacts = 0;
244 while (numContacts) {
245 CUInt128 id = file.ReadUInt128();
246 uint32_t ip = file.ReadUInt32();
247 uint16_t udpPort = file.ReadUInt16();
248 uint16_t tcpPort = file.ReadUInt16();
249 uint8_t contactVersion = file.ReadUInt8();
250
251 if (::IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip), udpPort)) {
test_incremental_pca_partial_fit()252 if (!theApp->ipfilter->IsFiltered(wxUINT32_SWAP_ALWAYS(ip)) &&
253 !(udpPort == 53 && contactVersion <= 5) &&
254 (contactVersion > 1)) // only kad2 nodes
255 {
256 // 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)
257 CUInt128 distance = me;
258 distance ^= id;
259 validContacts++;
260 // don't bother if we already have 50 and the farest distance is smaller than this contact
261 if (CKademlia::s_bootstrapList.size() < 50 || CKademlia::s_bootstrapList.back()->GetDistance() > distance) {
262 // look where to put this contact into the proper position
263 bool inserted = false;
264 CContact* contact = new CContact(id, ip, udpPort, tcpPort, contactVersion, 0, false, me);
265 for (ContactList::iterator it = CKademlia::s_bootstrapList.begin(); it != CKademlia::s_bootstrapList.end(); ++it) {
266 if ((*it)->GetDistance() > distance) {
267 CKademlia::s_bootstrapList.insert(it, contact);
268 inserted = true;
269 break;
270 }
271 }
272 if (!inserted) {
273 CKademlia::s_bootstrapList.push_back(contact);
274 } else if (CKademlia::s_bootstrapList.size() > 50) {
275 delete CKademlia::s_bootstrapList.back();
276 CKademlia::s_bootstrapList.pop_back();
277 }
278 }
279 }
280 }
281 numContacts--;
test_incremental_pca_against_pca_random_data()282 }
283 AddLogLineN(CFormat(wxPLURAL("Read %u Kad contact", "Read %u Kad contacts", CKademlia::s_bootstrapList.size())) % CKademlia::s_bootstrapList.size());
284 AddDebugLogLineN(logKadRouting, CFormat(wxT("Loaded Bootstrap nodes.dat, selected %u out of %u valid contacts")) % CKademlia::s_bootstrapList.size() % validContacts);
285 }
286 if (CKademlia::s_bootstrapList.size() == 0) {
287 AddLogLineC(_("No contacts found, please bootstrap, or download a nodes.dat file."));
288 }
289 }
290
291 void CRoutingZone::WriteFile()
292 {
293 // don't overwrite a bootstrap nodes.dat with an empty one, if we didn't finish probing
294 if (!CKademlia::s_bootstrapList.empty() && GetNumContacts() == 0) {
test_explained_variances()295 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"));
296 return;
297 }
298
299 // The bootstrap method gets a very nice sample of contacts to save.
300 ContactList contacts;
301 GetBootstrapContacts(&contacts, 200);
302 ContactList::size_type numContacts = contacts.size();
303 numContacts = std::min<ContactList::size_type>(numContacts, CONTACT_FILE_LIMIT); // safety precaution, should not be above
304 if (numContacts < 25) {
305 AddLogLineN(CFormat(wxPLURAL("Only %d Kad contact available, nodes.dat not written", "Only %d Kad contacts available, nodes.dat not written", numContacts)) % numContacts);
306 return;
307 }
308 try {
309 unsigned int count = 0;
310 CFile file;
311 if (file.Open(m_filename, CFile::write_safe)) {
312 // Start file with 0 to prevent older clients from reading it.
313 file.WriteUInt32(0);
test_singular_values()314 // Now tag it with a version which happens to be 2.
315 file.WriteUInt32(2);
316 // file.WriteUInt32(0); // if we would use version >= 3 this would mean that this is a normal nodes.dat
317 file.WriteUInt32(numContacts);
318 for (ContactList::const_iterator it = contacts.begin(); it != contacts.end(); ++it) {
319 CContact *c = *it;
320 count++;
321 if (count > CONTACT_FILE_LIMIT) {
322 // This should never happen
323 wxFAIL;
324 break;
325 }
326 file.WriteUInt128(c->GetClientID());
327 file.WriteUInt32(c->GetIPAddress());
328 file.WriteUInt16(c->GetUDPPort());
329 file.WriteUInt16(c->GetTCPPort());
330 file.WriteUInt8(c->GetVersion());
331 c->GetUDPKey().StoreToFile(file);
332 file.WriteUInt8(c->IsIPVerified() ? 1 : 0);
333 }
334 file.Close();
335 }
336 AddLogLineN(CFormat(wxPLURAL("Wrote %d Kad contact", "Wrote %d Kad contacts", count)) % count);
337 } catch (const CIOFailureException& e) {
338 AddDebugLogLineC(logKadRouting, wxT("IO failure in CRoutingZone::writeFile: ") + e.what());
339 }
340 }
341
342 #if 0
343 void CRoutingZone::WriteBootstrapFile()
344 {
345 AddDebugLogLineC(logKadRouting, wxT("Writing special bootstrap nodes.dat - not intended for normal use"));
346 try {
347 // Write a saved contact list.
348 CUInt128 id;
349 CFile file;
350 if (file.Open(m_filename, CFile::write)) {
351 // The bootstrap method gets a very nice sample of contacts to save.
352 ContactMap mapContacts;
353 CUInt128 random(CUInt128((uint32_t)0), 0);
354 CUInt128 distance = random;
355 distance ^= me;
356 GetClosestTo(2, random, distance, 1200, &mapContacts, false, false);
357 // filter out Kad1 nodes
358 for (ContactMap::iterator it = mapContacts.begin(); it != mapContacts.end(); ) {
359 ContactMap::iterator itCur = it++;
360 CContact* contact = itCur->second;
361 if (contact->GetVersion() <= 1) {
362 mapContacts.erase(itCur);
363 }
364 }
365 // Start file with 0 to prevent older clients from reading it.
366 file.WriteUInt32(0);
367 // Now tag it with a version which happens to be 3.
368 file.WriteUInt32(3);
369 file.WriteUInt32(1); // using version >= 3, this means that this is not a normal nodes.dat
370 file.WriteUInt32((uint32_t)mapContacts.size());
test_whitening()371 for (ContactMap::const_iterator it = mapContacts.begin(); it != mapContacts.end(); ++it)
372 {
373 CContact* contact = it->second;
374 file.WriteUInt128(contact->GetClientID());
375 file.WriteUInt32(contact->GetIPAddress());
376 file.WriteUInt16(contact->GetUDPPort());
377 file.WriteUInt16(contact->GetTCPPort());
378 file.WriteUInt8(contact->GetVersion());
379 }
380 file.Close();
381 AddDebugLogLineN(logKadRouting, CFormat(wxT("Wrote %u contacts to bootstrap file.")) % mapContacts.size());
382 } else {
383 AddDebugLogLineC(logKadRouting, wxT("Unable to store Kad file: ") + m_filename);
384 }
385 } catch (const CIOFailureException& e) {
386 AddDebugLogLineC(logKadRouting, wxT("CFileException in CRoutingZone::writeFile") + e.what());
387 }
388 }
389 #endif
390
391 bool CRoutingZone::CanSplit() const throw()
test_incremental_pca_partial_fit_float_division()392 {
393 // Max levels allowed.
394 if (m_level >= 127) {
395 return false;
396 }
397
398 // Check if this zone is allowed to split.
399 return ((m_zoneIndex < KK || m_level < KBASE) && m_bin->GetSize() == K);
400 }
401
402 // Returns true if a contact was added or updated, false if the routing table was not touched.
403 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)
404 {
405 if (IsGoodIPPort(wxUINT32_SWAP_ALWAYS(ip), port)) {
406 if (!theApp->ipfilter->IsFiltered(wxUINT32_SWAP_ALWAYS(ip)) && !(port == 53 && version <= 5) /*No DNS Port without encryption*/) {
407 return AddUnfiltered(id, ip, port, tport, version, key, ipVerified, update, fromHello);
408 }
409 }
410 return false;
411 }
412
413 // Returns true if a contact was added or updated, false if the routing table was not touched.
414 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)
415 {
416 if (id != me) {
test_incremental_pca_fit_overflow_error()417 CContact *contact = new CContact(id, ip, port, tport, version, key, ipVerified);
418 if (fromHello) {
419 contact->SetReceivedHelloPacket();
420 }
421 if (Add(contact, update, ipVerified)) {
422 wxASSERT(!update);
423 return true;
424 } else {
425 delete contact;
426 return update;
427 }
428 }
429 return false;
430 }
431
432 bool CRoutingZone::Add(CContact *contact, bool& update, bool& outIpVerified)
433 {
434 // If we're not a leaf, call add on the correct branch.
435 if (!IsLeaf()) {
436 return m_subZones[contact->GetDistance().GetBitNumber(m_level)]->Add(contact, update, outIpVerified);
437 } else {
438 // Do we already have a contact with this KadID?
439 CContact *contactUpdate = m_bin->GetContact(contact->GetClientID());
440 if (contactUpdate) {
441 if (update) {
442 if (contactUpdate->GetUDPKey().GetKeyValue(theApp->GetPublicIP(false)) != 0 && contactUpdate->GetUDPKey().GetKeyValue(theApp->GetPublicIP(false)) != contact->GetUDPKey().GetKeyValue(theApp->GetPublicIP(false))) {
443 // if our existing contact has a UDPSender-Key (which should be the case for all > = 0.49a clients)
444 // except if our IP has changed recently, we demand that the key is the same as the key we received
445 // from the packet which wants to update this contact in order to make sure this is not a try to
446 // hijack this entry
447 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"));
448 update = false;
449 } else if (contactUpdate->GetVersion() >= 1 && contactUpdate->GetVersion() < 6 && contactUpdate->GetReceivedHelloPacket()) {
450 // legacy kad2 contacts are allowed only to update their RefreshTimer to avoid having them hijacked/corrupted by an attacker
451 // (kad1 contacts do not have this restriction as they might turn out as kad2 later on)
452 // only exception is if we didn't received a HELLO packet from this client yet
453 if (contactUpdate->GetIPAddress() == contact->GetIPAddress() && contactUpdate->GetTCPPort() == contact->GetTCPPort() && contactUpdate->GetVersion() == contact->GetVersion() && contactUpdate->GetUDPPort() == contact->GetUDPPort()) {
454 wxASSERT(!contact->IsIPVerified()); // legacy kad2 nodes should be unable to verify their IP on a HELLO
455 outIpVerified = contactUpdate->IsIPVerified();
456 m_bin->SetAlive(contactUpdate);
457 AddDebugLogLineN(logKadRouting, CFormat(wxT("Updated kad contact refreshtimer only for legacy kad2 contact (%s, %u)")) % KadIPToString(contactUpdate->GetIPAddress()) % contactUpdate->GetVersion());
458 } else {
459 AddDebugLogLineN(logKadRouting, CFormat(wxT("Rejected value update for legacy kad2 contact (%s -> %s, %u -> %u)"))
460 % KadIPToString(contactUpdate->GetIPAddress()) % KadIPToString(contact->GetIPAddress()) % contactUpdate->GetVersion() % contact->GetVersion());
461 update = false;
462 }
463 } else {
464 #ifdef __DEBUG__
465 // just for outlining, get removed anyway
466 //debug logging stuff - remove later
467 if (contact->GetUDPKey().GetKeyValue(theApp->GetPublicIP(false)) == 0) {
468 if (contact->GetVersion() >= 6 && contact->GetType() < 2) {
469 AddDebugLogLineN(logKadRouting, wxT("Updating > 0.49a + type < 2 contact without valid key stored ") + KadIPToString(contact->GetIPAddress()));
470 }
471 } else {
472 AddDebugLogLineN(logKadRouting, wxT("Updating contact, passed key check ") + KadIPToString(contact->GetIPAddress()));
473 }
474
475 if (contactUpdate->GetVersion() >= 1 && contactUpdate->GetVersion() < 6) {
476 wxASSERT(!contactUpdate->GetReceivedHelloPacket());
477 AddDebugLogLineN(logKadRouting, CFormat(wxT("Accepted update for legacy kad2 contact, because of first HELLO (%s -> %s, %u -> %u)"))
478 % KadIPToString(contactUpdate->GetIPAddress()) % KadIPToString(contact->GetIPAddress()) % contactUpdate->GetVersion() % contact->GetVersion());
479 }
480 #endif
481 // All other nodes (Kad1, Kad2 > 0.49a with UDPKey checked or not set, first hello updates) are allowed to do full updates
482 // do not let Kad1 responses overwrite Kad2 ones
483 if (m_bin->ChangeContactIPAddress(contactUpdate, contact->GetIPAddress()) && contact->GetVersion() >= contactUpdate->GetVersion()) {
484 contactUpdate->SetUDPPort(contact->GetUDPPort());
485 contactUpdate->SetTCPPort(contact->GetTCPPort());
486 contactUpdate->SetVersion(contact->GetVersion());
487 contactUpdate->SetUDPKey(contact->GetUDPKey());
488 // don't unset the verified flag (will clear itself on ipchanges)
489 if (!contactUpdate->IsIPVerified()) {
490 contactUpdate->SetIPVerified(contact->IsIPVerified());
491 }
492 outIpVerified = contactUpdate->IsIPVerified();
493 m_bin->SetAlive(contactUpdate);
494 if (contact->GetReceivedHelloPacket()) {
495 contactUpdate->SetReceivedHelloPacket();
496 }
497 } else {
498 update = false;
499 }
500 }
501 }
502 return false;
503 } else if (m_bin->GetRemaining()) {
504 update = false;
505 // This bin is not full, so add the new contact
506 return m_bin->AddContact(contact);
507 } else if (CanSplit()) {
508 // This bin was full and split, call add on the correct branch.
509 Split();
510 return m_subZones[contact->GetDistance().GetBitNumber(m_level)]->Add(contact, update, outIpVerified);
511 } else {
512 update = false;
513 return false;
514 }
515 }
516 }
517
518 CContact *CRoutingZone::GetContact(const CUInt128& id) const throw()
519 {
520 if (IsLeaf()) {
521 return m_bin->GetContact(id);
522 } else {
523 CUInt128 distance = CKademlia::GetPrefs()->GetKadID();
524 distance ^= id;
525 return m_subZones[distance.GetBitNumber(m_level)]->GetContact(id);
526 }
527 }
528
529 CContact *CRoutingZone::GetContact(uint32_t ip, uint16_t port, bool tcpPort) const throw()
530 {
531 if (IsLeaf()) {
532 return m_bin->GetContact(ip, port, tcpPort);
533 } else {
534 CContact *contact = m_subZones[0]->GetContact(ip, port, tcpPort);
535 return (contact != NULL) ? contact : m_subZones[1]->GetContact(ip, port, tcpPort);
536 }
537 }
538
539 CContact *CRoutingZone::GetRandomContact(uint32_t maxType, uint32_t minKadVersion) const
540 {
541 if (IsLeaf()) {
542 return m_bin->GetRandomContact(maxType, minKadVersion);
543 } else {
544 unsigned zone = GetRandomUint16() & 1 /* GetRandomUint16() % 2 */;
545 CContact *contact = m_subZones[zone]->GetRandomContact(maxType, minKadVersion);
546 return (contact != NULL) ? contact : m_subZones[1 - zone]->GetRandomContact(maxType, minKadVersion);
547 }
548 }
549
550 void CRoutingZone::GetClosestTo(uint32_t maxType, const CUInt128& target, const CUInt128& distance, uint32_t maxRequired, ContactMap *result, bool emptyFirst, bool inUse) const
551 {
552 // If leaf zone, do it here
553 if (IsLeaf()) {
554 m_bin->GetClosestTo(maxType, target, maxRequired, result, emptyFirst, inUse);
555 return;
556 }
557
558 // otherwise, recurse in the closer-to-the-target subzone first
559 int closer = distance.GetBitNumber(m_level);
560 m_subZones[closer]->GetClosestTo(maxType, target, distance, maxRequired, result, emptyFirst, inUse);
561
562 // if still not enough tokens found, recurse in the other subzone too
563 if (result->size() < maxRequired) {
564 m_subZones[1-closer]->GetClosestTo(maxType, target, distance, maxRequired, result, false, inUse);
565 }
566 }
567
568 void CRoutingZone::GetAllEntries(ContactList *result, bool emptyFirst) const
569 {
570 if (IsLeaf()) {
571 m_bin->GetEntries(result, emptyFirst);
572 } else {
573 m_subZones[0]->GetAllEntries(result, emptyFirst);
574 m_subZones[1]->GetAllEntries(result, false);
575 }
576 }
577
578 void CRoutingZone::TopDepth(int depth, ContactList *result, bool emptyFirst) const
579 {
580 if (IsLeaf()) {
581 m_bin->GetEntries(result, emptyFirst);
582 } else if (depth <= 0) {
583 RandomBin(result, emptyFirst);
584 } else {
585 m_subZones[0]->TopDepth(depth-1, result, emptyFirst);
586 m_subZones[1]->TopDepth(depth-1, result, false);
587 }
588 }
589
590 void CRoutingZone::RandomBin(ContactList *result, bool emptyFirst) const
591 {
592 if (IsLeaf()) {
593 m_bin->GetEntries(result, emptyFirst);
594 } else {
595 m_subZones[rand()&1]->RandomBin(result, emptyFirst);
596 }
597 }
598
599 uint32_t CRoutingZone::GetMaxDepth() const throw()
600 {
601 if (IsLeaf()) {
602 return 0;
603 }
604 return 1 + std::max(m_subZones[0]->GetMaxDepth(), m_subZones[1]->GetMaxDepth());
605 }
606
607 void CRoutingZone::Split()
608 {
609 StopTimer();
610
611 m_subZones[0] = GenSubZone(0);
612 m_subZones[1] = GenSubZone(1);
613
614 ContactList entries;
615 m_bin->GetEntries(&entries);
616 m_bin->m_dontDeleteContacts = true;
617 delete m_bin;
618 m_bin = NULL;
619
620 for (ContactList::const_iterator it = entries.begin(); it != entries.end(); ++it) {
621 if (!m_subZones[(*it)->GetDistance().GetBitNumber(m_level)]->m_bin->AddContact(*it)) {
622 delete *it;
623 }
624 }
625 }
626
627 uint32_t CRoutingZone::Consolidate()
628 {
629 uint32_t mergeCount = 0;
630
631 if (IsLeaf()) {
632 return mergeCount;
633 }
634
635 wxASSERT(m_bin == NULL);
636
637 if (!m_subZones[0]->IsLeaf()) {
638 mergeCount += m_subZones[0]->Consolidate();
639 }
640 if (!m_subZones[1]->IsLeaf()) {
641 mergeCount += m_subZones[1]->Consolidate();
642 }
643
644 if (m_subZones[0]->IsLeaf() && m_subZones[1]->IsLeaf() && GetNumContacts() < K / 2) {
645 m_bin = new CRoutingBin();
646
647 m_subZones[0]->StopTimer();
648 m_subZones[1]->StopTimer();
649
650 ContactList list0;
651 ContactList list1;
652 m_subZones[0]->m_bin->GetEntries(&list0);
653 m_subZones[1]->m_bin->GetEntries(&list1);
654
655 m_subZones[0]->m_bin->m_dontDeleteContacts = true;
656 m_subZones[1]->m_bin->m_dontDeleteContacts = true;
657
658 delete m_subZones[0];
659 delete m_subZones[1];
660
661 m_subZones[0] = NULL;
662 m_subZones[1] = NULL;
663
664 for (ContactList::const_iterator it = list0.begin(); it != list0.end(); ++it) {
665 m_bin->AddContact(*it);
666 }
667 for (ContactList::const_iterator it = list1.begin(); it != list1.end(); ++it) {
668 m_bin->AddContact(*it);
669 }
670
671 StartTimer();
672
673 mergeCount++;
674 }
675 return mergeCount;
676 }
677
678 CRoutingZone *CRoutingZone::GenSubZone(unsigned side)
679 {
680 wxASSERT(side <= 1);
681
682 CUInt128 newIndex(m_zoneIndex);
683 newIndex <<= 1;
684 newIndex += side;
685 return new CRoutingZone(this, m_level + 1, newIndex);
686 }
687
688 void CRoutingZone::StartTimer()
689 {
690 // Start filling the tree, closest bins first.
691 m_nextBigTimer = time(NULL) + SEC(10);
692 CKademlia::AddEvent(this);
693 }
694
695 void CRoutingZone::StopTimer()
696 {
697 CKademlia::RemoveEvent(this);
698 }
699
700 bool CRoutingZone::OnBigTimer() const
701 {
702 if (IsLeaf() && (m_zoneIndex < KK || m_level < KBASE || m_bin->GetRemaining() >= (K * 0.8))) {
703 RandomLookup();
704 return true;
705 }
706
707 return false;
708 }
709
710 //This is used when we find a leaf and want to know what this sample looks like.
711 //We fall back two levels and take a sample to try to minimize any areas of the
712 //tree that will give very bad results.
713 uint32_t CRoutingZone::EstimateCount() const
714 {
715 if (!IsLeaf()) {
716 return 0;
717 }
718
719 if (m_level < KBASE) {
720 return (uint32_t)(pow(2.0, (int)m_level) * K);
721 }
722
723 CRoutingZone* curZone = m_superZone->m_superZone->m_superZone;
724
725 // Find out how full this part of the tree is.
726 float modify = ((float)curZone->GetNumContacts()) / (float)(K * 2);
727
728 // First calculate users assuming the tree is full.
729 // Modify count by bin size.
730 // Modify count by how full the tree is.
731
732 // LowIDModififier
733 // Modify count by assuming 20% of the users are firewalled and can't be a contact for < 0.49b nodes
734 // Modify count by actual statistics of Firewalled ratio for >= 0.49b if we are not firewalled ourself
735 // Modify count by 40% for >= 0.49b if we are firewalled ourself (the actual Firewalled count at this date on kad is 35-55%)
736 const float firewalledModifyOld = 1.20f;
737 float firewalledModifyNew = 0;
738 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
739 firewalledModifyNew = 1.40f; // we are firewalled and can't get the real statistics, assume 40% firewalled >=0.49b nodes
740 } else if (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true) > 0) {
741 firewalledModifyNew = 1.0 + (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true)); // apply the firewalled ratio to the modify
742 wxASSERT(firewalledModifyNew > 1.0 && firewalledModifyNew < 1.90);
743 }
744 float newRatio = CKademlia::GetPrefs()->StatsGetKadV8Ratio();
745 float firewalledModifyTotal = 0;
746 if (newRatio > 0 && firewalledModifyNew > 0) { // weight the old and the new modifier based on how many new contacts we have
747 firewalledModifyTotal = (newRatio * firewalledModifyNew) + ((1 - newRatio) * firewalledModifyOld);
748 } else {
749 firewalledModifyTotal = firewalledModifyOld;
750 }
751 wxASSERT(firewalledModifyTotal > 1.0 && firewalledModifyTotal < 1.90);
752
753 return (uint32_t)(pow(2.0, (int)m_level - 2) * (float)K * modify * firewalledModifyTotal);
754 }
755
756 void CRoutingZone::OnSmallTimer()
757 {
758 if (!IsLeaf()) {
759 return;
760 }
761
762 CContact *c = NULL;
763 time_t now = time(NULL);
764 ContactList entries;
765
766 // Remove dead entries
767 m_bin->GetEntries(&entries);
768 for (ContactList::iterator it = entries.begin(); it != entries.end(); ++it) {
769 c = *it;
770 if (c->GetType() == 4) {
771 if ((c->GetExpireTime() > 0) && (c->GetExpireTime() <= now)) {
772 if (!c->InUse()) {
773 m_bin->RemoveContact(c);
774 delete c;
775 }
776 continue;
777 }
778 }
779 if(c->GetExpireTime() == 0) {
780 c->SetExpireTime(now);
781 }
782 }
783
784 c = m_bin->GetOldest();
785 if (c != NULL) {
786 if (c->GetExpireTime() >= now || c->GetType() == 4) {
787 m_bin->PushToBottom(c);
788 c = NULL;
789 }
790 }
791
792 if (c != NULL) {
793 c->CheckingType();
794 if (c->GetVersion() >= 6) {
795 DebugSend(Kad2HelloReq, c->GetIPAddress(), c->GetUDPPort());
796 CUInt128 clientID = c->GetClientID();
797 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, c->GetIPAddress(), c->GetUDPPort(), c->GetVersion(), c->GetUDPKey(), &clientID, false);
798 if (c->GetVersion() >= 8) {
799 // FIXME:
800 // This is a bit of a work around for statistic values. Normally we only count values from incoming HELLO_REQs for
801 // the firewalled statistics in order to get numbers from nodes which have us on their routing table,
802 // however if we send a HELLO due to the timer, the remote node won't send a HELLO_REQ itself anymore (but
803 // a HELLO_RES which we don't count), so count those statistics here. This isn't really accurate, but it should
804 // do fair enough. Maybe improve it later for example by putting a flag into the contact and make the answer count
805 CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(false);
806 CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(false);
807 }
808 } else if (c->GetVersion() >= 2) {
809 DebugSend(Kad2HelloReq, c->GetIPAddress(), c->GetUDPPort());
810 CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, c->GetIPAddress(), c->GetUDPPort(), c->GetVersion(), 0, NULL, false);
811 wxASSERT(c->GetUDPKey() == CKadUDPKey(0));
812 } else {
813 AddDebugLogLineN(logKadRouting, CFormat(wxT("Ignoring Kad contact %s version %d.")) % KadIPToString(c->GetIPAddress()) % c->GetVersion());
814 //wxFAIL; // thanks, I'm having enough problems without any Kad asserts
815 }
816 }
817 }
818
819 void CRoutingZone::RandomLookup() const
820 {
821 // Look-up a random client in this zone
822 CUInt128 prefix(m_zoneIndex);
823 prefix <<= 128 - m_level;
824 CUInt128 random(prefix, m_level);
825 random ^= me;
826 CSearchManager::FindNode(random, false);
827 }
828
829 uint32_t CRoutingZone::GetNumContacts() const throw()
830 {
831 if (IsLeaf()) {
832 return m_bin->GetSize();
833 } else {
834 return m_subZones[0]->GetNumContacts() + m_subZones[1]->GetNumContacts();
835 }
836 }
837
838 void CRoutingZone::GetNumContacts(uint32_t& nInOutContacts, uint32_t& nInOutFilteredContacts, uint8_t minVersion) const throw()
839 {
840 if (IsLeaf()) {
841 m_bin->GetNumContacts(nInOutContacts, nInOutFilteredContacts, minVersion);
842 } else {
843 m_subZones[0]->GetNumContacts(nInOutContacts, nInOutFilteredContacts, minVersion);
844 m_subZones[1]->GetNumContacts(nInOutContacts, nInOutFilteredContacts, minVersion);
845 }
846 }
847
848 uint32_t CRoutingZone::GetBootstrapContacts(ContactList *results, uint32_t maxRequired) const
849 {
850 wxASSERT(m_superZone == NULL);
851
852 results->clear();
853
854 uint32_t count = 0;
855 ContactList top;
856 TopDepth(LOG_BASE_EXPONENT, &top);
857 if (!top.empty()) {
858 for (ContactList::const_iterator it = top.begin(); it != top.end(); ++it) {
859 results->push_back(*it);
860 count++;
861 if (count == maxRequired) {
862 break;
863 }
864 }
865 }
866
867 return count;
868 }
869
870 bool CRoutingZone::VerifyContact(const CUInt128& id, uint32_t ip)
871 {
872 CContact* contact = GetContact(id);
873 if (contact == NULL) {
874 return false;
875 } else if (ip != contact->GetIPAddress()) {
876 return false;
877 } else {
878 if (contact->IsIPVerified()) {
879 AddDebugLogLineN(logKadRouting, wxT("Sender already verified (sender: ") + KadIPToString(ip) + wxT(")"));
880 } else {
881 contact->SetIPVerified(true);
882 }
883 return true;
884 }
885 }
886
887 void CRoutingZone::SetAllContactsVerified()
888 {
889 if (IsLeaf()) {
890 m_bin->SetAllContactsVerified();
891 } else {
892 m_subZones[0]->SetAllContactsVerified();
893 m_subZones[1]->SetAllContactsVerified();
894 }
895 }
896
897 bool CRoutingZone::IsAcceptableContact(const CContact *toCheck) const
898 {
899 // 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
900 // we use this to check KADEMLIA_RES routing answers on searches
901 if (toCheck->GetVersion() <= 1) {
902 // No Kad1 contacts allowed
903 return false;
904 }
905 CContact *duplicate = GetContact(toCheck->GetClientID());
906 if (duplicate != NULL) {
907 if ((duplicate->IsIPVerified() && duplicate->GetIPAddress() != toCheck->GetIPAddress()) || duplicate->GetUDPPort() != toCheck->GetUDPPort()) {
908 // already existing verified node with different IP
909 return false;
910 } else {
911 // node exists already in our routing table, that's fine
912 return true;
913 }
914 }
915 // if the node is not yet known, check if our IP limitations would hit
916 return CRoutingBin::CheckGlobalIPLimits(toCheck->GetIPAddress(), toCheck->GetUDPPort());
917 }
918
919 bool CRoutingZone::HasOnlyLANNodes() const throw()
920 {
921 if (IsLeaf()) {
922 return m_bin->HasOnlyLANNodes();
923 } else {
924 return m_subZones[0]->HasOnlyLANNodes() && m_subZones[1]->HasOnlyLANNodes();
925 }
926 }
927