1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 Angel Vidal ( kry@amule.org )
5 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2003-2011 Barry Dunne (http://www.emule-project.net)
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 //
26
27 // Note To Mods //
28 /*
29 Please do not change anything here and release it..
30 There is going to be a new forum created just for the Kademlia side of the client..
31 If you feel there is an error or a way to improve something, please
32 post it in the forum first and let us look at it.. If it is a real improvement,
33 it will be added to the offical client.. Changing something without knowing
34 what all it does can cause great harm to the network if released in mass form..
35 Any mod that changes anything within the Kademlia side will not be allowed to advertise
36 there client on the eMule forum..
37 */
38
39 #include "Kademlia.h" // Interface declarations
40
41 #include <protocol/kad/Constants.h>
42
43 #include "Defines.h"
44 #include "Indexed.h"
45 #include "UDPFirewallTester.h"
46 #include "../routing/RoutingZone.h"
47 #include "../utils/KadUDPKey.h"
48 #include "../utils/KadClientSearcher.h"
49 #include "../../amule.h"
50 #include "../../Logger.h"
51 #include <protocol/kad2/Client2Client/UDP.h>
52
53 #ifdef _MSC_VER // silly warnings about deprecated functions
54 #pragma warning(disable:4996)
55 #endif
56
57 const CUInt128 Kademlia::s_nullUInt128(false);
58
59 ////////////////////////////////////////
60 using namespace Kademlia;
61 ////////////////////////////////////////
62
63 CKademlia * CKademlia::instance = NULL;
64 EventMap CKademlia::m_events;
65 time_t CKademlia::m_nextSearchJumpStart;
66 time_t CKademlia::m_nextSelfLookup;
67 time_t CKademlia::m_statusUpdate;
68 time_t CKademlia::m_bigTimer;
69 time_t CKademlia::m_nextFirewallCheck;
70 time_t CKademlia::m_nextFindBuddy;
71 time_t CKademlia::m_bootstrap;
72 time_t CKademlia::m_consolidate;
73 time_t CKademlia::m_externPortLookup;
74 time_t CKademlia::m_lanModeCheck = 0;
75 bool CKademlia::m_running = false;
76 bool CKademlia::m_lanMode = false;
77 ContactList CKademlia::s_bootstrapList;
78 std::list<uint32_t> CKademlia::m_statsEstUsersProbes;
79
Start(CPrefs * prefs)80 void CKademlia::Start(CPrefs *prefs)
81 {
82 if (instance) {
83 // If we already have an instance, something is wrong.
84 delete prefs;
85 wxASSERT(instance->m_running);
86 wxASSERT(instance->m_prefs);
87 return;
88 }
89
90 // Make sure a prefs was passed in..
91 if (!prefs) {
92 return;
93 }
94
95 AddDebugLogLineN(logKadMain, wxT("Starting Kademlia"));
96
97 // Init jump start timer.
98 m_nextSearchJumpStart = time(NULL);
99 // Force a FindNodeComplete within the first 3 minutes.
100 m_nextSelfLookup = time(NULL) + MIN2S(3);
101 // Init status timer.
102 m_statusUpdate = time(NULL);
103 // Init big timer for Zones
104 m_bigTimer = time(NULL);
105 // First Firewall check is done on connect, init next check.
106 m_nextFirewallCheck = time(NULL) + (HR2S(1));
107 // Find a buddy after the first 5mins of starting the client.
108 // We wait just in case it takes a bit for the client to determine firewall status..
109 m_nextFindBuddy = time(NULL) + (MIN2S(5));
110 // Init contact consolidate timer;
111 m_consolidate = time(NULL) + (MIN2S(45));
112 // Look up our extern port
113 m_externPortLookup = time(NULL);
114 // Init bootstrap time.
115 m_bootstrap = 0;
116 // Init our random seed.
117 srand((uint32_t)time(NULL));
118 // Create our Kad objects.
119 instance = new CKademlia();
120 instance->m_prefs = prefs;
121 instance->m_indexed = new CIndexed();
122 instance->m_routingZone = new CRoutingZone();
123 instance->m_udpListener = new CKademliaUDPListener();
124 // Mark Kad as running state.
125 m_running = true;
126 }
127
128
Stop()129 void CKademlia::Stop()
130 {
131 // Make sure we are running to begin with.
132 if (!m_running) {
133 return;
134 }
135
136 AddDebugLogLineN(logKadMain, wxT("Stopping Kademlia"));
137
138 // Mark Kad as being in the stop state to make sure nothing else is used.
139 m_running = false;
140
141 // Reset Firewallstate
142 CUDPFirewallTester::Reset();
143
144 // Remove all active searches.
145 CSearchManager::StopAllSearches();
146
147 // Delete all Kad Objects.
148 delete instance->m_udpListener;
149 instance->m_udpListener = NULL;
150
151 delete instance->m_routingZone;
152 instance->m_routingZone = NULL;
153
154 delete instance->m_indexed;
155 instance->m_indexed = NULL;
156
157 delete instance->m_prefs;
158 instance->m_prefs = NULL;
159
160 delete instance;
161 instance = NULL;
162
163 for (ContactList::iterator it = s_bootstrapList.begin(); it != s_bootstrapList.end(); ++it) {
164 delete *it;
165 }
166 s_bootstrapList.clear();
167
168 // Make sure all zones are removed.
169 m_events.clear();
170
171 // theApp->ShowConnectionState();
172 }
173
Process()174 void CKademlia::Process()
175 {
176
177 if (instance == NULL || !m_running) {
178 return;
179 }
180
181 time_t now = time(NULL);
182 uint32_t maxUsers = 0;
183 uint32_t tempUsers = 0;
184 uint32_t lastContact = 0;
185 bool updateUserFile = false;
186
187 wxASSERT(instance->m_prefs != NULL);
188 lastContact = instance->m_prefs->GetLastContact();
189 CSearchManager::UpdateStats();
190
191 if (m_statusUpdate <= now) {
192 updateUserFile = true;
193 m_statusUpdate = MIN2S(1) + now;
194 }
195
196 if (m_nextFirewallCheck <= now) {
197 RecheckFirewalled();
198 }
199
200 if (m_nextSelfLookup <= now) {
201 CSearchManager::FindNode(instance->m_prefs->GetKadID(), true);
202 m_nextSelfLookup = HR2S(4) + now;
203 }
204
205 if (m_nextFindBuddy <= now) {
206 instance->m_prefs->SetFindBuddy();
207 m_nextFindBuddy = MIN2S(20) + now;
208 }
209
210 if (m_externPortLookup <= now && CUDPFirewallTester::IsFWCheckUDPRunning() && GetPrefs()->FindExternKadPort(false)) {
211 // If our UDP firewallcheck is running and we don't know our external port, we send a request every 15 seconds
212 CContact *contact = GetRoutingZone()->GetRandomContact(3, 6);
213 if (contact != NULL) {
214 AddDebugLogLineN(logKadPrefs, wxT("Requesting our external port from ") + KadIPToString(contact->GetIPAddress()));
215 DebugSend(Kad2Ping, contact->GetIPAddress(), contact->GetUDPPort());
216 GetUDPListener()->SendNullPacket(KADEMLIA2_PING, contact->GetIPAddress(), contact->GetUDPPort(), contact->GetUDPKey(), &contact->GetClientID());
217 } else {
218 AddDebugLogLineN(logKadPrefs, wxT("No valid client for requesting external port available"));
219 }
220 m_externPortLookup = 15 + now;
221 }
222
223 for (EventMap::const_iterator it = m_events.begin(); it != m_events.end(); ++it) {
224 CRoutingZone *zone = it->first;
225 if (updateUserFile) {
226 // The EstimateCount function is not made for really small networks, if we are in LAN mode, it is actually
227 // better to assume that all users of the network are in our routing table and use the real count function
228 if (IsRunningInLANMode()) {
229 tempUsers = zone->GetNumContacts();
230 } else {
231 tempUsers = zone->EstimateCount();
232 }
233 if (maxUsers < tempUsers) {
234 maxUsers = tempUsers;
235 }
236 }
237
238 if (m_bigTimer <= now) {
239 if (zone->m_nextBigTimer <= now) {
240 if(zone->OnBigTimer()) {
241 zone->m_nextBigTimer = HR2S(1) + now;
242 m_bigTimer = SEC(10) + now;
243 }
244 } else {
245 if (lastContact && (now - lastContact > KADEMLIADISCONNECTDELAY - MIN2S(5))) {
246 if(zone->OnBigTimer()) {
247 zone->m_nextBigTimer = HR2S(1) + now;
248 m_bigTimer = SEC(10) + now;
249 }
250 }
251 }
252 }
253
254 if (zone->m_nextSmallTimer <= now) {
255 zone->OnSmallTimer();
256 zone->m_nextSmallTimer = MIN2S(1) + now;
257 }
258 }
259
260 // This is a convenient place to add this, although not related to routing
261 if (m_nextSearchJumpStart <= now) {
262 CSearchManager::JumpStart();
263 m_nextSearchJumpStart = SEARCH_JUMPSTART + now;
264 }
265
266 // Try to consolidate any zones that are close to empty.
267 if (m_consolidate <= now) {
268 uint32_t mergedCount = instance->m_routingZone->Consolidate();
269 if (mergedCount) {
270 AddDebugLogLineN(logKadRouting, CFormat(wxT("Kad merged %u zones")) % mergedCount);
271 }
272 m_consolidate = MIN2S(45) + now;
273 }
274
275 // Update user count only if changed.
276 if (updateUserFile) {
277 if (maxUsers != instance->m_prefs->GetKademliaUsers()) {
278 instance->m_prefs->SetKademliaUsers(maxUsers);
279 instance->m_prefs->SetKademliaFiles();
280 theApp->ShowUserCount();
281 }
282 }
283
284 if (!IsConnected() && !s_bootstrapList.empty() && (now - m_bootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && now - m_bootstrap >= 2))) {
285 CContact *contact = s_bootstrapList.front();
286 s_bootstrapList.pop_front();
287 m_bootstrap = now;
288 AddDebugLogLineN(logKadMain, CFormat(wxT("Trying to bootstrap Kad from %s, Distance: %s Version: %u, %u contacts left"))
289 % KadIPToString(contact->GetIPAddress()) % contact->GetDistance().ToHexString() % contact->GetVersion() % s_bootstrapList.size());
290 instance->m_udpListener->Bootstrap(contact->GetIPAddress(), contact->GetUDPPort(), contact->GetVersion(), &contact->GetClientID());
291 delete contact;
292 }
293
294 if (GetUDPListener() != NULL) {
295 GetUDPListener()->ExpireClientSearch(); // function does only one compare in most cases, so no real need for a timer
296 }
297 }
298
ProcessPacket(const uint8_t * data,uint32_t lenData,uint32_t ip,uint16_t port,bool validReceiverKey,const CKadUDPKey & senderKey)299 void CKademlia::ProcessPacket(const uint8_t *data, uint32_t lenData, uint32_t ip, uint16_t port, bool validReceiverKey, const CKadUDPKey& senderKey)
300 {
301 try {
302 if( instance && instance->m_udpListener ) {
303 instance->m_udpListener->ProcessPacket(data, lenData, ip, port, validReceiverKey, senderKey);
304 }
305 } catch (const wxString& DEBUG_ONLY(error)) {
306 AddDebugLogLineN(logKadMain, CFormat(wxT("Exception on Kad ProcessPacket while processing packet (length = %u) from %s:"))
307 % lenData % KadIPPortToString(ip, port));
308 AddDebugLogLineN(logKadMain, error);
309 throw;
310 } catch (...) {
311 AddDebugLogLineN(logKadMain, wxT("Unhandled exception on Kad ProcessPacket"));
312 throw;
313 }
314 }
315
RecheckFirewalled()316 void CKademlia::RecheckFirewalled()
317 {
318 if (instance && instance->m_prefs && !IsRunningInLANMode()) {
319 // Something is forcing a new firewall check
320 // Stop any new buddy requests, and tell the client
321 // to recheck it's IP which in turns rechecks firewall.
322 instance->m_prefs->SetFindBuddy(false);
323 instance->m_prefs->SetRecheckIP();
324 // also UDP check
325 CUDPFirewallTester::ReCheckFirewallUDP(false);
326 time_t now = time(NULL);
327 // Delay the next buddy search to at least 5 minutes after our firewallcheck so we are sure to be still firewalled
328 m_nextFindBuddy = (m_nextFindBuddy < MIN2S(5) + now) ? MIN2S(5) + now : m_nextFindBuddy;
329 m_nextFirewallCheck = HR2S(1) + now;
330 }
331 }
332
333 #if 0 // currently unused function
334 bool CKademlia::FindNodeIDByIP(CKadClientSearcher& requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort)
335 {
336 wxCHECK(IsRunning() && instance && GetUDPListener() && GetRoutingZone(), false);
337
338 // first search our known contacts if we can deliver a result without asking, otherwise forward the request
339 CContact* contact;
340 if ((contact = GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(ip), tcpPort, true)) != NULL) {
341 uint8_t nodeID[16];
342 contact->GetClientID().ToByteArray(nodeID);
343 requester.KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, nodeID);
344 return true;
345 } else {
346 return GetUDPListener()->FindNodeIDByIP(&requester, wxUINT32_SWAP_ALWAYS(ip), tcpPort, udpPort);
347 }
348 }
349 #endif
350
FindIPByNodeID(CKadClientSearcher & requester,const uint8_t * nodeID)351 bool CKademlia::FindIPByNodeID(CKadClientSearcher& requester, const uint8_t* nodeID)
352 {
353 wxCHECK(IsRunning() && instance && GetUDPListener(), false);
354
355 // first search our known contacts if we can deliver a result without asking, otherwise forward the request
356 CContact* contact;
357 if ((contact = GetRoutingZone()->GetContact(CUInt128(nodeID))) != NULL) {
358 // make sure that this entry is not too old, otherwise just do a search to be sure
359 if (contact->GetLastSeen() != 0 && time(NULL) - contact->GetLastSeen() < 1800) {
360 requester.KadSearchIPByNodeIDResult(KCSR_SUCCEEDED, wxUINT32_SWAP_ALWAYS(contact->GetIPAddress()), contact->GetTCPPort());
361 return true;
362 }
363 }
364 return CSearchManager::FindNodeSpecial(CUInt128(nodeID), &requester);
365 }
366
CancelClientSearch(CKadClientSearcher & fromRequester)367 void CKademlia::CancelClientSearch(CKadClientSearcher& fromRequester)
368 {
369 wxCHECK_RET(instance && GetUDPListener(), wxT("Something is really bad"));
370
371 GetUDPListener()->ExpireClientSearch(&fromRequester);
372 CSearchManager::CancelNodeSpecial(&fromRequester);
373 }
374
StatsAddClosestDistance(const CUInt128 & distance)375 void CKademlia::StatsAddClosestDistance(const CUInt128& distance)
376 {
377 if (distance.Get32BitChunk(0) > 0) {
378 uint32_t toAdd = (0xFFFFFFFF / distance.Get32BitChunk(0)) / 2;
379 std::list<uint32_t>::iterator it = m_statsEstUsersProbes.begin();
380 for (; it != m_statsEstUsersProbes.end(); ++it) {
381 if (*it == toAdd) {
382 break;
383 }
384 }
385 if (it == m_statsEstUsersProbes.end()) {
386 m_statsEstUsersProbes.push_front(toAdd);
387 }
388 }
389 if (m_statsEstUsersProbes.size() > 100) {
390 m_statsEstUsersProbes.pop_back();
391 }
392 }
393
CalculateKadUsersNew()394 uint32_t CKademlia::CalculateKadUsersNew()
395 {
396 // the idea of calculating the user count with this method is simple:
397 // whenever we do a search for any NodeID (except in certain cases where the result is not usable),
398 // we remember the distance of the closest node we found. Because we assume all NodeIDs are distributed
399 // equally, we can calculate based on this distance how "filled" the possible NodesID room is and by this
400 // calculate how many users there are. Of course this only works if we have enough samples, because
401 // each single sample will be wrong, but the average of them should produce a usable number. To avoid
402 // drifts caused by a a single (or more) really close or really far away hits, we do use median-average instead through
403
404 // doesn't work well if we have no files to index and nothing to download and the numbers seems to be a bit too low
405 // compared to our other method. So let's stay with the old one for now, but keep this here as an alternative
406
407 if (m_statsEstUsersProbes.size() < 10) {
408 return 0;
409 }
410 uint32_t median = 0;
411
412 std::list<uint32_t> medianList;
413 for (std::list<uint32_t>::iterator it1 = m_statsEstUsersProbes.begin(); it1 != m_statsEstUsersProbes.end(); ++it1) {
414 uint32_t probe = *it1;
415 bool inserted = false;
416 for (std::list<uint32_t>::iterator it2 = medianList.begin(); it2 != medianList.end(); ++it2) {
417 if (*it2 > probe) {
418 medianList.insert(it2, probe);
419 inserted = true;
420 break;
421 }
422 }
423 if (!inserted) {
424 medianList.push_back(probe);
425 }
426 }
427 // cut away 1/3 of the values - 1/6 of the top and 1/6 of the bottom to avoid spikes having too much influence, build the average of the rest
428 std::list<uint32_t>::size_type cut = medianList.size() / 6;
429 for (std::list<uint32_t>::size_type i = 0; i != cut; ++i) {
430 medianList.pop_front();
431 medianList.pop_back();
432 }
433 uint64_t average = 0;
434 for (std::list<uint32_t>::iterator it = medianList.begin(); it != medianList.end(); ++it) {
435 average += *it;
436 }
437 median = (uint32_t)(average / medianList.size());
438
439 // LowIDModififier
440 // Modify count by assuming 20% of the users are firewalled and can't be a contact for < 0.49b nodes
441 // Modify count by actual statistics of Firewalled ratio for >= 0.49b if we are not firewalled ourself
442 // Modify count by 40% for >= 0.49b if we are firewalled ourself (the actual Firewalled count at this date on kad is 35-55%)
443 const float firewalledModifyOld = 1.20f;
444 float firewalledModifyNew = 0.0;
445 if (CUDPFirewallTester::IsFirewalledUDP(true)) {
446 firewalledModifyNew = 1.40f; // we are firewalled and can't get the real statistics, assume 40% firewalled >=0.49b nodes
447 } else if (GetPrefs()->StatsGetFirewalledRatio(true) > 0) {
448 firewalledModifyNew = 1.0 + (CKademlia::GetPrefs()->StatsGetFirewalledRatio(true)); // apply the firewalled ratio to the modify
449 wxASSERT(firewalledModifyNew > 1.0 && firewalledModifyNew < 1.90);
450 }
451 float newRatio = CKademlia::GetPrefs()->StatsGetKadV8Ratio();
452 float firewalledModifyTotal = 0.0;
453 if (newRatio > 0 && firewalledModifyNew > 0) { // weigth the old and the new modifier based on how many new contacts we have
454 firewalledModifyTotal = (newRatio * firewalledModifyNew) + ((1 - newRatio) * firewalledModifyOld);
455 } else {
456 firewalledModifyTotal = firewalledModifyOld;
457 }
458 wxASSERT(firewalledModifyTotal > 1.0 && firewalledModifyTotal < 1.90);
459
460 return (uint32_t)((float)median * firewalledModifyTotal);
461 }
462
IsRunningInLANMode()463 bool CKademlia::IsRunningInLANMode()
464 {
465 if (thePrefs::FilterLanIPs() || !IsRunning()) {
466 return false;
467 }
468
469 time_t now = time(NULL);
470 if (m_lanModeCheck + 10 <= now) {
471 m_lanModeCheck = now;
472 uint32_t count = GetRoutingZone()->GetNumContacts();
473 // Limit to 256 nodes, if we have more we don't want to use the LAN mode which is assuming we use a small home LAN
474 // (otherwise we might need to do firewallcheck, external port requests etc after all)
475 if (count == 0 || count > 256) {
476 m_lanMode = false;
477 } else {
478 if (GetRoutingZone()->HasOnlyLANNodes()) {
479 if (!m_lanMode) {
480 m_lanMode = true;
481 theApp->ShowConnectionState();
482 AddDebugLogLineN(logKadMain, wxT("Activating LAN mode"));
483 }
484 } else {
485 if (m_lanMode) {
486 m_lanMode = false;
487 theApp->ShowConnectionState();
488 AddDebugLogLineN(logKadMain, wxT("Deactivating LAN mode"));
489 }
490 }
491 }
492 }
493 return m_lanMode;
494 }
495
496
497 // Global function.
498
499 #include "../../CryptoPP_Inc.h"
KadGetKeywordHash(const wxString & rstrKeyword,Kademlia::CUInt128 * pKadID)500 void KadGetKeywordHash(const wxString& rstrKeyword, Kademlia::CUInt128* pKadID)
501 {
502 uint8_t Output[16];
503
504 CryptoPP::Weak::MD4 md4_hasher;
505
506 // This should be safe - we assume rstrKeyword is ANSI anyway.
507 char* ansi_buffer = strdup(unicode2UTF8(rstrKeyword));
508
509 //printf("Kad keyword hash: UTF8 %s\n",ansi_buffer);
510 md4_hasher.CalculateDigest(Output,(const unsigned char*)ansi_buffer,strlen(ansi_buffer));
511 //DumpMem(Output,16);
512 free(ansi_buffer);
513
514 pKadID->SetValueBE(Output);
515 }
516