NodeTable.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file NodeTable.cpp
  15. * @author Alex Leverington <nessence@gmail.com>
  16. * @date 2014
  17. */
  18. #include "NodeTable.h"
  19. using namespace std;
  20. using namespace dev;
  21. using namespace dev::p2p;
  22. const char* NodeTableWarn::name() { return "!P!"; }
  23. const char* NodeTableNote::name() { return "*P*"; }
  24. const char* NodeTableMessageSummary::name() { return "-P-"; }
  25. const char* NodeTableMessageDetail::name() { return "=P="; }
  26. const char* NodeTableConnect::name() { return "+P+"; }
  27. const char* NodeTableEvent::name() { return "+P+"; }
  28. const char* NodeTableTimer::name() { return "+P+"; }
  29. const char* NodeTableUpdate::name() { return "+P+"; }
  30. const char* NodeTableTriviaSummary::name() { return "-P-"; }
  31. const char* NodeTableTriviaDetail::name() { return "=P="; }
  32. const char* NodeTableAllDetail::name() { return "=P="; }
  33. const char* NodeTableEgress::name() { return ">>P"; }
  34. const char* NodeTableIngress::name() { return "<<P"; }
  35. NodeEntry::NodeEntry(NodeID const& _src, Public const& _pubk, NodeIPEndpoint const& _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src, _pubk)) {}
  36. NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled):
  37. m_node(Node(_alias.pub(), _endpoint)),
  38. m_secret(_alias.sec()),
  39. m_socket(make_shared<NodeSocket>(_io, *reinterpret_cast<UDPSocketEvents*>(this), (bi::udp::endpoint)m_node.endpoint)),
  40. m_socketPointer(m_socket.get()),
  41. m_timers(_io)
  42. {
  43. for (unsigned i = 0; i < s_bins; i++)
  44. m_state[i].distance = i;
  45. if (!_enabled)
  46. return;
  47. try
  48. {
  49. m_socketPointer->connect();
  50. doDiscovery();
  51. }
  52. catch (std::exception const& _e)
  53. {
  54. clog(NetWarn) << "Exception connecting NodeTable socket: " << _e.what();
  55. clog(NetWarn) << "Discovery disabled.";
  56. }
  57. }
  58. NodeTable::~NodeTable()
  59. {
  60. m_socketPointer->disconnect();
  61. m_timers.stop();
  62. }
  63. void NodeTable::processEvents()
  64. {
  65. if (m_nodeEventHandler)
  66. m_nodeEventHandler->processEvents();
  67. }
  68. shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relation)
  69. {
  70. if (_relation == Known)
  71. {
  72. auto ret = make_shared<NodeEntry>(m_node.id, _node.id, _node.endpoint);
  73. ret->pending = false;
  74. DEV_GUARDED(x_nodes)
  75. m_nodes[_node.id] = ret;
  76. noteActiveNode(_node.id, _node.endpoint);
  77. return ret;
  78. }
  79. if (!_node.endpoint)
  80. return shared_ptr<NodeEntry>();
  81. // ping address to recover nodeid if nodeid is empty
  82. if (!_node.id)
  83. {
  84. DEV_GUARDED(x_nodes)
  85. clog(NodeTableConnect) << "Sending public key discovery Ping to" << (bi::udp::endpoint)_node.endpoint << "(Advertising:" << (bi::udp::endpoint)m_node.endpoint << ")";
  86. DEV_GUARDED(x_pubkDiscoverPings)
  87. m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now();
  88. ping(_node.endpoint);
  89. return shared_ptr<NodeEntry>();
  90. }
  91. DEV_GUARDED(x_nodes)
  92. if (m_nodes.count(_node.id))
  93. return m_nodes[_node.id];
  94. auto ret = make_shared<NodeEntry>(m_node.id, _node.id, _node.endpoint);
  95. DEV_GUARDED(x_nodes)
  96. m_nodes[_node.id] = ret;
  97. clog(NodeTableConnect) << "addNode pending for" << _node.endpoint;
  98. ping(_node.endpoint);
  99. return ret;
  100. }
  101. list<NodeID> NodeTable::nodes() const
  102. {
  103. list<NodeID> nodes;
  104. DEV_GUARDED(x_nodes)
  105. for (auto& i: m_nodes)
  106. nodes.push_back(i.second->id);
  107. return nodes;
  108. }
  109. list<NodeEntry> NodeTable::snapshot() const
  110. {
  111. list<NodeEntry> ret;
  112. DEV_GUARDED(x_state)
  113. for (auto const& s: m_state)
  114. for (auto const& np: s.nodes)
  115. if (auto n = np.lock())
  116. ret.push_back(*n);
  117. return ret;
  118. }
  119. Node NodeTable::node(NodeID const& _id)
  120. {
  121. Guard l(x_nodes);
  122. if (m_nodes.count(_id))
  123. {
  124. auto entry = m_nodes[_id];
  125. return Node(_id, entry->endpoint, entry->peerType);
  126. }
  127. return UnspecifiedNode;
  128. }
  129. shared_ptr<NodeEntry> NodeTable::nodeEntry(NodeID _id)
  130. {
  131. Guard l(x_nodes);
  132. return m_nodes.count(_id) ? m_nodes[_id] : shared_ptr<NodeEntry>();
  133. }
  134. void NodeTable::doDiscover(NodeID _node, unsigned _round, shared_ptr<set<shared_ptr<NodeEntry>>> _tried)
  135. {
  136. // NOTE: ONLY called by doDiscovery!
  137. if (!m_socketPointer->isOpen())
  138. return;
  139. if (_round == s_maxSteps)
  140. {
  141. clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
  142. doDiscovery();
  143. return;
  144. }
  145. else if (!_round && !_tried)
  146. // initialized _tried on first round
  147. _tried = make_shared<set<shared_ptr<NodeEntry>>>();
  148. auto nearest = nearestNodeEntries(_node);
  149. list<shared_ptr<NodeEntry>> tried;
  150. for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++)
  151. if (!_tried->count(nearest[i]))
  152. {
  153. auto r = nearest[i];
  154. tried.push_back(r);
  155. FindNode p(r->endpoint, _node);
  156. p.sign(m_secret);
  157. DEV_GUARDED(x_findNodeTimeout)
  158. m_findNodeTimeout.push_back(make_pair(r->id, chrono::steady_clock::now()));
  159. m_socketPointer->send(p);
  160. }
  161. if (tried.empty())
  162. {
  163. clog(NodeTableEvent) << "Terminating discover after " << _round << " rounds.";
  164. doDiscovery();
  165. return;
  166. }
  167. while (!tried.empty())
  168. {
  169. _tried->insert(tried.front());
  170. tried.pop_front();
  171. }
  172. m_timers.schedule(c_reqTimeout.count() * 2, [this, _node, _round, _tried](boost::system::error_code const& _ec)
  173. {
  174. if (_ec)
  175. clog(NodeTableMessageDetail) << "Discovery timer was probably cancelled: " << _ec.value() << _ec.message();
  176. if (_ec.value() == boost::asio::error::operation_aborted || m_timers.isStopped())
  177. return;
  178. // error::operation_aborted means that the timer was probably aborted.
  179. // It usually happens when "this" object is deallocated, in which case
  180. // subsequent call to doDiscover() would cause a crash. We can not rely on
  181. // m_timers.isStopped(), because "this" pointer was captured by the lambda,
  182. // and therefore, in case of deallocation m_timers object no longer exists.
  183. doDiscover(_node, _round + 1, _tried);
  184. });
  185. }
  186. vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeID _target)
  187. {
  188. // send s_alpha FindNode packets to nodes we know, closest to target
  189. static unsigned lastBin = s_bins - 1;
  190. unsigned head = distance(m_node.id, _target);
  191. unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins;
  192. map<unsigned, list<shared_ptr<NodeEntry>>> found;
  193. unsigned count = 0;
  194. // if d is 0, then we roll look forward, if last, we reverse, else, spread from d
  195. if (head > 1 && tail != lastBin)
  196. while (head != tail && head < s_bins && count < s_bucketSize)
  197. {
  198. Guard l(x_state);
  199. for (auto const& n: m_state[head].nodes)
  200. if (auto p = n.lock())
  201. {
  202. if (count < s_bucketSize)
  203. found[distance(_target, p->id)].push_back(p);
  204. else
  205. break;
  206. }
  207. if (count < s_bucketSize && tail)
  208. for (auto const& n: m_state[tail].nodes)
  209. if (auto p = n.lock())
  210. {
  211. if (count < s_bucketSize)
  212. found[distance(_target, p->id)].push_back(p);
  213. else
  214. break;
  215. }
  216. head++;
  217. if (tail)
  218. tail--;
  219. }
  220. else if (head < 2)
  221. while (head < s_bins && count < s_bucketSize)
  222. {
  223. Guard l(x_state);
  224. for (auto const& n: m_state[head].nodes)
  225. if (auto p = n.lock())
  226. {
  227. if (count < s_bucketSize)
  228. found[distance(_target, p->id)].push_back(p);
  229. else
  230. break;
  231. }
  232. head++;
  233. }
  234. else
  235. while (tail > 0 && count < s_bucketSize)
  236. {
  237. Guard l(x_state);
  238. for (auto const& n: m_state[tail].nodes)
  239. if (auto p = n.lock())
  240. {
  241. if (count < s_bucketSize)
  242. found[distance(_target, p->id)].push_back(p);
  243. else
  244. break;
  245. }
  246. tail--;
  247. }
  248. vector<shared_ptr<NodeEntry>> ret;
  249. for (auto& nodes: found)
  250. for (auto const& n: nodes.second)
  251. if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed())
  252. ret.push_back(n);
  253. return ret;
  254. }
  255. void NodeTable::ping(NodeIPEndpoint _to) const
  256. {
  257. NodeIPEndpoint src;
  258. DEV_GUARDED(x_nodes)
  259. src = m_node.endpoint;
  260. PingNode p(src, _to);
  261. p.sign(m_secret);
  262. m_socketPointer->send(p);
  263. }
  264. void NodeTable::ping(NodeEntry* _n) const
  265. {
  266. if (_n)
  267. ping(_n->endpoint);
  268. }
  269. void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _new)
  270. {
  271. if (!m_socketPointer->isOpen())
  272. return;
  273. unsigned evicts = 0;
  274. DEV_GUARDED(x_evictions)
  275. {
  276. m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id));
  277. evicts = m_evictions.size();
  278. }
  279. if (evicts == 1)
  280. doCheckEvictions();
  281. ping(_leastSeen.get());
  282. }
  283. void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint)
  284. {
  285. if (_pubk == m_node.address() || !NodeIPEndpoint(_endpoint.address(), _endpoint.port(), _endpoint.port()).isAllowed())
  286. return;
  287. shared_ptr<NodeEntry> node = nodeEntry(_pubk);
  288. if (!!node && !node->pending)
  289. {
  290. clog(NodeTableConnect) << "Noting active node:" << _pubk << _endpoint.address().to_string() << ":" << _endpoint.port();
  291. node->endpoint.address = _endpoint.address();
  292. node->endpoint.udpPort = _endpoint.port();
  293. shared_ptr<NodeEntry> contested;
  294. {
  295. Guard l(x_state);
  296. NodeBucket& s = bucket_UNSAFE(node.get());
  297. bool removed = false;
  298. s.nodes.remove_if([&node, &removed](weak_ptr<NodeEntry> const& n)
  299. {
  300. if (n.lock() == node)
  301. removed = true;
  302. return removed;
  303. });
  304. if (s.nodes.size() >= s_bucketSize)
  305. {
  306. if (removed)
  307. clog(NodeTableWarn) << "DANGER: Bucket overflow when swapping node position.";
  308. // It's only contested iff nodeentry exists
  309. contested = s.nodes.front().lock();
  310. if (!contested)
  311. {
  312. s.nodes.pop_front();
  313. s.nodes.push_back(node);
  314. if (!removed && m_nodeEventHandler)
  315. m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded);
  316. }
  317. }
  318. else
  319. {
  320. s.nodes.push_back(node);
  321. if (!removed && m_nodeEventHandler)
  322. m_nodeEventHandler->appendEvent(node->id, NodeEntryAdded);
  323. }
  324. }
  325. if (contested)
  326. evict(contested, node);
  327. }
  328. }
  329. void NodeTable::dropNode(shared_ptr<NodeEntry> _n)
  330. {
  331. // remove from nodetable
  332. {
  333. Guard l(x_state);
  334. NodeBucket& s = bucket_UNSAFE(_n.get());
  335. s.nodes.remove_if([&_n](weak_ptr<NodeEntry> n) { return n.lock() == _n; });
  336. }
  337. // notify host
  338. clog(NodeTableUpdate) << "p2p.nodes.drop " << _n->id;
  339. if (m_nodeEventHandler)
  340. m_nodeEventHandler->appendEvent(_n->id, NodeEntryDropped);
  341. }
  342. NodeTable::NodeBucket& NodeTable::bucket_UNSAFE(NodeEntry const* _n)
  343. {
  344. return m_state[_n->distance - 1];
  345. }
  346. void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet)
  347. {
  348. try {
  349. unique_ptr<DiscoveryDatagram> packet = DiscoveryDatagram::interpretUDP(_from, _packet);
  350. if (!packet)
  351. return;
  352. if (packet->isExpired())
  353. {
  354. clog(NodeTableWarn) << "Invalid packet (timestamp in the past) from " << _from.address().to_string() << ":" << _from.port();
  355. return;
  356. }
  357. switch (packet->packetType())
  358. {
  359. case Pong::type:
  360. {
  361. auto in = dynamic_cast<Pong const&>(*packet);
  362. // whenever a pong is received, check if it's in m_evictions
  363. bool found = false;
  364. EvictionTimeout evictionEntry;
  365. DEV_GUARDED(x_evictions)
  366. for (auto it = m_evictions.begin(); it != m_evictions.end(); ++it)
  367. if (it->first.first == in.sourceid && it->first.second > std::chrono::steady_clock::now())
  368. {
  369. found = true;
  370. evictionEntry = *it;
  371. m_evictions.erase(it);
  372. break;
  373. }
  374. if (found)
  375. {
  376. if (auto n = nodeEntry(evictionEntry.second))
  377. dropNode(n);
  378. if (auto n = nodeEntry(evictionEntry.first.first))
  379. n->pending = false;
  380. }
  381. else
  382. {
  383. // if not, check if it's known/pending or a pubk discovery ping
  384. if (auto n = nodeEntry(in.sourceid))
  385. n->pending = false;
  386. else
  387. {
  388. DEV_GUARDED(x_pubkDiscoverPings)
  389. {
  390. if (!m_pubkDiscoverPings.count(_from.address()))
  391. return; // unsolicited pong; don't note node as active
  392. m_pubkDiscoverPings.erase(_from.address());
  393. }
  394. if (!haveNode(in.sourceid))
  395. addNode(Node(in.sourceid, NodeIPEndpoint(_from.address(), _from.port(), _from.port())));
  396. }
  397. }
  398. // update our endpoint address and UDP port
  399. DEV_GUARDED(x_nodes)
  400. {
  401. if ((!m_node.endpoint || !m_node.endpoint.isAllowed()) && isPublicAddress(in.destination.address))
  402. m_node.endpoint.address = in.destination.address;
  403. m_node.endpoint.udpPort = in.destination.udpPort;
  404. }
  405. clog(NodeTableConnect) << "PONG from " << in.sourceid << _from;
  406. break;
  407. }
  408. case Neighbours::type:
  409. {
  410. auto in = dynamic_cast<Neighbours const&>(*packet);
  411. bool expected = false;
  412. auto now = chrono::steady_clock::now();
  413. DEV_GUARDED(x_findNodeTimeout)
  414. m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t)
  415. {
  416. if (t.first == in.sourceid && now - t.second < c_reqTimeout)
  417. expected = true;
  418. else if (t.first == in.sourceid)
  419. return true;
  420. return false;
  421. });
  422. if (!expected)
  423. {
  424. clog(NetConnect) << "Dropping unsolicited neighbours packet from " << _from.address();
  425. break;
  426. }
  427. for (auto n: in.neighbours)
  428. addNode(Node(n.node, n.endpoint));
  429. break;
  430. }
  431. case FindNode::type:
  432. {
  433. auto in = dynamic_cast<FindNode const&>(*packet);
  434. vector<shared_ptr<NodeEntry>> nearest = nearestNodeEntries(in.target);
  435. static unsigned const nlimit = (m_socketPointer->maxDatagramSize - 109) / 90;
  436. for (unsigned offset = 0; offset < nearest.size(); offset += nlimit)
  437. {
  438. Neighbours out(_from, nearest, offset, nlimit);
  439. out.sign(m_secret);
  440. if (out.data.size() > 1280)
  441. clog(NetWarn) << "Sending truncated datagram, size: " << out.data.size();
  442. m_socketPointer->send(out);
  443. }
  444. break;
  445. }
  446. case PingNode::type:
  447. {
  448. auto in = dynamic_cast<PingNode const&>(*packet);
  449. in.source.address = _from.address();
  450. in.source.udpPort = _from.port();
  451. addNode(Node(in.sourceid, in.source));
  452. Pong p(in.source);
  453. p.echo = sha3(in.echo);
  454. p.sign(m_secret);
  455. m_socketPointer->send(p);
  456. break;
  457. }
  458. }
  459. noteActiveNode(packet->sourceid, _from);
  460. }
  461. catch (std::exception const& _e)
  462. {
  463. clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port() << ": " << _e.what();
  464. }
  465. catch (...)
  466. {
  467. clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port();
  468. }
  469. }
  470. void NodeTable::doCheckEvictions()
  471. {
  472. m_timers.schedule(c_evictionCheckInterval.count(), [this](boost::system::error_code const& _ec)
  473. {
  474. if (_ec)
  475. clog(NodeTableMessageDetail) << "Check Evictions timer was probably cancelled: " << _ec.value() << _ec.message();
  476. if (_ec.value() == boost::asio::error::operation_aborted || m_timers.isStopped())
  477. return;
  478. bool evictionsRemain = false;
  479. list<shared_ptr<NodeEntry>> drop;
  480. {
  481. Guard le(x_evictions);
  482. Guard ln(x_nodes);
  483. for (auto& e: m_evictions)
  484. if (chrono::steady_clock::now() - e.first.second > c_reqTimeout)
  485. if (m_nodes.count(e.second))
  486. drop.push_back(m_nodes[e.second]);
  487. evictionsRemain = (m_evictions.size() - drop.size() > 0);
  488. }
  489. drop.unique();
  490. for (auto n: drop)
  491. dropNode(n);
  492. if (evictionsRemain)
  493. doCheckEvictions();
  494. });
  495. }
  496. void NodeTable::doDiscovery()
  497. {
  498. m_timers.schedule(c_bucketRefresh.count(), [this](boost::system::error_code const& _ec)
  499. {
  500. if (_ec)
  501. clog(NodeTableMessageDetail) << "Discovery timer was probably cancelled: " << _ec.value() << _ec.message();
  502. if (_ec.value() == boost::asio::error::operation_aborted || m_timers.isStopped())
  503. return;
  504. clog(NodeTableEvent) << "performing random discovery";
  505. NodeID randNodeId;
  506. crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size));
  507. crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size));
  508. doDiscover(randNodeId);
  509. });
  510. }
  511. unique_ptr<DiscoveryDatagram> DiscoveryDatagram::interpretUDP(bi::udp::endpoint const& _from, bytesConstRef _packet)
  512. {
  513. unique_ptr<DiscoveryDatagram> decoded;
  514. // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes)
  515. if (_packet.size() < h256::size + Signature::size + 1 + 3)
  516. {
  517. clog(NodeTableWarn) << "Invalid packet (too small) from " << _from.address().to_string() << ":" << _from.port();
  518. return decoded;
  519. }
  520. bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size));
  521. bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size));
  522. bytesConstRef signatureBytes(_packet.cropped(h256::size, Signature::size));
  523. bytesConstRef bodyBytes(_packet.cropped(h256::size + Signature::size + 1));
  524. h256 echo(sha3(hashedBytes));
  525. if (!_packet.cropped(0, h256::size).contentsEqual(echo.asBytes()))
  526. {
  527. clog(NodeTableWarn) << "Invalid packet (bad hash) from " << _from.address().to_string() << ":" << _from.port();
  528. return decoded;
  529. }
  530. Public sourceid(dev::recover(*(Signature const*)signatureBytes.data(), sha3(signedBytes)));
  531. if (!sourceid)
  532. {
  533. clog(NodeTableWarn) << "Invalid packet (bad signature) from " << _from.address().to_string() << ":" << _from.port();
  534. return decoded;
  535. }
  536. switch (signedBytes[0])
  537. {
  538. case PingNode::type:
  539. decoded.reset(new PingNode(_from, sourceid, echo));
  540. break;
  541. case Pong::type:
  542. decoded.reset(new Pong(_from, sourceid, echo));
  543. break;
  544. case FindNode::type:
  545. decoded.reset(new FindNode(_from, sourceid, echo));
  546. break;
  547. case Neighbours::type:
  548. decoded.reset(new Neighbours(_from, sourceid, echo));
  549. break;
  550. default:
  551. clog(NodeTableWarn) << "Invalid packet (unknown packet type) from " << _from.address().to_string() << ":" << _from.port();
  552. return decoded;
  553. }
  554. decoded->interpretRLP(bodyBytes);
  555. return decoded;
  556. }