diff --git a/include/opendht/dht.h b/include/opendht/dht.h index 5b50aefac2dc8f2fa4980b803f6eec88871d243d..dd556c0c7275330c0096fc36d248e84fc012cdcd 100644 --- a/include/opendht/dht.h +++ b/include/opendht/dht.h @@ -27,11 +27,9 @@ THE SOFTWARE. #pragma once -#define WANT4 1 -#define WANT6 2 - #include "infohash.h" #include "value.h" +#include "network_engine.h" #include <string> #include <array> @@ -45,73 +43,6 @@ THE SOFTWARE. namespace dht { -using want_t = int_fast8_t; -using Address = std::pair<sockaddr_storage, socklen_t>; - -std::string print_addr(const sockaddr* sa, socklen_t slen); -std::string print_addr(const sockaddr_storage& ss, socklen_t sslen); -std::string printAddr(const Address& addr); - -struct NodeExport { - InfoHash id; - sockaddr_storage ss; - socklen_t sslen; -}; - -struct Node { - InfoHash id {}; - sockaddr_storage ss; - socklen_t sslen {0}; - time_point time {time_point::min()}; /* last time eared about */ - time_point reply_time {time_point::min()}; /* time of last correct reply received */ - time_point pinged_time {time_point::min()}; /* time of last message sent */ - unsigned pinged {0}; /* how many requests we sent since last reply */ - - Node() : ss() { - std::fill_n((uint8_t*)&ss, sizeof(ss), 0); - } - Node(const InfoHash& id, const sockaddr* sa, socklen_t salen) - : id(id), ss(), sslen(salen) { - std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss); - if ((unsigned)salen < sizeof(ss)) - std::fill_n((uint8_t*)&ss+salen, sizeof(ss)-salen, 0); - } - InfoHash getId() const { - return id; - } - std::pair<const sockaddr*, socklen_t> getAddr() const { - return {(const sockaddr*)&ss, sslen}; - } - std::string getAddrStr() const { - return print_addr(ss, sslen); - } - bool isExpired(time_point now) const; - bool isExpired() const { return isExpired(clock::now()); } - bool isGood(time_point now) const; - bool isMessagePending(time_point now) const; - NodeExport exportNode() const { return NodeExport {id, ss, sslen}; } - sa_family_t getFamily() const { return ss.ss_family; } - - void update(const sockaddr* sa, socklen_t salen); - - /** To be called when a message was sent to the node */ - void requested(time_point now); - - /** To be called when a message was received from the node. - Answer should be true if the message was an aswer to a request we made*/ - void received(time_point now, bool answer); - - friend std::ostream& operator<< (std::ostream& s, const Node& h); - - static constexpr const std::chrono::minutes NODE_GOOD_TIME {120}; - - /* The time after which we consider a node to be expirable. */ - static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {10}; - - /* Time for a request to timeout */ - static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {3}; -}; - /** * Main Dht class. * Provides a Distributed Hash Table node. @@ -193,7 +124,7 @@ public: * and an ID for the node. */ Dht(int s, int s6, Config config); - virtual ~Dht(); + virtual ~Dht() {} /** * Get the ID of the node. diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index e2b771d04eec8f0425674aba47c6caa0f5570051..657c1192ad776f699176ecf80beabf641262de1a 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -26,9 +26,9 @@ THE SOFTWARE. #pragma once -#include "dht.h" #include "value.h" #include "infohash.h" +#include "node.h" #include "utils.h" #include "rng.h" diff --git a/include/opendht/node.h b/include/opendht/node.h new file mode 100644 index 0000000000000000000000000000000000000000..ed7217c6e49fc9d7bcf8e4a25b5738582601fe97 --- /dev/null +++ b/include/opendht/node.h @@ -0,0 +1,96 @@ +/* +Copyright (C) 2009-2014 Juliusz Chroboczek +Copyright (C) 2014-2016 Savoir-faire Linux Inc. + +Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>, + Simon Désaulniers <sim.desaulniers@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once + +#include "utils.h" +#include "infohash.h" + +#include <arpa/inet.h> + +namespace dht { + +struct NodeExport { + InfoHash id; + sockaddr_storage ss; + socklen_t sslen; +}; + +struct Node { + InfoHash id {}; + sockaddr_storage ss; + socklen_t sslen {0}; + time_point time {time_point::min()}; /* last time eared about */ + time_point reply_time {time_point::min()}; /* time of last correct reply received */ + time_point pinged_time {time_point::min()}; /* time of last message sent */ + unsigned pinged {0}; /* how many requests we sent since last reply */ + + Node() : ss() { + std::fill_n((uint8_t*)&ss, sizeof(ss), 0); + } + Node(const InfoHash& id, const sockaddr* sa, socklen_t salen) + : id(id), ss(), sslen(salen) { + std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss); + if ((unsigned)salen < sizeof(ss)) + std::fill_n((uint8_t*)&ss+salen, sizeof(ss)-salen, 0); + } + InfoHash getId() const { + return id; + } + std::pair<const sockaddr*, socklen_t> getAddr() const { + return {(const sockaddr*)&ss, sslen}; + } + std::string getAddrStr() const { + return print_addr(ss, sslen); + } + bool isExpired(time_point now) const; + bool isExpired() const { return isExpired(clock::now()); } + bool isGood(time_point now) const; + bool isMessagePending(time_point now) const; + NodeExport exportNode() const { return NodeExport {id, ss, sslen}; } + sa_family_t getFamily() const { return ss.ss_family; } + + void update(const sockaddr* sa, socklen_t salen); + + /** To be called when a message was sent to the node */ + void requested(time_point now); + + /** To be called when a message was received from the node. + Answer should be true if the message was an aswer to a request we made*/ + void received(time_point now, bool answer); + + friend std::ostream& operator<< (std::ostream& s, const Node& h); + + static constexpr const std::chrono::minutes NODE_GOOD_TIME {120}; + + /* The time after which we consider a node to be expirable. */ + static constexpr const std::chrono::minutes NODE_EXPIRE_TIME {10}; + + /* Time for a request to timeout */ + static constexpr const std::chrono::seconds MAX_RESPONSE_TIME {3}; +}; + +} diff --git a/include/opendht/utils.h b/include/opendht/utils.h index ea8e1f0c0cdf1843ea8b0d3555ae1e3d926ab03e..a63799337d724956dfe62fd0537114291cef0cf1 100644 --- a/include/opendht/utils.h +++ b/include/opendht/utils.h @@ -19,6 +19,9 @@ #pragma once +#define WANT4 1 +#define WANT6 2 + #include <msgpack.hpp> #include <chrono> @@ -40,6 +43,13 @@ void erase_if(std::map<Key, Item>& map, const Condition& condition) namespace dht { +using Address = std::pair<sockaddr_storage, socklen_t>; +using want_t = int_fast8_t; + +std::string print_addr(const sockaddr* sa, socklen_t slen); +std::string print_addr(const sockaddr_storage& ss, socklen_t sslen); +std::string printAddr(const Address& addr); + class DhtException : public std::runtime_error { public: DhtException(const std::string &str = "") : diff --git a/src/dht.cpp b/src/dht.cpp index 8f5a5633331fbe422f051081ef17912cc1b01056..ac965407a7667c909a349563cb63af4857d8b529 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -91,35 +91,6 @@ to_hex(const uint8_t *buf, size_t buflen) return s.str(); } -std::string -dht::print_addr(const sockaddr* sa, socklen_t slen) -{ - char hbuf[NI_MAXHOST]; - char sbuf[NI_MAXSERV]; - std::stringstream out; - if (!getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { - if (sa->sa_family == AF_INET6) - out << "[" << hbuf << "]"; - else - out << hbuf; - if (strcmp(sbuf, "0")) - out << ":" << sbuf; - } else - out << "[invalid address]"; - return out.str(); -} - -std::string -dht::print_addr(const sockaddr_storage& ss, socklen_t sslen) -{ - return print_addr((const sockaddr*)&ss, sslen); -} - -std::string -dht::printAddr(const Address& addr) { - return print_addr((const sockaddr*)&addr.first, addr.second); -} - template <class DT> static double print_dt(DT d) { @@ -130,10 +101,6 @@ namespace dht { static constexpr InfoHash zeroes {}; -constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME; -constexpr std::chrono::minutes Node::NODE_GOOD_TIME; -constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME; - constexpr std::chrono::seconds Dht::SEARCH_GET_STEP; constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME; constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME; @@ -372,63 +339,6 @@ Dht::findNode(const InfoHash& id, sa_family_t af) const return {}; } -/* This is our definition of a known-good node. */ -bool -Node::isGood(time_point now) const -{ - return - not isExpired(now) && - reply_time >= now - NODE_GOOD_TIME && - time >= now - NODE_EXPIRE_TIME; -} - -bool -Node::isExpired(time_point now) const -{ - return pinged >= 3 && reply_time < pinged_time && pinged_time + MAX_RESPONSE_TIME < now; -} - -bool -Node::isMessagePending(time_point now) const -{ - return reply_time < pinged_time && pinged_time + MAX_RESPONSE_TIME > now; -} - -void -Node::update(const sockaddr* sa, socklen_t salen) -{ - std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss); - sslen = salen; -} - -/** To be called when a message was sent to the node */ -void -Node::requested(time_point now) -{ - pinged++; - if (reply_time > pinged_time || pinged_time + MAX_RESPONSE_TIME < now) - pinged_time = now; -} - -/** To be called when a message was received from the node. - Answer should be true if the message was an aswer to a request we made*/ -void -Node::received(time_point now, bool answer) -{ - time = now; - if (answer) { - pinged = 0; - reply_time = now; - } -} - -std::ostream& operator<< (std::ostream& s, const Node& h) -{ - s << h.id << " " << print_addr(h.ss, h.sslen); - return s; -} - - std::shared_ptr<Node> Dht::NodeCache::getNode(const InfoHash& id, sa_family_t family) { auto& list = family == AF_INET ? cache_4 : cache_6; @@ -2208,9 +2118,6 @@ Dht::Dht(int s, int s6, Config config) } -Dht::~Dht() -{} - /* Rate control for requests we receive. */ bool Dht::rateLimit() diff --git a/src/node.cpp b/src/node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bbc198208fc2f930df0a3b6f427fa77541c1b4c --- /dev/null +++ b/src/node.cpp @@ -0,0 +1,84 @@ +/* +Copyright (C) 2009-2014 Juliusz Chroboczek +Copyright (C) 2014-2016 Savoir-faire Linux Inc. + +Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com>, + Simon Désaulniers <sim.desaulniers@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "node.h" + +namespace dht { + +constexpr std::chrono::minutes Node::NODE_EXPIRE_TIME; +constexpr std::chrono::minutes Node::NODE_GOOD_TIME; +constexpr std::chrono::seconds Node::MAX_RESPONSE_TIME; + +/* This is our definition of a known-good node. */ +Node::isGood(time_point now) const +{ + return + not isExpired(now) && + reply_time >= now - NODE_GOOD_TIME && + time >= now - NODE_EXPIRE_TIME; +} + +bool +Node::isExpired(time_point now) const +{ + return pinged >= 3 && reply_time < pinged_time && pinged_time + MAX_RESPONSE_TIME < now; +} + +bool +Node::isMessagePending(time_point now) const +{ + return reply_time < pinged_time && pinged_time + MAX_RESPONSE_TIME > now; +} + +void +Node::update(const sockaddr* sa, socklen_t salen) +{ + std::copy_n((const uint8_t*)sa, salen, (uint8_t*)&ss); + sslen = salen; +} + +/** To be called when a message was sent to the node */ +void +Node::requested(time_point now) +{ + pinged++; + if (reply_time > pinged_time || pinged_time + MAX_RESPONSE_TIME < now) + pinged_time = now; +} + +/** To be called when a message was received from the node. + Answer should be true if the message was an aswer to a request we made*/ +void +Node::received(time_point now, bool answer) +{ + time = now; + if (answer) { + pinged = 0; + reply_time = now; + } +} + +} diff --git a/src/utils.cpp b/src/utils.cpp index d49b34aa21f3d9bf8bb84dea53d324a2abfa3711..5f2ea2bae5ca83ab01892132f7126418270e48e7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -21,6 +21,35 @@ namespace dht { +std::string +dht::print_addr(const sockaddr* sa, socklen_t slen) +{ + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + std::stringstream out; + if (!getnameinfo(sa, slen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { + if (sa->sa_family == AF_INET6) + out << "[" << hbuf << "]"; + else + out << hbuf; + if (strcmp(sbuf, "0")) + out << ":" << sbuf; + } else + out << "[invalid address]"; + return out.str(); +} + +std::string +dht::print_addr(const sockaddr_storage& ss, socklen_t sslen) +{ + return print_addr((const sockaddr*)&ss, sslen); +} + +std::string +dht::printAddr(const Address& addr) { + return print_addr((const sockaddr*)&addr.first, addr.second); +} + time_point from_time_t(std::time_t t) { return clock::now() + (std::chrono::system_clock::from_time_t(t) - std::chrono::system_clock::now()); }