From c7d6502b430503d44dde98659c81742e6b9b2bdb Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 16 Dec 2014 22:01:39 +0100 Subject: udp != tcp. history-commit. --- kademlia.cpp | 33 +++++++++++++++++++++++++++++++++ net.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ network.cpp | 55 ------------------------------------------------------- 3 files changed, 88 insertions(+), 55 deletions(-) create mode 100644 kademlia.cpp create mode 100644 net.cpp delete mode 100644 network.cpp diff --git a/kademlia.cpp b/kademlia.cpp new file mode 100644 index 00000000..21c28cb8 --- /dev/null +++ b/kademlia.cpp @@ -0,0 +1,33 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file kademlia.cpp + * @author Alex Leverington + * @date 2014 + * Basic networking tests + */ + +#include +#include +using namespace std; +using namespace dev; +using namespace dev::p2p; + +BOOST_AUTO_TEST_CASE(host_listen_udp4) +{ + +} + diff --git a/net.cpp b/net.cpp new file mode 100644 index 00000000..acdd649d --- /dev/null +++ b/net.cpp @@ -0,0 +1,55 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file network.cpp + * @author Marko Simovic + * @date 2014 + * Basic networking tests + */ + +#include +#include +#include +#include +#include +#include "TestHelper.h" +using namespace std; +using namespace dev; +using namespace dev::eth; + +// Disabled since tests shouldn't block (not the worst offender, but timeout should be reduced anyway). +/* +BOOST_AUTO_TEST_CASE(listen_port_busy) +{ + short port = 20000; + + //make use of the port ahead of our client + ba::io_service ioService; + bi::tcp::endpoint endPoint(bi::tcp::v4(), port); + bi::tcp::acceptor acceptor(ioService, endPoint); + acceptor.listen(10); + + //prepare client and try to listen on same, used, port + Client c1("TestClient1", KeyPair::create().address(), + (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string()); + + c1.startNetwork(port); + + BOOST_REQUIRE(c1.haveNetwork()); + BOOST_REQUIRE(c1.peerServer()->listenPort() != 0); + BOOST_REQUIRE(c1.peerServer()->listenPort() != port); +} +*/ diff --git a/network.cpp b/network.cpp deleted file mode 100644 index acdd649d..00000000 --- a/network.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file network.cpp - * @author Marko Simovic - * @date 2014 - * Basic networking tests - */ - -#include -#include -#include -#include -#include -#include "TestHelper.h" -using namespace std; -using namespace dev; -using namespace dev::eth; - -// Disabled since tests shouldn't block (not the worst offender, but timeout should be reduced anyway). -/* -BOOST_AUTO_TEST_CASE(listen_port_busy) -{ - short port = 20000; - - //make use of the port ahead of our client - ba::io_service ioService; - bi::tcp::endpoint endPoint(bi::tcp::v4(), port); - bi::tcp::acceptor acceptor(ioService, endPoint); - acceptor.listen(10); - - //prepare client and try to listen on same, used, port - Client c1("TestClient1", KeyPair::create().address(), - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string()); - - c1.startNetwork(port); - - BOOST_REQUIRE(c1.haveNetwork()); - BOOST_REQUIRE(c1.peerServer()->listenPort() != 0); - BOOST_REQUIRE(c1.peerServer()->listenPort() != port); -} -*/ -- cgit From d22e4b3b21b05aa3590f84847259ba17895a91b2 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 08:35:12 +0100 Subject: initial interface for udp. test sending/receiving udp. --- kademlia.cpp | 12 --------- net.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/kademlia.cpp b/kademlia.cpp index 21c28cb8..a9d7701c 100644 --- a/kademlia.cpp +++ b/kademlia.cpp @@ -17,17 +17,5 @@ /** @file kademlia.cpp * @author Alex Leverington * @date 2014 - * Basic networking tests */ -#include -#include -using namespace std; -using namespace dev; -using namespace dev::p2p; - -BOOST_AUTO_TEST_CASE(host_listen_udp4) -{ - -} - diff --git a/net.cpp b/net.cpp index acdd649d..e5265441 100644 --- a/net.cpp +++ b/net.cpp @@ -14,42 +14,76 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file network.cpp - * @author Marko Simovic +/** @file net.cpp + * @author Alex Leverington * @date 2014 - * Basic networking tests */ #include -#include -#include -#include -#include -#include "TestHelper.h" +#include +#include using namespace std; using namespace dev; -using namespace dev::eth; +using namespace dev::p2p; +namespace ba = boost::asio; +namespace bi = ba::ip; -// Disabled since tests shouldn't block (not the worst offender, but timeout should be reduced anyway). -/* -BOOST_AUTO_TEST_CASE(listen_port_busy) +class TestA: UDPSocketEvents, public Worker { - short port = 20000; +public: + TestA(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~TestA() { m_io.stop(); stopWorking(); } + + void start() { startWorking(); } + void doWork() { m_io.run(); } + + void onDisconnected(UDPSocketFace*) {}; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if(_packet.toString() == "AAAA") success = true; }; - //make use of the port ahead of our client - ba::io_service ioService; - bi::tcp::endpoint endPoint(bi::tcp::v4(), port); - bi::tcp::acceptor acceptor(ioService, endPoint); - acceptor.listen(10); + ba::io_service m_io; + shared_ptr> m_socket; + + bool success = false; +}; - //prepare client and try to listen on same, used, port - Client c1("TestClient1", KeyPair::create().address(), - (boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string()); +//struct TestBProtocol: UDPSocketEvents +//{ +// void onDisconnected(UDPSocketFace*) {}; +// void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { cout << "received TestBProtocol" << endl; }; +//}; +// +//class TestB: TestBProtocol +//{ +//public: +// TestB(): m_io(), m_socket(m_io, *this, 30300) {} +////private: +// ba::io_service m_io; +// UDPSocket m_socket; +//}; +// +//class TestC +//{ +//public: +// TestC(): m_io(), m_socket(m_io, m_rpc, 30300) {} +////private: +// ba::io_service m_io; +// TestBProtocol m_rpc; +// UDPSocket m_socket; +//}; - c1.startNetwork(port); +BOOST_AUTO_TEST_SUITE(p2p) - BOOST_REQUIRE(c1.haveNetwork()); - BOOST_REQUIRE(c1.peerServer()->listenPort() != 0); - BOOST_REQUIRE(c1.peerServer()->listenPort() != port); +BOOST_AUTO_TEST_CASE(test) +{ + UDPDatagram d; + d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); + d.data = bytes({65,65,65,65}); + + TestA a; a.start(); a.m_socket->connect(); + a.m_socket->send(d); + sleep(1); + BOOST_REQUIRE_EQUAL(true, a.success); } -*/ + +BOOST_AUTO_TEST_SUITE_END() + -- cgit From b3b4411c4c31d74fe0d7f5f2f85461036cac0f6e Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 17:21:06 +0100 Subject: spacing --- net.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net.cpp b/net.cpp index e5265441..0b320830 100644 --- a/net.cpp +++ b/net.cpp @@ -38,7 +38,7 @@ public: void doWork() { m_io.run(); } void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if(_packet.toString() == "AAAA") success = true; }; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } ba::io_service m_io; shared_ptr> m_socket; @@ -73,7 +73,7 @@ public: BOOST_AUTO_TEST_SUITE(p2p) -BOOST_AUTO_TEST_CASE(test) +BOOST_AUTO_TEST_CASE(test_txrx_one) { UDPDatagram d; d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); -- cgit From ed9a5e572a8254f1595154e302f51dd242673272 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 18 Dec 2014 20:25:36 +0100 Subject: stash --- net.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net.cpp b/net.cpp index 0b320830..1e8d20c5 100644 --- a/net.cpp +++ b/net.cpp @@ -28,6 +28,21 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; +class Kademlia: UDPSocketEvents +{ +public: + Kademlia(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~Kademlia() { m_io.stop(); stopWorking(); } + + void onDisconnected(UDPSocketFace*) {}; + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } + + ba::io_service m_io; + shared_ptr> m_socket; + + bool success = false; +}; + class TestA: UDPSocketEvents, public Worker { public: -- cgit From 4588bfba6655698396cf067d251a849ad4dfd7c1 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 19 Dec 2014 22:14:11 +0100 Subject: initialize atomics so udp messages are delivered on linux #656 --- net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net.cpp b/net.cpp index 1e8d20c5..34b20ccc 100644 --- a/net.cpp +++ b/net.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(test_txrx_one) d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); d.data = bytes({65,65,65,65}); - TestA a; a.start(); a.m_socket->connect(); + TestA a; a.m_socket->connect(); a.start(); a.m_socket->send(d); sleep(1); BOOST_REQUIRE_EQUAL(true, a.success); -- cgit From 16ba69ae780179d327bf05e164a3e176127ee462 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 19 Dec 2014 22:40:44 +0100 Subject: fix the fix --- net.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/net.cpp b/net.cpp index 34b20ccc..6e9efff1 100644 --- a/net.cpp +++ b/net.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include using namespace std; @@ -28,21 +29,6 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -class Kademlia: UDPSocketEvents -{ -public: - Kademlia(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~Kademlia() { m_io.stop(); stopWorking(); } - - void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } - - ba::io_service m_io; - shared_ptr> m_socket; - - bool success = false; -}; - class TestA: UDPSocketEvents, public Worker { public: -- cgit From 400d19b140acda22ffad294db5f8958190f728e4 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 22 Dec 2014 01:51:19 +0100 Subject: move some things for udp. added a class for kademlia. --- net.cpp | 567 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 530 insertions(+), 37 deletions(-) diff --git a/net.cpp b/net.cpp index 6e9efff1..0a22a7e6 100644 --- a/net.cpp +++ b/net.cpp @@ -20,8 +20,8 @@ */ #include -#include #include +#include #include using namespace std; using namespace dev; @@ -29,58 +29,551 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -class TestA: UDPSocketEvents, public Worker +/** + * Ping packet: Check if node is alive. + * PingNode is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * ipAddress: Our IP address. + * port: Our port. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + * Ping is used to implement evict. When a new node is seen for + * a given bucket which is full, the least-responsive node is pinged. + * If the pinged node doesn't respond then it is removed and the new + * node is inserted. + */ +struct PingNode: RLPDatagram +{ + bytes ipAddress; + uint16_t port; + uint64_t expiration; + + Signature signature; + +// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } +}; + +struct Pong: RLPDatagram { + // todo: weak-signed pong + Address from; + uint64_t replyTo; /// expiration from PingNode + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } +}; + +/** + * FindNeighbors Packet: Request k-nodes, closest to the target. + * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. + * + * signature: Signature of message. + * target: Address of NodeId. The responding node will send back nodes closest to the target. + * expiration: Triggers regeneration of packet. May also provide control over synchronization. + * + */ +struct FindNeighbors: RLPDatagram +{ + h160 target; + uint64_t expiration; + + Signature signature; + + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } +}; + +/** + * Node Packet: Multiple node packets are sent in response to FindNeighbors. + */ +struct Neighbors: RLPDatagram +{ + struct Node + { + bytes ipAddress; + uint16_t port; + NodeId node; +// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } + }; + + std::set nodes; + h256 nonce; + + Signature signature; + +// void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } +}; + +/** + * NodeTable using S/Kademlia system for node discovery and preference. + * untouched buckets are refreshed if they have not been touched within an hour + * + * Thread-safety is ensured by modifying NodeEntry details via + * shared_ptr replacement instead of mutating values. + * + * @todo don't try to evict node if node isRequired. (support for makeRequired) + * @todo optimize (use tree for state (or set w/custom compare for cache)) + * @todo constructor support for m_node, m_secret + * @todo use s_bitsPerStep for find and refresh/ping + * @todo exclude bucket from refresh if we have node as peer + * @todo restore nodes + */ +class NodeTable: UDPSocketEvents, public std::enable_shared_from_this +{ + using nodeSocket = UDPSocket; + using timePoint = std::chrono::steady_clock::time_point; + + static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. +// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. + static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. + const unsigned s_findTimout = 300; // How long to wait between find queries. +// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. + const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] + const unsigned s_bits = sizeof(Address); // Denoted by n. + const unsigned s_buckets = 8 * s_bits - 1; + const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. + const unsigned s_pingTimeout = 500; + static size_t const s_tableSize = Address::size * 8 - 1; // Address::size + +public: + static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } + +protected: + struct NodeDefaultEndpoint + { + NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {} + bi::udp::endpoint udp; + }; + + struct NodeEntry + { + NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} + NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} + Address id; + Public pubk; + NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) + const unsigned distance; + timePoint activePing; + }; + + struct NodeBucket + { + unsigned distance; + timePoint modified; + std::list> nodes; + }; + + using EvictionTimeout = std::pair,Address>; + public: - TestA(): Worker("test",0), m_io(), m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~TestA() { m_io.stop(); stopWorking(); } + NodeTable(ba::io_service& _io): + m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), + m_socket(new nodeSocket(_io, *this, 30300)), + m_socketPtr(m_socket.get()), + m_io(_io), + m_bucketRefreshTimer(m_io), + m_evictionCheckTimer(m_io) + { + for (unsigned i = 0; i < s_buckets; i++) + m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); + doRefreshBuckets(boost::system::error_code()); + } + + ~NodeTable() { + m_evictionCheckTimer.cancel(); + m_bucketRefreshTimer.cancel(); + m_socketPtr->disconnect(); + } + + void join() { doFindNode(m_node.id); } + + std::list
nodes() const + { + std::list
nodes; + Guard l(x_nodes); + for (auto& i: m_nodes) + nodes.push_back(i.second->id); + return std::move(nodes); + } + + NodeEntry operator[](Address _id) + { + Guard l(x_nodes); + return *m_nodes[_id]; + } + +protected: + void requestNeighbors(NodeEntry const& _node, Address _target) const + { + FindNeighbors p; + p.target = _target; + + p.to = _node.endpoint.udp; + p.seal(m_secret); + m_socketPtr->send(p); + } + + /// Dispatches udp requests in order to populate node table to be as close as possible to _node. + void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()) + { + if (!m_socketPtr->isOpen() || _round == 7) + return; + + auto nearest = findNearest(_node); + std::list> tried; + for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) + if (!_tried->count(nearest[i])) + { + tried.push_back(nearest[i]); + requestNeighbors(*nearest[i], _node); + } + else + continue; + + while (auto n = tried.front()) + { + _tried->insert(n); + tried.pop_front(); + } + + auto self(shared_from_this()); + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); + m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) + { + if (_ec) + return; + doFindNode(_node, _round + 1, _tried); + }); + } + + std::vector> findNearest(Address _target) + { + // send s_alpha FindNeighbors packets to nodes we know, closest to target + unsigned head = dist(m_node.id, _target); + unsigned tail = (head - 1) % (s_tableSize - 1); + + // todo: optimize with tree + std::map>> found; + unsigned count = 0; + + // if d is 0, then we roll look forward, if last, we reverse, else, spread from d + if (head != 0 && tail != s_tableSize) + while (head != tail && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + + if (count < s_bucketSize && head) + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head++; + tail = (tail - 1) % (s_tableSize - 1); + } + else if (head == 0) + while (head < s_bucketSize && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[head].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + head--; + } + else if (tail == s_tableSize - 1) + while (tail > 0 && count < s_bucketSize) + { + Guard l(x_state); + for (auto& n: m_state[tail].nodes) + if (auto p = n.lock()) + { + if (count < s_bucketSize) + found[dist(_target, p->id)].push_back(p); + else + break; + } + tail--; + } + + std::vector> ret; + for (auto& nodes: found) + for (auto& n: nodes.second) + ret.push_back(n); + return std::move(ret); + } + + void ping(bi::address _address, unsigned _port) const + { + PingNode p; + string ip = m_node.endpoint.udp.address().to_string(); + p.ipAddress = asBytes(ip); + p.port = m_node.endpoint.udp.port(); +// p.expiration; + p.seal(m_secret); + m_socketPtr->send(p); + } + + void ping(NodeEntry* _n) const + { + if (_n && _n->endpoint.udp.address().is_v4()) + ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); + } + + void evict(std::shared_ptr _leastSeen, std::shared_ptr _new) + { + if (!m_socketPtr->isOpen()) + return; + + Guard l(x_evictions); + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + if (m_evictions.size() == 1) + doCheckEvictions(boost::system::error_code()); + + m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); + ping(_leastSeen.get()); + } + void noteNode(Public _pubk, bi::udp::endpoint _endpoint) + { + Address id = right160(sha3(_pubk)); + std::shared_ptr node; + { + Guard l(x_nodes); + auto n = m_nodes.find(id); + if (n == m_nodes.end()) + { + m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); + node = m_nodes[id]; + } + else + node = n->second; + } + + noteNode(node); + } + + void noteNode(std::shared_ptr _n) + { + std::shared_ptr contested; + { + NodeBucket s = bucket(_n.get()); + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) + { + auto p = n.lock(); + if (!p || p == _n) + return true; + return false; + }); + + if (s.nodes.size() >= s_bucketSize) + { + contested = s.nodes.front().lock(); + if (!contested) + { + s.nodes.pop_front(); + s.nodes.push_back(_n); + } + } + else + s.nodes.push_back(_n); + } + + if (contested) + evict(contested, _n); + } + + void dropNode(std::shared_ptr _n) + { + NodeBucket s = bucket(_n.get()); + { + Guard l(x_state); + s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); + } + Guard l(x_nodes); + m_nodes.erase(_n->id); + } + + NodeBucket const& bucket(NodeEntry* _n) const + { + return m_state[_n->distance]; + } + + void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) + { + RLP rlp(_packet); + + + // whenever a pong is received, first check if it's in m_evictions, if so, remove it + Guard l(x_evictions); + } + + void onDisconnected(UDPSocketFace*) + { + + } + + void doCheckEvictions(boost::system::error_code const& _ec) + { + if (_ec || !m_socketPtr->isOpen()) + return; + + m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); + auto self(shared_from_this()); + m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) + { + if (_ec) + return; + + bool evictionsRemain = false; + std::list> drop; + { + Guard l(x_evictions); + for (auto& e: m_evictions) + if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) + { + Guard l(x_nodes); + drop.push_back(m_nodes[e.second]); + } + evictionsRemain = m_evictions.size() - drop.size() > 0; + } + + for (auto& n: drop) + dropNode(n); + + if (evictionsRemain) + doCheckEvictions(boost::system::error_code()); + }); + } + + void doRefreshBuckets(boost::system::error_code const& _ec) + { + cout << "refreshing buckets" << endl; + if (_ec) + return; + + // first check if there are any pending evictions + + + bool connected = m_socketPtr->isOpen(); + bool refreshed = false; + if (connected) + { + Guard l(x_state); + for (auto& d: m_state) + if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) + while (!d.nodes.empty()) + { + auto n = d.nodes.front(); + if (auto p = n.lock()) + { + refreshed = true; + ping(p.get()); + break; + } + d.nodes.pop_front(); + } + } + + unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; + auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; + m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); + m_bucketRefreshTimer.async_wait(runcb); + } + +private: + NodeEntry m_node; ///< This node. + Secret m_secret; ///< This nodes secret key. + + mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. + std::map> m_nodes; ///< Address -> Node table (most common lookup path) + + Mutex x_state; + std::array m_state; ///< State table; logbinned nodes. + + Mutex x_evictions; + std::deque m_evictions; ///< Eviction timeouts. + + shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. + nodeSocket* m_socketPtr; ///< Set to m_socket.get(). + ba::io_service& m_io; ///< Used by bucket refresh timer. + boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. + boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. +}; + +/** + * Only used for testing. Not useful beyond tests. + */ +class TestHost: public Worker +{ +public: + TestHost(): Worker("test",0), m_io() {}; + ~TestHost() { m_io.stop(); stopWorking(); } + void start() { startWorking(); } + void doWork() { m_io.run(); } + +protected: + ba::io_service m_io; +}; + +/** + * Only used for testing. Not useful beyond tests. + */ +class TestNodeHost: public TestHost +{ +public: + TestNodeHost(): m_nodes(m_io) {}; + ~TestNodeHost() { m_io.stop(); stopWorking(); } + void start() { startWorking(); } + void doWork() { m_io.run(); } + + NodeTable m_nodes; +}; + +class TestUDPSocket: UDPSocketEvents, public TestHost +{ +public: + TestUDPSocket(): m_socket(new UDPSocket(m_io, *this, 30300)) {} + ~TestUDPSocket() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } void onDisconnected(UDPSocketFace*) {}; - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } + void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } - ba::io_service m_io; - shared_ptr> m_socket; + shared_ptr> m_socket; bool success = false; }; -//struct TestBProtocol: UDPSocketEvents -//{ -// void onDisconnected(UDPSocketFace*) {}; -// void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { cout << "received TestBProtocol" << endl; }; -//}; -// -//class TestB: TestBProtocol -//{ -//public: -// TestB(): m_io(), m_socket(m_io, *this, 30300) {} -////private: -// ba::io_service m_io; -// UDPSocket m_socket; -//}; -// -//class TestC -//{ -//public: -// TestC(): m_io(), m_socket(m_io, m_rpc, 30300) {} -////private: -// ba::io_service m_io; -// TestBProtocol m_rpc; -// UDPSocket m_socket; -//}; - BOOST_AUTO_TEST_SUITE(p2p) -BOOST_AUTO_TEST_CASE(test_txrx_one) +BOOST_AUTO_TEST_CASE(kademlia) { - UDPDatagram d; - d.to = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300); - d.data = bytes({65,65,65,65}); + TestNodeHost nodeHost; - TestA a; a.m_socket->connect(); a.start(); +} + +BOOST_AUTO_TEST_CASE(test_txrx_one) +{ + UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); + TestUDPSocket a; a.m_socket->connect(); a.start(); a.m_socket->send(d); sleep(1); BOOST_REQUIRE_EQUAL(true, a.success); -- cgit From 88f7ff617d3878001ab7732a913e3ab21639b1db Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 22 Dec 2014 03:56:07 +0100 Subject: repot. --- net.cpp | 489 +--------------------------------------------------------------- 1 file changed, 1 insertion(+), 488 deletions(-) diff --git a/net.cpp b/net.cpp index 0a22a7e6..3d2e08eb 100644 --- a/net.cpp +++ b/net.cpp @@ -23,500 +23,13 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -/** - * Ping packet: Check if node is alive. - * PingNode is cached and regenerated after expiration - t, where t is timeout. - * - * signature: Signature of message. - * ipAddress: Our IP address. - * port: Our port. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - * Ping is used to implement evict. When a new node is seen for - * a given bucket which is full, the least-responsive node is pinged. - * If the pinged node doesn't respond then it is removed and the new - * node is inserted. - */ -struct PingNode: RLPDatagram -{ - bytes ipAddress; - uint16_t port; - uint64_t expiration; - - Signature signature; - -// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; } -}; - -struct Pong: RLPDatagram -{ - // todo: weak-signed pong - Address from; - uint64_t replyTo; /// expiration from PingNode - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << from << replyTo; } -}; - -/** - * FindNeighbors Packet: Request k-nodes, closest to the target. - * FindNeighbors is cached and regenerated after expiration - t, where t is timeout. - * - * signature: Signature of message. - * target: Address of NodeId. The responding node will send back nodes closest to the target. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. - * - */ -struct FindNeighbors: RLPDatagram -{ - h160 target; - uint64_t expiration; - - Signature signature; - - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } -}; - -/** - * Node Packet: Multiple node packets are sent in response to FindNeighbors. - */ -struct Neighbors: RLPDatagram -{ - struct Node - { - bytes ipAddress; - uint16_t port; - NodeId node; -// void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } - }; - - std::set nodes; - h256 nonce; - - Signature signature; - -// void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << nonce; } -}; - -/** - * NodeTable using S/Kademlia system for node discovery and preference. - * untouched buckets are refreshed if they have not been touched within an hour - * - * Thread-safety is ensured by modifying NodeEntry details via - * shared_ptr replacement instead of mutating values. - * - * @todo don't try to evict node if node isRequired. (support for makeRequired) - * @todo optimize (use tree for state (or set w/custom compare for cache)) - * @todo constructor support for m_node, m_secret - * @todo use s_bitsPerStep for find and refresh/ping - * @todo exclude bucket from refresh if we have node as peer - * @todo restore nodes - */ -class NodeTable: UDPSocketEvents, public std::enable_shared_from_this -{ - using nodeSocket = UDPSocket; - using timePoint = std::chrono::steady_clock::time_point; - - static unsigned const s_bucketSize = 16; // Denoted by k in [Kademlia]. Number of nodes stored in each bucket. -// const unsigned s_bitsPerStep = 5; // @todo Denoted by b in [Kademlia]. Bits by which address space will be divided for find responses. - static unsigned const s_alpha = 3; // Denoted by \alpha in [Kademlia]. Number of concurrent FindNeighbors requests. - const unsigned s_findTimout = 300; // How long to wait between find queries. -// const unsigned s_siblings = 5; // @todo Denoted by s in [S/Kademlia]. User-defined by sub-protocols. - const unsigned s_bucketRefresh = 3600; // Refresh interval prevents bucket from becoming stale. [Kademlia] - const unsigned s_bits = sizeof(Address); // Denoted by n. - const unsigned s_buckets = 8 * s_bits - 1; - const unsigned s_evictionCheckInterval = 75; // Interval by which eviction timeouts are checked. - const unsigned s_pingTimeout = 500; - static size_t const s_tableSize = Address::size * 8 - 1; // Address::size - -public: - static unsigned dist(Address const& _a, Address const& _b) { u160 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; } - -protected: - struct NodeDefaultEndpoint - { - NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {} - bi::udp::endpoint udp; - }; - - struct NodeEntry - { - NodeEntry(Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(0) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, bi::udp::endpoint _udp): id(_id), pubk(_pubk), endpoint(NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_id)) {} - NodeEntry(NodeEntry _src, Address _id, Public _pubk, NodeDefaultEndpoint _gw): id(_id), pubk(_pubk), endpoint(_gw), distance(dist(_src.id,_id)) {} - Address id; - Public pubk; - NodeDefaultEndpoint endpoint; ///< How we've previously connected to this node. (must match node's reported endpoint) - const unsigned distance; - timePoint activePing; - }; - - struct NodeBucket - { - unsigned distance; - timePoint modified; - std::list> nodes; - }; - - using EvictionTimeout = std::pair,Address>; - -public: - NodeTable(ba::io_service& _io): - m_node(NodeEntry(Address(), Public(), bi::udp::endpoint())), - m_socket(new nodeSocket(_io, *this, 30300)), - m_socketPtr(m_socket.get()), - m_io(_io), - m_bucketRefreshTimer(m_io), - m_evictionCheckTimer(m_io) - { - for (unsigned i = 0; i < s_buckets; i++) - m_state[i].distance = i, m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1); - doRefreshBuckets(boost::system::error_code()); - } - - ~NodeTable() { - m_evictionCheckTimer.cancel(); - m_bucketRefreshTimer.cancel(); - m_socketPtr->disconnect(); - } - - void join() { doFindNode(m_node.id); } - - std::list
nodes() const - { - std::list
nodes; - Guard l(x_nodes); - for (auto& i: m_nodes) - nodes.push_back(i.second->id); - return std::move(nodes); - } - - NodeEntry operator[](Address _id) - { - Guard l(x_nodes); - return *m_nodes[_id]; - } - -protected: - void requestNeighbors(NodeEntry const& _node, Address _target) const - { - FindNeighbors p; - p.target = _target; - - p.to = _node.endpoint.udp; - p.seal(m_secret); - m_socketPtr->send(p); - } - - /// Dispatches udp requests in order to populate node table to be as close as possible to _node. - void doFindNode(Address _node, unsigned _round = 0, std::shared_ptr>> _tried = std::shared_ptr>>()) - { - if (!m_socketPtr->isOpen() || _round == 7) - return; - - auto nearest = findNearest(_node); - std::list> tried; - for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++) - if (!_tried->count(nearest[i])) - { - tried.push_back(nearest[i]); - requestNeighbors(*nearest[i], _node); - } - else - continue; - - while (auto n = tried.front()) - { - _tried->insert(n); - tried.pop_front(); - } - - auto self(shared_from_this()); - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_findTimout)); - m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec) - { - if (_ec) - return; - doFindNode(_node, _round + 1, _tried); - }); - } - - std::vector> findNearest(Address _target) - { - // send s_alpha FindNeighbors packets to nodes we know, closest to target - unsigned head = dist(m_node.id, _target); - unsigned tail = (head - 1) % (s_tableSize - 1); - - // todo: optimize with tree - std::map>> found; - unsigned count = 0; - - // if d is 0, then we roll look forward, if last, we reverse, else, spread from d - if (head != 0 && tail != s_tableSize) - while (head != tail && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[head].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - - if (count < s_bucketSize && head) - for (auto& n: m_state[tail].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - head++; - tail = (tail - 1) % (s_tableSize - 1); - } - else if (head == 0) - while (head < s_bucketSize && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[head].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - head--; - } - else if (tail == s_tableSize - 1) - while (tail > 0 && count < s_bucketSize) - { - Guard l(x_state); - for (auto& n: m_state[tail].nodes) - if (auto p = n.lock()) - { - if (count < s_bucketSize) - found[dist(_target, p->id)].push_back(p); - else - break; - } - tail--; - } - - std::vector> ret; - for (auto& nodes: found) - for (auto& n: nodes.second) - ret.push_back(n); - return std::move(ret); - } - - void ping(bi::address _address, unsigned _port) const - { - PingNode p; - string ip = m_node.endpoint.udp.address().to_string(); - p.ipAddress = asBytes(ip); - p.port = m_node.endpoint.udp.port(); -// p.expiration; - p.seal(m_secret); - m_socketPtr->send(p); - } - - void ping(NodeEntry* _n) const - { - if (_n && _n->endpoint.udp.address().is_v4()) - ping(_n->endpoint.udp.address(), _n->endpoint.udp.port()); - } - - void evict(std::shared_ptr _leastSeen, std::shared_ptr _new) - { - if (!m_socketPtr->isOpen()) - return; - - Guard l(x_evictions); - m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); - if (m_evictions.size() == 1) - doCheckEvictions(boost::system::error_code()); - - m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id)); - ping(_leastSeen.get()); - } - - void noteNode(Public _pubk, bi::udp::endpoint _endpoint) - { - Address id = right160(sha3(_pubk)); - std::shared_ptr node; - { - Guard l(x_nodes); - auto n = m_nodes.find(id); - if (n == m_nodes.end()) - { - m_nodes[id] = std::shared_ptr(new NodeEntry(m_node, id, _pubk, _endpoint)); - node = m_nodes[id]; - } - else - node = n->second; - } - - noteNode(node); - } - - void noteNode(std::shared_ptr _n) - { - std::shared_ptr contested; - { - NodeBucket s = bucket(_n.get()); - Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) - { - auto p = n.lock(); - if (!p || p == _n) - return true; - return false; - }); - - if (s.nodes.size() >= s_bucketSize) - { - contested = s.nodes.front().lock(); - if (!contested) - { - s.nodes.pop_front(); - s.nodes.push_back(_n); - } - } - else - s.nodes.push_back(_n); - } - - if (contested) - evict(contested, _n); - } - - void dropNode(std::shared_ptr _n) - { - NodeBucket s = bucket(_n.get()); - { - Guard l(x_state); - s.nodes.remove_if([&_n](std::weak_ptr n) { return n.lock() == _n; }); - } - Guard l(x_nodes); - m_nodes.erase(_n->id); - } - - NodeBucket const& bucket(NodeEntry* _n) const - { - return m_state[_n->distance]; - } - - void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) - { - RLP rlp(_packet); - - - // whenever a pong is received, first check if it's in m_evictions, if so, remove it - Guard l(x_evictions); - } - - void onDisconnected(UDPSocketFace*) - { - - } - - void doCheckEvictions(boost::system::error_code const& _ec) - { - if (_ec || !m_socketPtr->isOpen()) - return; - - m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(s_evictionCheckInterval)); - auto self(shared_from_this()); - m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec) - { - if (_ec) - return; - - bool evictionsRemain = false; - std::list> drop; - { - Guard l(x_evictions); - for (auto& e: m_evictions) - if (chrono::steady_clock::now() - e.first.second > chrono::milliseconds(s_pingTimeout)) - { - Guard l(x_nodes); - drop.push_back(m_nodes[e.second]); - } - evictionsRemain = m_evictions.size() - drop.size() > 0; - } - - for (auto& n: drop) - dropNode(n); - - if (evictionsRemain) - doCheckEvictions(boost::system::error_code()); - }); - } - - void doRefreshBuckets(boost::system::error_code const& _ec) - { - cout << "refreshing buckets" << endl; - if (_ec) - return; - - // first check if there are any pending evictions - - - bool connected = m_socketPtr->isOpen(); - bool refreshed = false; - if (connected) - { - Guard l(x_state); - for (auto& d: m_state) - if (chrono::steady_clock::now() - d.modified > chrono::seconds(s_bucketRefresh)) - while (!d.nodes.empty()) - { - auto n = d.nodes.front(); - if (auto p = n.lock()) - { - refreshed = true; - ping(p.get()); - break; - } - d.nodes.pop_front(); - } - } - - unsigned nextRefresh = connected ? (refreshed ? 200 : s_bucketRefresh*1000) : 10000; - auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); }; - m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); - m_bucketRefreshTimer.async_wait(runcb); - } - -private: - NodeEntry m_node; ///< This node. - Secret m_secret; ///< This nodes secret key. - - mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const. - std::map> m_nodes; ///< Address -> Node table (most common lookup path) - - Mutex x_state; - std::array m_state; ///< State table; logbinned nodes. - - Mutex x_evictions; - std::deque m_evictions; ///< Eviction timeouts. - - shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. - nodeSocket* m_socketPtr; ///< Set to m_socket.get(). - ba::io_service& m_io; ///< Used by bucket refresh timer. - boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh. - boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions. -}; - /** * Only used for testing. Not useful beyond tests. */ -- cgit From 1e0d4c95ce3d788b0be8cb5b8b32ede72683e7ae Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 08:56:56 +0100 Subject: refactor constants to be determined during compile. added RLPXDatagram. constructors and updates to datagram constructors. docs and logging. WIP tests and host/harness for NodeTable. --- net.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/net.cpp b/net.cpp index 3d2e08eb..886e17a4 100644 --- a/net.cpp +++ b/net.cpp @@ -30,6 +30,8 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; +BOOST_AUTO_TEST_SUITE(p2p) + /** * Only used for testing. Not useful beyond tests. */ @@ -37,7 +39,7 @@ class TestHost: public Worker { public: TestHost(): Worker("test",0), m_io() {}; - ~TestHost() { m_io.stop(); stopWorking(); } + virtual ~TestHost() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } @@ -45,28 +47,62 @@ protected: ba::io_service m_io; }; +struct TestNodeTable: public NodeTable +{ + void generateTestNodes(int _count = 10) + { + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + m_testNodes.clear(); + for (auto i = 0; i < _count; i++) + m_testNodes.push_back(make_pair(KeyPair::create(),s_basePort++)); + } + std::vector> m_testNodes; // keypair and port + + /// Constructor + using NodeTable::NodeTable; + + void setup() + { + /// Phase 1 test: populate with pings + /// Phase 2 test: pre-populate *expected* ping-responses, send pings + + bi::address ourIp = bi::address::from_string("127.0.0.1"); + uint16_t ourPort = 30300; + bi::udp::endpoint ourEndpoint(ourIp, ourPort); + + generateTestNodes(); + for (auto& n: m_testNodes) + ping(bi::udp::endpoint(ourIp, n.second)); + + // wait 1ms between each send + // send PingNode for each s_bootstrapNodes + // wait until nodecount is s_testNodes.count() + + } + + void reset() + { + Guard l(x_state); + for (auto& n: m_state) n.nodes.clear(); + } +}; + /** * Only used for testing. Not useful beyond tests. */ -class TestNodeHost: public TestHost +struct TestNodeTableHost: public TestHost { -public: - TestNodeHost(): m_nodes(m_io) {}; - ~TestNodeHost() { m_io.stop(); stopWorking(); } - void start() { startWorking(); } - void doWork() { m_io.run(); } - - NodeTable m_nodes; + TestNodeTableHost(): nodeTable(new TestNodeTable(m_io)) {}; + shared_ptr nodeTable; }; class TestUDPSocket: UDPSocketEvents, public TestHost { public: TestUDPSocket(): m_socket(new UDPSocket(m_io, *this, 30300)) {} - ~TestUDPSocket() { m_io.stop(); stopWorking(); } - void start() { startWorking(); } - void doWork() { m_io.run(); } - + void onDisconnected(UDPSocketFace*) {}; void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; } @@ -75,12 +111,13 @@ public: bool success = false; }; -BOOST_AUTO_TEST_SUITE(p2p) - BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeHost nodeHost; - +// TestNodeTableHost node; +// node.start(); +// node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for +// node.nodeTable->setup(); +// sleep(1); } BOOST_AUTO_TEST_CASE(test_txrx_one) -- cgit From cb6517e99e568b01bd46eba5b1c403cea6ea3428 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 09:25:36 +0100 Subject: send/receive messages (not yet interepreted) --- net.cpp | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/net.cpp b/net.cpp index 886e17a4..d3aaae53 100644 --- a/net.cpp +++ b/net.cpp @@ -49,21 +49,10 @@ protected: struct TestNodeTable: public NodeTable { - void generateTestNodes(int _count = 10) - { - asserts(_count < 1000); - static uint16_t s_basePort = 30500; - - m_testNodes.clear(); - for (auto i = 0; i < _count; i++) - m_testNodes.push_back(make_pair(KeyPair::create(),s_basePort++)); - } - std::vector> m_testNodes; // keypair and port - /// Constructor using NodeTable::NodeTable; - void setup() + void setup(std::vector> const& _testNodes) { /// Phase 1 test: populate with pings /// Phase 2 test: pre-populate *expected* ping-responses, send pings @@ -72,8 +61,7 @@ struct TestNodeTable: public NodeTable uint16_t ourPort = 30300; bi::udp::endpoint ourEndpoint(ourIp, ourPort); - generateTestNodes(); - for (auto& n: m_testNodes) + for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); // wait 1ms between each send @@ -94,8 +82,32 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): nodeTable(new TestNodeTable(m_io)) {}; + TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + + void generateTestNodes(int _count = 10) + { + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + m_testNodes.clear(); + for (auto i = 0; i < _count; i++) + { + KeyPair k = KeyPair::create(); + m_testNodes.push_back(make_pair(k,s_basePort+i)); + testNodes.push_back(make_shared(m_io,k,s_basePort+i)); + } + } + std::vector> m_testNodes; // keypair and port + + void setup() + { + generateTestNodes(); + nodeTable->setup(m_testNodes); + } + + KeyPair m_alias; shared_ptr nodeTable; + std::vector> testNodes; }; class TestUDPSocket: UDPSocketEvents, public TestHost @@ -113,11 +125,11 @@ public: BOOST_AUTO_TEST_CASE(kademlia) { -// TestNodeTableHost node; -// node.start(); -// node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for -// node.nodeTable->setup(); -// sleep(1); + TestNodeTableHost node; + node.start(); + node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for + node.setup(); + sleep(1); } BOOST_AUTO_TEST_CASE(test_txrx_one) -- cgit From 25a905b740892831f07c3d54f465ddaaf83441a6 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 23 Dec 2014 13:44:52 +0100 Subject: basic implementation of packets --- net.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net.cpp b/net.cpp index d3aaae53..8277c1f7 100644 --- a/net.cpp +++ b/net.cpp @@ -54,7 +54,6 @@ struct TestNodeTable: public NodeTable void setup(std::vector> const& _testNodes) { - /// Phase 1 test: populate with pings /// Phase 2 test: pre-populate *expected* ping-responses, send pings bi::address ourIp = bi::address::from_string("127.0.0.1"); @@ -63,11 +62,6 @@ struct TestNodeTable: public NodeTable for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); - - // wait 1ms between each send - // send PingNode for each s_bootstrapNodes - // wait until nodecount is s_testNodes.count() - } void reset() -- cgit From aad7141f0af696ec386f58e41fa9ecc862f116d7 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 24 Dec 2014 10:22:27 +0100 Subject: message signing and verification. shutdown io/thread before dealloc in nodetable/testnodetables. --- net.cpp | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/net.cpp b/net.cpp index 8277c1f7..274f729c 100644 --- a/net.cpp +++ b/net.cpp @@ -42,6 +42,7 @@ public: virtual ~TestHost() { m_io.stop(); stopWorking(); } void start() { startWorking(); } void doWork() { m_io.run(); } + void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); } protected: ba::io_service m_io; @@ -52,18 +53,20 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - void setup(std::vector> const& _testNodes) + void pingAll(std::vector> const& _testNodes) { - /// Phase 2 test: pre-populate *expected* ping-responses, send pings - bi::address ourIp = bi::address::from_string("127.0.0.1"); - uint16_t ourPort = 30300; - bi::udp::endpoint ourEndpoint(ourIp, ourPort); - for (auto& n: _testNodes) ping(bi::udp::endpoint(ourIp, n.second)); } + void populate(std::vector> const& _testNodes) + { + bi::address ourIp = bi::address::from_string("127.0.0.1"); + for (auto& n: _testNodes) + noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + } + void reset() { Guard l(x_state); @@ -77,8 +80,9 @@ struct TestNodeTable: public NodeTable struct TestNodeTableHost: public TestHost { TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - void generateTestNodes(int _count = 10) + void generateTestNodes(int _count = 30) { asserts(_count < 1000); static uint16_t s_basePort = 30500; @@ -96,7 +100,16 @@ struct TestNodeTableHost: public TestHost void setup() { generateTestNodes(); - nodeTable->setup(m_testNodes); + } + + void pingAll() + { + nodeTable->pingAll(m_testNodes); + } + + void populate() + { + nodeTable->populate(m_testNodes); } KeyPair m_alias; @@ -123,7 +136,10 @@ BOOST_AUTO_TEST_CASE(kademlia) node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); - sleep(1); + node.pingAll(); + this_thread::sleep_for(chrono::milliseconds(500)); + + cout << "NodeTable:\n" << *node.nodeTable.get() << endl; } BOOST_AUTO_TEST_CASE(test_txrx_one) -- cgit From 7553954cf200f6ee7ee6ff6769020759dcb7b671 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 24 Dec 2014 14:48:47 +0100 Subject: memory --- net.cpp | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/net.cpp b/net.cpp index 274f729c..d5113b8b 100644 --- a/net.cpp +++ b/net.cpp @@ -57,14 +57,23 @@ struct TestNodeTable: public NodeTable { bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) + { ping(bi::udp::endpoint(ourIp, n.second)); + this_thread::sleep_for(chrono::milliseconds(5)); + } } - void populate(std::vector> const& _testNodes) + void populate(std::vector> const& _testNodes, size_t _count = 0) { + if (!_count) + _count = _testNodes.size(); + bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) - noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + if (_count--) + noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second)); + else + break; } void reset() @@ -82,7 +91,7 @@ struct TestNodeTableHost: public TestHost TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - void generateTestNodes(int _count = 30) + void generateTestNodes(int _count = 16) { asserts(_count < 1000); static uint16_t s_basePort = 30500; @@ -105,11 +114,13 @@ struct TestNodeTableHost: public TestHost void pingAll() { nodeTable->pingAll(m_testNodes); +// for (auto& n: testNodes) +// n->pingAll(m_testNodes); } - void populate() + void populate(size_t _count = 0) { - nodeTable->populate(m_testNodes); + nodeTable->populate(m_testNodes, _count); } KeyPair m_alias; @@ -130,6 +141,13 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(test_findnode_neighbors) +{ + // Executing findNode should result in a list which is serialized + // into Neighbors packet. Neighbors packet should then be deserialized + // into the same list of nearest nodes. +} + BOOST_AUTO_TEST_CASE(kademlia) { TestNodeTableHost node; @@ -137,12 +155,23 @@ BOOST_AUTO_TEST_CASE(kademlia) node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); node.pingAll(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + this_thread::sleep_for(chrono::milliseconds(10000)); + + node.nodeTable->reset(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + + node.populate(2); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; this_thread::sleep_for(chrono::milliseconds(500)); - cout << "NodeTable:\n" << *node.nodeTable.get() << endl; +// node.nodeTable->join(); +// this_thread::sleep_for(chrono::milliseconds(2000)); +// +// clog << "NodeTable:\n" << *node.nodeTable.get() << endl; } -BOOST_AUTO_TEST_CASE(test_txrx_one) +BOOST_AUTO_TEST_CASE(test_udp_once) { UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); TestUDPSocket a; a.m_socket->connect(); a.start(); -- cgit From b66334952443955b157e6693d871c7aa242ae07a Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 00:56:50 +0100 Subject: test encoding/decoding neighbors. add MAC. --- net.cpp | 101 +++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/net.cpp b/net.cpp index d5113b8b..4c45475f 100644 --- a/net.cpp +++ b/net.cpp @@ -53,7 +53,23 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - void pingAll(std::vector> const& _testNodes) + static std::vector> createTestNodes(int _count = 16) + { + std::vector> ret; + asserts(_count < 1000); + static uint16_t s_basePort = 30500; + + ret.clear(); + for (auto i = 0; i < _count; i++) + { + KeyPair k = KeyPair::create(); + ret.push_back(make_pair(k,s_basePort+i)); + } + + return std::move(ret); + } + + void pingTestNodes(std::vector> const& _testNodes) { bi::address ourIp = bi::address::from_string("127.0.0.1"); for (auto& n: _testNodes) @@ -63,7 +79,7 @@ struct TestNodeTable: public NodeTable } } - void populate(std::vector> const& _testNodes, size_t _count = 0) + void populateTestNodes(std::vector> const& _testNodes, size_t _count = 0) { if (!_count) _count = _testNodes.size(); @@ -88,44 +104,19 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)) {}; + TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes()) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } - - void generateTestNodes(int _count = 16) - { - asserts(_count < 1000); - static uint16_t s_basePort = 30500; - - m_testNodes.clear(); - for (auto i = 0; i < _count; i++) - { - KeyPair k = KeyPair::create(); - m_testNodes.push_back(make_pair(k,s_basePort+i)); - testNodes.push_back(make_shared(m_io,k,s_basePort+i)); - } - } - std::vector> m_testNodes; // keypair and port - void setup() - { - generateTestNodes(); - } + void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared(m_io,n.first,n.second)); } - void pingAll() - { - nodeTable->pingAll(m_testNodes); -// for (auto& n: testNodes) -// n->pingAll(m_testNodes); - } + void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); } - void populate(size_t _count = 0) - { - nodeTable->populate(m_testNodes, _count); - } + void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); } KeyPair m_alias; shared_ptr nodeTable; - std::vector> testNodes; + std::vector> testNodes; // keypair and port + std::vector> nodeTables; }; class TestUDPSocket: UDPSocketEvents, public TestHost @@ -141,6 +132,36 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(test_neighbors_packet) +{ + KeyPair k = KeyPair::create(); + std::vector> testNodes(TestNodeTable::createTestNodes()); + bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); + + Neighbors out(to); + for (auto n: testNodes) + { + Neighbors::Node node; + node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); + node.port = n.second; + node.node = n.first.pub(); + out.nodes.push_back(node); + } + out.sign(k.sec()); + + bytesConstRef packet(out.data.data(), out.data.size()); + bytesConstRef rlpBytes(packet.cropped(97, packet.size() - 97)); + Neighbors in = Neighbors::fromBytesConstRef(to, rlpBytes); + int count = 0; + for (auto n: in.nodes) + { + BOOST_REQUIRE_EQUAL(testNodes[count].second, n.port); + BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node); + BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node)); + count++; + } +} + BOOST_AUTO_TEST_CASE(test_findnode_neighbors) { // Executing findNode should result in a list which is serialized @@ -154,21 +175,23 @@ BOOST_AUTO_TEST_CASE(kademlia) node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); + node.populate(); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + node.pingAll(); + this_thread::sleep_for(chrono::milliseconds(4000)); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - this_thread::sleep_for(chrono::milliseconds(10000)); node.nodeTable->reset(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.populate(2); - clog << "NodeTable:\n" << *node.nodeTable.get() << endl; this_thread::sleep_for(chrono::milliseconds(500)); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; -// node.nodeTable->join(); -// this_thread::sleep_for(chrono::milliseconds(2000)); -// -// clog << "NodeTable:\n" << *node.nodeTable.get() << endl; + node.nodeTable->join(); + this_thread::sleep_for(chrono::milliseconds(2000)); + clog << "NodeTable:\n" << *node.nodeTable.get() << endl; } BOOST_AUTO_TEST_CASE(test_udp_once) -- cgit From 60f2344b2bbb9efec42469cebf62570dc5068284 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 26 Dec 2014 05:38:27 +0100 Subject: inline << operator, mute logging --- net.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net.cpp b/net.cpp index 4c45475f..d9b5d157 100644 --- a/net.cpp +++ b/net.cpp @@ -53,14 +53,14 @@ struct TestNodeTable: public NodeTable /// Constructor using NodeTable::NodeTable; - static std::vector> createTestNodes(int _count = 16) + static std::vector> createTestNodes(unsigned _count) { std::vector> ret; asserts(_count < 1000); static uint16_t s_basePort = 30500; ret.clear(); - for (auto i = 0; i < _count; i++) + for (unsigned i = 0; i < _count; i++) { KeyPair k = KeyPair::create(); ret.push_back(make_pair(k,s_basePort+i)); @@ -75,7 +75,7 @@ struct TestNodeTable: public NodeTable for (auto& n: _testNodes) { ping(bi::udp::endpoint(ourIp, n.second)); - this_thread::sleep_for(chrono::milliseconds(5)); + this_thread::sleep_for(chrono::milliseconds(2)); } } @@ -104,7 +104,7 @@ struct TestNodeTable: public NodeTable */ struct TestNodeTableHost: public TestHost { - TestNodeTableHost(): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes()) {}; + TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes(_count)) {}; ~TestNodeTableHost() { m_io.stop(); stopWorking(); } void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared(m_io,n.first,n.second)); } @@ -135,7 +135,7 @@ public: BOOST_AUTO_TEST_CASE(test_neighbors_packet) { KeyPair k = KeyPair::create(); - std::vector> testNodes(TestNodeTable::createTestNodes()); + std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); Neighbors out(to); @@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeTableHost node; + TestNodeTableHost node(12); node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(kademlia) clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.pingAll(); - this_thread::sleep_for(chrono::milliseconds(4000)); + this_thread::sleep_for(chrono::milliseconds(1000)); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->reset(); -- cgit From 94c1a961d9e7bfc951e10a8a81fc1513c23b9f65 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 28 Dec 2014 14:24:21 +0100 Subject: manually populate nodes for test rather than leveraging ping --- net.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net.cpp b/net.cpp index d9b5d157..8a2e2af7 100644 --- a/net.cpp +++ b/net.cpp @@ -111,6 +111,8 @@ struct TestNodeTableHost: public TestHost void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); } + void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); } + void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); } KeyPair m_alias; @@ -171,22 +173,21 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) BOOST_AUTO_TEST_CASE(kademlia) { - TestNodeTableHost node(12); + // Not yet a 'real' test. + TestNodeTableHost node(8); node.start(); node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for node.setup(); node.populate(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - node.pingAll(); - this_thread::sleep_for(chrono::milliseconds(1000)); + node.populateAll(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->reset(); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; - node.populate(2); - this_thread::sleep_for(chrono::milliseconds(500)); + node.populate(1); clog << "NodeTable:\n" << *node.nodeTable.get() << endl; node.nodeTable->join(); -- cgit From 96ebead6aa318f496fe5030f0d84236d0c39d3e0 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 4 Jan 2015 21:01:56 +0100 Subject: coding standards, h512 node id, mute warnings for clang builds. attempt inherited constructor fix for windows. --- boostTest.cpp | 4 ++++ net.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/boostTest.cpp b/boostTest.cpp index 7d89f853..cef3cc0a 100644 --- a/boostTest.cpp +++ b/boostTest.cpp @@ -21,4 +21,8 @@ */ #define BOOST_TEST_MODULE EthereumTests +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" #include +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/net.cpp b/net.cpp index 8a2e2af7..0a008d6e 100644 --- a/net.cpp +++ b/net.cpp @@ -171,6 +171,12 @@ BOOST_AUTO_TEST_CASE(test_findnode_neighbors) // into the same list of nearest nodes. } +BOOST_AUTO_TEST_CASE(test_windows_template) +{ + bi::udp::endpoint ep; + PingNode p(ep); +} + BOOST_AUTO_TEST_CASE(kademlia) { // Not yet a 'real' test. -- cgit From 682c68842ca9ac64fb4908c7de6587bc3c95a130 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 5 Jan 2015 22:01:23 +0100 Subject: code review --- net.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net.cpp b/net.cpp index 0a008d6e..6952c282 100644 --- a/net.cpp +++ b/net.cpp @@ -134,16 +134,16 @@ public: bool success = false; }; -BOOST_AUTO_TEST_CASE(test_neighbors_packet) +BOOST_AUTO_TEST_CASE(test_neighbours_packet) { KeyPair k = KeyPair::create(); std::vector> testNodes(TestNodeTable::createTestNodes(16)); bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000); - Neighbors out(to); + Neighbours out(to); for (auto n: testNodes) { - Neighbors::Node node; + Neighbours::Node node; node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); node.port = n.second; node.node = n.first.pub(); @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(test_neighbors_packet) bytesConstRef packet(out.data.data(), out.data.size()); bytesConstRef rlpBytes(packet.cropped(97, packet.size() - 97)); - Neighbors in = Neighbors::fromBytesConstRef(to, rlpBytes); + Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes); int count = 0; for (auto n: in.nodes) { @@ -164,10 +164,10 @@ BOOST_AUTO_TEST_CASE(test_neighbors_packet) } } -BOOST_AUTO_TEST_CASE(test_findnode_neighbors) +BOOST_AUTO_TEST_CASE(test_findnode_neighbours) { // Executing findNode should result in a list which is serialized - // into Neighbors packet. Neighbors packet should then be deserialized + // into Neighbours packet. Neighbours packet should then be deserialized // into the same list of nearest nodes. } -- cgit From 2cf2af356bbb22d15ceee5df1a9d27af0a4036cc Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 6 Jan 2015 16:51:10 +0100 Subject: define constructors for windows --- net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net.cpp b/net.cpp index 6952c282..94699513 100644 --- a/net.cpp +++ b/net.cpp @@ -51,7 +51,7 @@ protected: struct TestNodeTable: public NodeTable { /// Constructor - using NodeTable::NodeTable; + TestNodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300): NodeTable(_io, _alias, _port) {} static std::vector> createTestNodes(unsigned _count) { -- cgit From ecf3c0bb324b328b562408a5605aa33c6bfca9f4 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 6 Jan 2015 17:01:17 +0100 Subject: stl sleep_for, for windows --- net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net.cpp b/net.cpp index 94699513..67c50dae 100644 --- a/net.cpp +++ b/net.cpp @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(test_udp_once) UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65})); TestUDPSocket a; a.m_socket->connect(); a.start(); a.m_socket->send(d); - sleep(1); + this_thread::sleep_for(chrono::seconds(1)); BOOST_REQUIRE_EQUAL(true, a.success); } -- cgit