NetDb.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. #include <string.h>
  2. #include <fstream>
  3. #include <vector>
  4. #include <boost/asio.hpp>
  5. #include <stdexcept>
  6. #include "I2PEndian.h"
  7. #include "Base.h"
  8. #include "Crypto.h"
  9. #include "Log.h"
  10. #include "Timestamp.h"
  11. #include "I2NPProtocol.h"
  12. #include "Tunnel.h"
  13. #include "Transports.h"
  14. #include "NTCP2.h"
  15. #include "RouterContext.h"
  16. #include "Garlic.h"
  17. #include "NetDb.hpp"
  18. #include "Config.h"
  19. using namespace i2p::transport;
  20. namespace i2p
  21. {
  22. namespace data
  23. {
  24. NetDb netdb;
  25. NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false)
  26. {
  27. }
  28. NetDb::~NetDb ()
  29. {
  30. Stop ();
  31. delete m_Reseeder;
  32. }
  33. void NetDb::Start ()
  34. {
  35. m_Storage.SetPlace(i2p::fs::GetDataDir());
  36. m_Storage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
  37. InitProfilesStorage ();
  38. m_Families.LoadCertificates ();
  39. Load ();
  40. uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
  41. if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold
  42. Reseed ();
  43. i2p::config::GetOption("persist.profiles", m_PersistProfiles);
  44. m_IsRunning = true;
  45. m_Thread = new std::thread (std::bind (&NetDb::Run, this));
  46. }
  47. void NetDb::Stop ()
  48. {
  49. if (m_IsRunning)
  50. {
  51. if (m_PersistProfiles)
  52. for (auto& it: m_RouterInfos)
  53. it.second->SaveProfile ();
  54. DeleteObsoleteProfiles ();
  55. m_RouterInfos.clear ();
  56. m_Floodfills.clear ();
  57. if (m_Thread)
  58. {
  59. m_IsRunning = false;
  60. m_Queue.WakeUp ();
  61. m_Thread->join ();
  62. delete m_Thread;
  63. m_Thread = 0;
  64. }
  65. m_LeaseSets.clear();
  66. m_Requests.Stop ();
  67. }
  68. }
  69. void NetDb::Run ()
  70. {
  71. uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
  72. while (m_IsRunning)
  73. {
  74. try
  75. {
  76. auto msg = m_Queue.GetNextWithTimeout (15000); // 15 sec
  77. if (msg)
  78. {
  79. int numMsgs = 0;
  80. while (msg)
  81. {
  82. LogPrint(eLogDebug, "NetDb: got request with type ", (int) msg->GetTypeID ());
  83. switch (msg->GetTypeID ())
  84. {
  85. case eI2NPDatabaseStore:
  86. HandleDatabaseStoreMsg (msg);
  87. break;
  88. case eI2NPDatabaseSearchReply:
  89. HandleDatabaseSearchReplyMsg (msg);
  90. break;
  91. case eI2NPDatabaseLookup:
  92. HandleDatabaseLookupMsg (msg);
  93. break;
  94. case eI2NPDummyMsg:
  95. // plain RouterInfo from NTCP2 with flags for now
  96. HandleNTCP2RouterInfoMsg (msg);
  97. break;
  98. default: // WTF?
  99. LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
  100. //i2p::HandleI2NPMessage (msg);
  101. }
  102. if (numMsgs > 100) break;
  103. msg = m_Queue.Get ();
  104. numMsgs++;
  105. }
  106. }
  107. if (!m_IsRunning) break;
  108. uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
  109. if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
  110. {
  111. m_Requests.ManageRequests ();
  112. lastManageRequest = ts;
  113. }
  114. if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
  115. {
  116. if (lastSave)
  117. {
  118. SaveUpdated ();
  119. ManageLeaseSets ();
  120. }
  121. lastSave = ts;
  122. }
  123. if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
  124. {
  125. i2p::context.CleanupDestination ();
  126. lastDestinationCleanup = ts;
  127. }
  128. if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // update timestamp and publish
  129. {
  130. i2p::context.UpdateTimestamp (ts);
  131. if (!m_HiddenMode) Publish ();
  132. lastPublish = ts;
  133. }
  134. if (ts - lastExploratory >= 30) // exploratory every 30 seconds
  135. {
  136. auto numRouters = m_RouterInfos.size ();
  137. if (!numRouters)
  138. throw std::runtime_error("No known routers, reseed seems to be totally failed");
  139. else // we have peers now
  140. m_FloodfillBootstrap = nullptr;
  141. if (numRouters < 2500 || ts - lastExploratory >= 90)
  142. {
  143. numRouters = 800/numRouters;
  144. if (numRouters < 1) numRouters = 1;
  145. if (numRouters > 9) numRouters = 9;
  146. m_Requests.ManageRequests ();
  147. if(!m_HiddenMode)
  148. Explore (numRouters);
  149. lastExploratory = ts;
  150. }
  151. }
  152. }
  153. catch (std::exception& ex)
  154. {
  155. LogPrint (eLogError, "NetDb: runtime exception: ", ex.what ());
  156. }
  157. }
  158. }
  159. void NetDb::SetHidden(bool hide)
  160. {
  161. // TODO: remove reachable addresses from router info
  162. m_HiddenMode = hide;
  163. }
  164. bool NetDb::AddRouterInfo (const uint8_t * buf, int len)
  165. {
  166. bool updated;
  167. AddRouterInfo (buf, len, updated);
  168. return updated;
  169. }
  170. std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
  171. {
  172. IdentityEx identity;
  173. if (identity.FromBuffer (buf, len))
  174. return AddRouterInfo (identity.GetIdentHash (), buf, len, updated);
  175. updated = false;
  176. return nullptr;
  177. }
  178. bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
  179. {
  180. bool updated;
  181. AddRouterInfo (ident, buf, len, updated);
  182. return updated;
  183. }
  184. std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated)
  185. {
  186. updated = true;
  187. auto r = FindRouter (ident);
  188. if (r)
  189. {
  190. if (r->IsNewer (buf, len))
  191. {
  192. bool wasFloodfill = r->IsFloodfill ();
  193. r->Update (buf, len);
  194. LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
  195. if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
  196. {
  197. LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
  198. std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  199. if (wasFloodfill)
  200. m_Floodfills.remove (r);
  201. else
  202. m_Floodfills.push_back (r);
  203. }
  204. }
  205. else
  206. {
  207. LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
  208. updated = false;
  209. }
  210. }
  211. else
  212. {
  213. r = std::make_shared<RouterInfo> (buf, len);
  214. if (!r->IsUnreachable () && r->HasValidAddresses ())
  215. {
  216. bool inserted = false;
  217. {
  218. std::unique_lock<std::mutex> l(m_RouterInfosMutex);
  219. inserted = m_RouterInfos.insert ({r->GetIdentHash (), r}).second;
  220. }
  221. if (inserted)
  222. {
  223. LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
  224. if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
  225. {
  226. std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  227. m_Floodfills.push_back (r);
  228. }
  229. }
  230. else
  231. {
  232. LogPrint (eLogWarning, "NetDb: Duplicated RouterInfo ", ident.ToBase64());
  233. updated = false;
  234. }
  235. }
  236. else
  237. updated = false;
  238. }
  239. // take care about requested destination
  240. m_Requests.RequestComplete (ident, r);
  241. return r;
  242. }
  243. bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len)
  244. {
  245. std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
  246. bool updated = false;
  247. auto it = m_LeaseSets.find(ident);
  248. if (it != m_LeaseSets.end () && it->second->GetStoreType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
  249. {
  250. // we update only is existing LeaseSet is not LeaseSet2
  251. uint64_t expires;
  252. if(LeaseSetBufferValidate(buf, len, expires))
  253. {
  254. if(it->second->GetExpirationTime() < expires)
  255. {
  256. it->second->Update (buf, len, false); // signature is verified already
  257. LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
  258. updated = true;
  259. }
  260. else
  261. LogPrint(eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase32());
  262. }
  263. else
  264. LogPrint(eLogError, "NetDb: LeaseSet is invalid: ", ident.ToBase32());
  265. }
  266. else
  267. {
  268. auto leaseSet = std::make_shared<LeaseSet> (buf, len, false); // we don't need leases in netdb
  269. if (leaseSet->IsValid ())
  270. {
  271. LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
  272. m_LeaseSets[ident] = leaseSet;
  273. updated = true;
  274. }
  275. else
  276. LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32());
  277. }
  278. return updated;
  279. }
  280. bool NetDb::AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType)
  281. {
  282. std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
  283. auto leaseSet = std::make_shared<LeaseSet2> (storeType, buf, len, false); // we don't need leases in netdb
  284. if (leaseSet->IsValid ())
  285. {
  286. auto it = m_LeaseSets.find(ident);
  287. if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
  288. leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
  289. {
  290. if (leaseSet->IsPublic ())
  291. {
  292. // TODO: implement actual update
  293. LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
  294. m_LeaseSets[ident] = leaseSet;
  295. return true;
  296. }
  297. else
  298. {
  299. LogPrint (eLogWarning, "NetDb: Unpublished LeaseSet2 received: ", ident.ToBase32());
  300. m_LeaseSets.erase (ident);
  301. }
  302. }
  303. }
  304. else
  305. LogPrint (eLogError, "NetDb: new LeaseSet2 validation failed: ", ident.ToBase32());
  306. return false;
  307. }
  308. std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
  309. {
  310. std::unique_lock<std::mutex> l(m_RouterInfosMutex);
  311. auto it = m_RouterInfos.find (ident);
  312. if (it != m_RouterInfos.end ())
  313. return it->second;
  314. else
  315. return nullptr;
  316. }
  317. std::shared_ptr<LeaseSet> NetDb::FindLeaseSet (const IdentHash& destination) const
  318. {
  319. std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
  320. auto it = m_LeaseSets.find (destination);
  321. if (it != m_LeaseSets.end ())
  322. return it->second;
  323. else
  324. return nullptr;
  325. }
  326. std::shared_ptr<RouterProfile> NetDb::FindRouterProfile (const IdentHash& ident) const
  327. {
  328. if (!m_PersistProfiles)
  329. return nullptr;
  330. auto router = FindRouter (ident);
  331. return router ? router->GetProfile () : nullptr;
  332. }
  333. void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
  334. {
  335. auto it = m_RouterInfos.find (ident);
  336. if (it != m_RouterInfos.end ())
  337. return it->second->SetUnreachable (unreachable);
  338. }
  339. void NetDb::Reseed ()
  340. {
  341. if (!m_Reseeder)
  342. {
  343. m_Reseeder = new Reseeder ();
  344. m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification
  345. }
  346. // try reseeding from floodfill first if specified
  347. std::string riPath;
  348. if(i2p::config::GetOption("reseed.floodfill", riPath)) {
  349. auto ri = std::make_shared<RouterInfo>(riPath);
  350. if (ri->IsFloodfill()) {
  351. const uint8_t * riData = ri->GetBuffer();
  352. int riLen = ri->GetBufferLen();
  353. if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
  354. // bad router info
  355. LogPrint(eLogError, "NetDb: bad router info");
  356. return;
  357. }
  358. m_FloodfillBootstrap = ri;
  359. ReseedFromFloodfill(*ri);
  360. // don't try reseed servers if trying to bootstrap from floodfill
  361. return;
  362. }
  363. }
  364. m_Reseeder->Bootstrap ();
  365. }
  366. void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
  367. {
  368. LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64());
  369. std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
  370. i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
  371. i2p::data::IdentHash ih = ri.GetIdentHash();
  372. i2p::data::IdentHash randomIdent;
  373. // make floodfill lookups
  374. while(numFloodfills > 0) {
  375. randomIdent.Randomize();
  376. auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, false);
  377. requests.push_back(msg);
  378. numFloodfills --;
  379. }
  380. // make regular router lookups
  381. while(numRouters > 0) {
  382. randomIdent.Randomize();
  383. auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, true);
  384. requests.push_back(msg);
  385. numRouters --;
  386. }
  387. // send them off
  388. i2p::transport::transports.SendMessages(ih, requests);
  389. }
  390. bool NetDb::LoadRouterInfo (const std::string & path)
  391. {
  392. auto r = std::make_shared<RouterInfo>(path);
  393. if (r->GetRouterIdentity () && !r->IsUnreachable () &&
  394. (!r->UsesIntroducer () || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour
  395. {
  396. r->DeleteBuffer ();
  397. r->ClearProperties (); // properties are not used for regular routers
  398. m_RouterInfos[r->GetIdentHash ()] = r;
  399. if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
  400. m_Floodfills.push_back (r);
  401. }
  402. else
  403. {
  404. LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid. Delete");
  405. i2p::fs::Remove(path);
  406. }
  407. return true;
  408. }
  409. void NetDb::VisitLeaseSets(LeaseSetVisitor v)
  410. {
  411. std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
  412. for ( auto & entry : m_LeaseSets)
  413. v(entry.first, entry.second);
  414. }
  415. void NetDb::VisitStoredRouterInfos(RouterInfoVisitor v)
  416. {
  417. m_Storage.Iterate([v] (const std::string & filename)
  418. {
  419. auto ri = std::make_shared<i2p::data::RouterInfo>(filename);
  420. v(ri);
  421. });
  422. }
  423. void NetDb::VisitRouterInfos(RouterInfoVisitor v)
  424. {
  425. std::unique_lock<std::mutex> lock(m_RouterInfosMutex);
  426. for ( const auto & item : m_RouterInfos )
  427. v(item.second);
  428. }
  429. size_t NetDb::VisitRandomRouterInfos(RouterInfoFilter filter, RouterInfoVisitor v, size_t n)
  430. {
  431. std::vector<std::shared_ptr<const RouterInfo> > found;
  432. const size_t max_iters_per_cyle = 3;
  433. size_t iters = max_iters_per_cyle;
  434. while(n > 0)
  435. {
  436. std::unique_lock<std::mutex> lock(m_RouterInfosMutex);
  437. uint32_t idx = rand () % m_RouterInfos.size ();
  438. uint32_t i = 0;
  439. for (const auto & it : m_RouterInfos) {
  440. if(i >= idx) // are we at the random start point?
  441. {
  442. // yes, check if we want this one
  443. if(filter(it.second))
  444. {
  445. // we have a match
  446. --n;
  447. found.push_back(it.second);
  448. // reset max iterations per cycle
  449. iters = max_iters_per_cyle;
  450. break;
  451. }
  452. }
  453. else // not there yet
  454. ++i;
  455. }
  456. // we have enough
  457. if(n == 0) break;
  458. --iters;
  459. // have we tried enough this cycle ?
  460. if(!iters) {
  461. // yes let's try the next cycle
  462. --n;
  463. iters = max_iters_per_cyle;
  464. }
  465. }
  466. // visit the ones we found
  467. size_t visited = 0;
  468. for(const auto & ri : found ) {
  469. v(ri);
  470. ++visited;
  471. }
  472. return visited;
  473. }
  474. void NetDb::Load ()
  475. {
  476. // make sure we cleanup netDb from previous attempts
  477. m_RouterInfos.clear ();
  478. m_Floodfills.clear ();
  479. m_LastLoad = i2p::util::GetSecondsSinceEpoch();
  480. std::vector<std::string> files;
  481. m_Storage.Traverse(files);
  482. for (const auto& path : files)
  483. LoadRouterInfo(path);
  484. LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
  485. }
  486. void NetDb::SaveUpdated ()
  487. {
  488. int updatedCount = 0, deletedCount = 0;
  489. auto total = m_RouterInfos.size ();
  490. uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
  491. uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
  492. auto uptime = i2p::context.GetUptime ();
  493. // routers don't expire if less than 90 or uptime is less than 1 hour
  494. bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
  495. if (checkForExpiration && uptime > 3600) // 1 hour
  496. expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
  497. NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
  498. for (auto& it: m_RouterInfos)
  499. {
  500. std::string ident = it.second->GetIdentHashBase64();
  501. std::string path = m_Storage.Path(ident);
  502. if (it.second->IsUpdated ())
  503. {
  504. it.second->SaveToFile (path);
  505. it.second->SetUpdated (false);
  506. it.second->SetUnreachable (false);
  507. it.second->DeleteBuffer ();
  508. updatedCount++;
  509. continue;
  510. }
  511. // find & mark expired routers
  512. if (it.second->UsesIntroducer ())
  513. {
  514. if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
  515. // RouterInfo expires after 1 hour if uses introducer
  516. it.second->SetUnreachable (true);
  517. }
  518. else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
  519. it.second->SetUnreachable (true);
  520. if (it.second->IsUnreachable ())
  521. {
  522. // delete RI file
  523. m_Storage.Remove(ident);
  524. deletedCount++;
  525. if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
  526. }
  527. } // m_RouterInfos iteration
  528. if (updatedCount > 0)
  529. LogPrint (eLogInfo, "NetDb: saved ", updatedCount, " new/updated routers");
  530. if (deletedCount > 0)
  531. {
  532. LogPrint (eLogInfo, "NetDb: deleting ", deletedCount, " unreachable routers");
  533. // clean up RouterInfos table
  534. {
  535. std::unique_lock<std::mutex> l(m_RouterInfosMutex);
  536. for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
  537. {
  538. if (it->second->IsUnreachable ())
  539. {
  540. if (m_PersistProfiles) it->second->SaveProfile ();
  541. it = m_RouterInfos.erase (it);
  542. continue;
  543. }
  544. ++it;
  545. }
  546. }
  547. // clean up expired floodfills or not floodfills anymore
  548. {
  549. std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  550. for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
  551. if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
  552. it = m_Floodfills.erase (it);
  553. else
  554. ++it;
  555. }
  556. }
  557. }
  558. void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete)
  559. {
  560. auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
  561. if (!dest)
  562. {
  563. LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already");
  564. return;
  565. }
  566. auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
  567. if (floodfill)
  568. transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
  569. else
  570. {
  571. LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
  572. m_Requests.RequestComplete (destination, nullptr);
  573. }
  574. }
  575. void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete)
  576. {
  577. auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory
  578. if (!dest)
  579. {
  580. LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already");
  581. return;
  582. }
  583. LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
  584. // direct
  585. transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
  586. }
  587. void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m)
  588. {
  589. uint8_t flood = m->GetPayload ()[0] & NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD;
  590. bool updated;
  591. auto ri = AddRouterInfo (m->GetPayload () + 1, m->GetPayloadLength () - 1, updated); // without flags
  592. if (flood && updated && context.IsFloodfill () && ri)
  593. {
  594. auto floodMsg = CreateDatabaseStoreMsg (ri, 0); // replyToken = 0
  595. Flood (ri->GetIdentHash (), floodMsg);
  596. }
  597. }
  598. void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m)
  599. {
  600. const uint8_t * buf = m->GetPayload ();
  601. size_t len = m->GetSize ();
  602. IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
  603. if (ident.IsZero ())
  604. {
  605. LogPrint (eLogDebug, "NetDb: database store with zero ident, dropped");
  606. return;
  607. }
  608. uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
  609. size_t offset = DATABASE_STORE_HEADER_SIZE;
  610. if (replyToken)
  611. {
  612. auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
  613. uint32_t tunnelID = bufbe32toh (buf + offset);
  614. offset += 4;
  615. if (!tunnelID) // send response directly
  616. transports.SendMessage (buf + offset, deliveryStatus);
  617. else
  618. {
  619. auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
  620. auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
  621. if (outbound)
  622. outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
  623. else
  624. LogPrint (eLogWarning, "NetDb: no outbound tunnels for DatabaseStore reply found");
  625. }
  626. offset += 32;
  627. }
  628. // we must send reply back before this check
  629. if (ident == i2p::context.GetIdentHash ())
  630. {
  631. LogPrint (eLogDebug, "NetDb: database store with own RouterInfo received, dropped");
  632. return;
  633. }
  634. size_t payloadOffset = offset;
  635. bool updated = false;
  636. uint8_t storeType = buf[DATABASE_STORE_TYPE_OFFSET];
  637. if (storeType) // LeaseSet or LeaseSet2
  638. {
  639. if (!m->from) // unsolicited LS must be received directly
  640. {
  641. if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
  642. {
  643. LogPrint (eLogDebug, "NetDb: store request: LeaseSet for ", ident.ToBase32());
  644. updated = AddLeaseSet (ident, buf + offset, len - offset);
  645. }
  646. else // all others are considered as LeaseSet2
  647. {
  648. LogPrint (eLogDebug, "NetDb: store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
  649. updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
  650. }
  651. }
  652. }
  653. else // RouterInfo
  654. {
  655. LogPrint (eLogDebug, "NetDb: store request: RouterInfo");
  656. size_t size = bufbe16toh (buf + offset);
  657. offset += 2;
  658. if (size > MAX_RI_BUFFER_SIZE || size > len - offset)
  659. {
  660. LogPrint (eLogError, "NetDb: invalid RouterInfo length ", (int)size);
  661. return;
  662. }
  663. uint8_t uncompressed[MAX_RI_BUFFER_SIZE];
  664. size_t uncompressedSize = m_Inflator.Inflate (buf + offset, size, uncompressed, MAX_RI_BUFFER_SIZE);
  665. if (uncompressedSize && uncompressedSize < MAX_RI_BUFFER_SIZE)
  666. updated = AddRouterInfo (ident, uncompressed, uncompressedSize);
  667. else
  668. {
  669. LogPrint (eLogInfo, "NetDb: decompression failed ", uncompressedSize);
  670. return;
  671. }
  672. }
  673. if (replyToken && context.IsFloodfill () && updated)
  674. {
  675. // flood updated
  676. auto floodMsg = NewI2NPShortMessage ();
  677. uint8_t * payload = floodMsg->GetPayload ();
  678. memcpy (payload, buf, 33); // key + type
  679. htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token
  680. size_t msgLen = len - payloadOffset;
  681. floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen;
  682. if (floodMsg->len < floodMsg->maxLen)
  683. {
  684. memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
  685. floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
  686. Flood (ident, floodMsg);
  687. }
  688. else
  689. LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
  690. }
  691. }
  692. void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
  693. {
  694. const uint8_t * buf = msg->GetPayload ();
  695. char key[48];
  696. int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
  697. key[l] = 0;
  698. int num = buf[32]; // num
  699. LogPrint (eLogDebug, "NetDb: DatabaseSearchReply for ", key, " num=", num);
  700. IdentHash ident (buf);
  701. auto dest = m_Requests.FindRequest (ident);
  702. if (dest)
  703. {
  704. bool deleteDest = true;
  705. if (num > 0)
  706. {
  707. auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
  708. auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
  709. auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr;
  710. if (!dest->IsExploratory ())
  711. {
  712. // reply to our destination. Try other floodfills
  713. if (outbound && inbound)
  714. {
  715. std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
  716. auto count = dest->GetExcludedPeers ().size ();
  717. if (count < 7)
  718. {
  719. auto nextFloodfill = GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
  720. if (nextFloodfill)
  721. {
  722. // tell floodfill about us
  723. msgs.push_back (i2p::tunnel::TunnelMessageBlock
  724. {
  725. i2p::tunnel::eDeliveryTypeRouter,
  726. nextFloodfill->GetIdentHash (), 0,
  727. CreateDatabaseStoreMsg ()
  728. });
  729. // request destination
  730. LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
  731. auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
  732. msgs.push_back (i2p::tunnel::TunnelMessageBlock
  733. {
  734. i2p::tunnel::eDeliveryTypeRouter,
  735. nextFloodfill->GetIdentHash (), 0, msg
  736. });
  737. deleteDest = false;
  738. }
  739. }
  740. else
  741. LogPrint (eLogWarning, "NetDb: ", key, " was not found on ", count, " floodfills");
  742. if (msgs.size () > 0)
  743. outbound->SendTunnelDataMsg (msgs);
  744. }
  745. }
  746. if (deleteDest)
  747. // no more requests for the destinationation. delete it
  748. m_Requests.RequestComplete (ident, nullptr);
  749. }
  750. else
  751. // no more requests for destination possible. delete it
  752. m_Requests.RequestComplete (ident, nullptr);
  753. }
  754. else if(!m_FloodfillBootstrap)
  755. LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found");
  756. // try responses
  757. for (int i = 0; i < num; i++)
  758. {
  759. const uint8_t * router = buf + 33 + i*32;
  760. char peerHash[48];
  761. int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48);
  762. peerHash[l1] = 0;
  763. LogPrint (eLogDebug, "NetDb: ", i, ": ", peerHash);
  764. auto r = FindRouter (router);
  765. if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
  766. {
  767. // router with ident not found or too old (1 hour)
  768. LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ...");
  769. if(m_FloodfillBootstrap)
  770. RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true);
  771. else
  772. RequestDestination (router);
  773. }
  774. else
  775. LogPrint (eLogDebug, "NetDb: [:|||:]");
  776. }
  777. }
  778. void NetDb::HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg)
  779. {
  780. const uint8_t * buf = msg->GetPayload ();
  781. IdentHash ident (buf);
  782. if (ident.IsZero ())
  783. {
  784. LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored");
  785. return;
  786. }
  787. char key[48];
  788. int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
  789. key[l] = 0;
  790. IdentHash replyIdent(buf + 32);
  791. uint8_t flag = buf[64];
  792. LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " received flags=", (int)flag);
  793. uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
  794. const uint8_t * excluded = buf + 65;
  795. uint32_t replyTunnelID = 0;
  796. if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel
  797. {
  798. replyTunnelID = bufbe32toh (excluded);
  799. excluded += 4;
  800. }
  801. uint16_t numExcluded = bufbe16toh (excluded);
  802. excluded += 2;
  803. if (numExcluded > 512)
  804. {
  805. LogPrint (eLogWarning, "NetDb: number of excluded peers", numExcluded, " exceeds 512");
  806. return;
  807. }
  808. std::shared_ptr<I2NPMessage> replyMsg;
  809. if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
  810. {
  811. LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded");
  812. std::set<IdentHash> excludedRouters;
  813. for (int i = 0; i < numExcluded; i++)
  814. {
  815. excludedRouters.insert (excluded);
  816. excluded += 32;
  817. }
  818. std::vector<IdentHash> routers;
  819. for (int i = 0; i < 3; i++)
  820. {
  821. auto r = GetClosestNonFloodfill (ident, excludedRouters);
  822. if (r)
  823. {
  824. routers.push_back (r->GetIdentHash ());
  825. excludedRouters.insert (r->GetIdentHash ());
  826. }
  827. }
  828. replyMsg = CreateDatabaseSearchReply (ident, routers);
  829. }
  830. else
  831. {
  832. if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
  833. lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
  834. {
  835. auto router = FindRouter (ident);
  836. if (router)
  837. {
  838. LogPrint (eLogDebug, "NetDb: requested RouterInfo ", key, " found");
  839. router->LoadBuffer ();
  840. if (router->GetBuffer ())
  841. replyMsg = CreateDatabaseStoreMsg (router);
  842. }
  843. }
  844. if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP ||
  845. lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
  846. {
  847. auto leaseSet = FindLeaseSet (ident);
  848. if (!leaseSet)
  849. {
  850. // no lease set found
  851. LogPrint(eLogDebug, "NetDb: requested LeaseSet not found for ", ident.ToBase32());
  852. }
  853. else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
  854. {
  855. LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
  856. replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
  857. }
  858. }
  859. if (!replyMsg)
  860. {
  861. std::set<IdentHash> excludedRouters;
  862. const uint8_t * exclude_ident = excluded;
  863. for (int i = 0; i < numExcluded; i++)
  864. {
  865. excludedRouters.insert (exclude_ident);
  866. exclude_ident += 32;
  867. }
  868. auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
  869. if (closestFloodfills.empty ())
  870. LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
  871. replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
  872. }
  873. }
  874. excluded += numExcluded * 32;
  875. if (replyMsg)
  876. {
  877. if (replyTunnelID)
  878. {
  879. // encryption might be used though tunnel only
  880. if (flag & DATABASE_LOOKUP_ENCRYPTION_FLAG) // encrypted reply requested
  881. {
  882. const uint8_t * sessionKey = excluded;
  883. const uint8_t numTags = excluded[32];
  884. if (numTags)
  885. {
  886. const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
  887. i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag);
  888. replyMsg = garlic.WrapSingleMessage (replyMsg);
  889. if(replyMsg == nullptr) LogPrint(eLogError, "NetDb: failed to wrap message");
  890. }
  891. else
  892. LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided");
  893. }
  894. auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
  895. auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
  896. if (outbound)
  897. outbound->SendTunnelDataMsg (replyIdent, replyTunnelID, replyMsg);
  898. else
  899. transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
  900. }
  901. else
  902. transports.SendMessage (replyIdent, replyMsg);
  903. }
  904. }
  905. void NetDb::Explore (int numDestinations)
  906. {
  907. // new requests
  908. auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
  909. auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
  910. auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
  911. bool throughTunnels = outbound && inbound;
  912. uint8_t randomHash[32];
  913. std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
  914. LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
  915. for (int i = 0; i < numDestinations; i++)
  916. {
  917. RAND_bytes (randomHash, 32);
  918. auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
  919. if (!dest)
  920. {
  921. LogPrint (eLogWarning, "NetDb: exploratory destination is requested already");
  922. return;
  923. }
  924. auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
  925. if (floodfill)
  926. {
  927. if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
  928. throughTunnels = false;
  929. if (throughTunnels)
  930. {
  931. msgs.push_back (i2p::tunnel::TunnelMessageBlock
  932. {
  933. i2p::tunnel::eDeliveryTypeRouter,
  934. floodfill->GetIdentHash (), 0,
  935. CreateDatabaseStoreMsg () // tell floodfill about us
  936. });
  937. msgs.push_back (i2p::tunnel::TunnelMessageBlock
  938. {
  939. i2p::tunnel::eDeliveryTypeRouter,
  940. floodfill->GetIdentHash (), 0,
  941. dest->CreateRequestMessage (floodfill, inbound) // explore
  942. });
  943. }
  944. else
  945. i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
  946. }
  947. else
  948. m_Requests.RequestComplete (randomHash, nullptr);
  949. }
  950. if (throughTunnels && msgs.size () > 0)
  951. outbound->SendTunnelDataMsg (msgs);
  952. }
  953. void NetDb::Publish ()
  954. {
  955. i2p::context.UpdateStats (); // for floodfill
  956. std::set<IdentHash> excluded; // TODO: fill up later
  957. for (int i = 0; i < 2; i++)
  958. {
  959. auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded);
  960. if (floodfill)
  961. {
  962. uint32_t replyToken;
  963. RAND_bytes ((uint8_t *)&replyToken, 4);
  964. LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
  965. transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
  966. excluded.insert (floodfill->GetIdentHash ());
  967. }
  968. }
  969. }
  970. void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
  971. {
  972. std::set<IdentHash> excluded;
  973. excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
  974. excluded.insert (ident); // don't flood back
  975. for (int i = 0; i < 3; i++)
  976. {
  977. auto floodfill = GetClosestFloodfill (ident, excluded);
  978. if (floodfill)
  979. {
  980. auto h = floodfill->GetIdentHash();
  981. LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
  982. transports.SendMessage (h, CopyI2NPMessage(floodMsg));
  983. excluded.insert (h);
  984. }
  985. else
  986. break;
  987. }
  988. }
  989. std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const
  990. {
  991. return GetRandomRouter (
  992. [](std::shared_ptr<const RouterInfo> router)->bool
  993. {
  994. return !router->IsHidden ();
  995. });
  996. }
  997. std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
  998. {
  999. return GetRandomRouter (
  1000. [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
  1001. {
  1002. return !router->IsHidden () && router != compatibleWith &&
  1003. router->IsCompatible (*compatibleWith);
  1004. });
  1005. }
  1006. std::shared_ptr<const RouterInfo> NetDb::GetRandomPeerTestRouter (bool v4only) const
  1007. {
  1008. return GetRandomRouter (
  1009. [v4only](std::shared_ptr<const RouterInfo> router)->bool
  1010. {
  1011. return !router->IsHidden () && router->IsPeerTesting () && router->IsSSU (v4only);
  1012. });
  1013. }
  1014. std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const
  1015. {
  1016. return GetRandomRouter (
  1017. [](std::shared_ptr<const RouterInfo> router)->bool
  1018. {
  1019. return !router->IsHidden () && router->IsSSUV6 ();
  1020. });
  1021. }
  1022. std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer () const
  1023. {
  1024. return GetRandomRouter (
  1025. [](std::shared_ptr<const RouterInfo> router)->bool
  1026. {
  1027. return !router->IsHidden () && router->IsIntroducer ();
  1028. });
  1029. }
  1030. std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
  1031. {
  1032. return GetRandomRouter (
  1033. [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
  1034. {
  1035. return !router->IsHidden () && router != compatibleWith &&
  1036. router->IsCompatible (*compatibleWith) &&
  1037. (router->GetCaps () & RouterInfo::eHighBandwidth);
  1038. });
  1039. }
  1040. template<typename Filter>
  1041. std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const
  1042. {
  1043. if (m_RouterInfos.empty())
  1044. return 0;
  1045. uint32_t ind = rand () % m_RouterInfos.size ();
  1046. for (int j = 0; j < 2; j++)
  1047. {
  1048. uint32_t i = 0;
  1049. std::unique_lock<std::mutex> l(m_RouterInfosMutex);
  1050. for (const auto& it: m_RouterInfos)
  1051. {
  1052. if (i >= ind)
  1053. {
  1054. if (!it.second->IsUnreachable () && filter (it.second))
  1055. return it.second;
  1056. }
  1057. else
  1058. i++;
  1059. }
  1060. // we couldn't find anything, try second pass
  1061. ind = 0;
  1062. }
  1063. return nullptr; // seems we have too few routers
  1064. }
  1065. void NetDb::PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg)
  1066. {
  1067. if (msg) m_Queue.Put (msg);
  1068. }
  1069. std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
  1070. const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
  1071. {
  1072. std::shared_ptr<const RouterInfo> r;
  1073. XORMetric minMetric;
  1074. IdentHash destKey = CreateRoutingKey (destination);
  1075. if (closeThanUsOnly)
  1076. minMetric = destKey ^ i2p::context.GetIdentHash ();
  1077. else
  1078. minMetric.SetMax ();
  1079. std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  1080. for (const auto& it: m_Floodfills)
  1081. {
  1082. if (!it->IsUnreachable ())
  1083. {
  1084. XORMetric m = destKey ^ it->GetIdentHash ();
  1085. if (m < minMetric && !excluded.count (it->GetIdentHash ()))
  1086. {
  1087. minMetric = m;
  1088. r = it;
  1089. }
  1090. }
  1091. }
  1092. return r;
  1093. }
  1094. std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
  1095. std::set<IdentHash>& excluded, bool closeThanUsOnly) const
  1096. {
  1097. struct Sorted
  1098. {
  1099. std::shared_ptr<const RouterInfo> r;
  1100. XORMetric metric;
  1101. bool operator< (const Sorted& other) const { return metric < other.metric; };
  1102. };
  1103. std::set<Sorted> sorted;
  1104. IdentHash destKey = CreateRoutingKey (destination);
  1105. XORMetric ourMetric;
  1106. if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
  1107. {
  1108. std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  1109. for (const auto& it: m_Floodfills)
  1110. {
  1111. if (!it->IsUnreachable ())
  1112. {
  1113. XORMetric m = destKey ^ it->GetIdentHash ();
  1114. if (closeThanUsOnly && ourMetric < m) continue;
  1115. if (sorted.size () < num)
  1116. sorted.insert ({it, m});
  1117. else if (m < sorted.rbegin ()->metric)
  1118. {
  1119. sorted.insert ({it, m});
  1120. sorted.erase (std::prev (sorted.end ()));
  1121. }
  1122. }
  1123. }
  1124. }
  1125. std::vector<IdentHash> res;
  1126. size_t i = 0;
  1127. for (const auto& it: sorted)
  1128. {
  1129. if (i < num)
  1130. {
  1131. const auto& ident = it.r->GetIdentHash ();
  1132. if (!excluded.count (ident))
  1133. {
  1134. res.push_back (ident);
  1135. i++;
  1136. }
  1137. }
  1138. else
  1139. break;
  1140. }
  1141. return res;
  1142. }
  1143. std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily(const std::string & fam) const {
  1144. return GetRandomRouter(
  1145. [fam](std::shared_ptr<const RouterInfo> router)->bool
  1146. {
  1147. return router->IsFamily(fam);
  1148. });
  1149. }
  1150. std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination,
  1151. const std::set<IdentHash>& excluded) const
  1152. {
  1153. std::shared_ptr<const RouterInfo> r;
  1154. XORMetric minMetric;
  1155. IdentHash destKey = CreateRoutingKey (destination);
  1156. minMetric.SetMax ();
  1157. // must be called from NetDb thread only
  1158. for (const auto& it: m_RouterInfos)
  1159. {
  1160. if (!it.second->IsFloodfill ())
  1161. {
  1162. XORMetric m = destKey ^ it.first;
  1163. if (m < minMetric && !excluded.count (it.first))
  1164. {
  1165. minMetric = m;
  1166. r = it.second;
  1167. }
  1168. }
  1169. }
  1170. return r;
  1171. }
  1172. void NetDb::ManageLeaseSets ()
  1173. {
  1174. auto ts = i2p::util::GetMillisecondsSinceEpoch ();
  1175. for (auto it = m_LeaseSets.begin (); it != m_LeaseSets.end ();)
  1176. {
  1177. if (!it->second->IsValid () || ts > it->second->GetExpirationTime () - LEASE_ENDDATE_THRESHOLD)
  1178. {
  1179. LogPrint (eLogInfo, "NetDb: LeaseSet ", it->first.ToBase64 (), " expired or invalid");
  1180. it = m_LeaseSets.erase (it);
  1181. }
  1182. else
  1183. ++it;
  1184. }
  1185. }
  1186. }
  1187. }