diff --git a/httpserver/service_node.cpp b/httpserver/service_node.cpp index 03c6b9b..73f105f 100644 --- a/httpserver/service_node.cpp +++ b/httpserver/service_node.cpp @@ -404,6 +404,8 @@ void ServiceNode::update_swarms() { // const char* ip = "149.56.148.124"; // const uint16_t port = 22023; + // TODO: this should be changed to lokid + const uint16_t port = 7777; const char* ip = "0.0.0.0"; @@ -417,11 +419,16 @@ void ServiceNode::update_swarms() { } })#"; - make_http_request( - ioc_, ip, port, "/json_rpc", req_body, - std::bind(&ServiceNode::on_swarm_update, this, std::placeholders::_1)); - - /// TODO: make an rpc request to lokid + make_http_request(ioc_, ip, port, "/json_rpc", req_body, + [this](std::shared_ptr res_body) { + try { + this->on_swarm_update(res_body); + } catch (const std::exception& e) { + BOOST_LOG_TRIVIAL(error) + << "Exception caught on swarm update: " + << e.what(); + } + }); update_timer_.expires_after(std::chrono::seconds(2)); diff --git a/httpserver/swarm.cpp b/httpserver/swarm.cpp index 1300156..11428a6 100644 --- a/httpserver/swarm.cpp +++ b/httpserver/swarm.cpp @@ -4,6 +4,7 @@ #include "service_node.h" #include +#include namespace loki { @@ -123,23 +124,40 @@ SwarmEvents Swarm::update_swarms(const all_swarms_t& swarms) { swarm_id_t get_swarm_by_pk(const std::vector& all_swarms, const std::string& pk) { - // TODO: handle errors - // TODO: get rid of allocations? + if (pk.size() != 66) { + throw std::invalid_argument("invalid pub key size"); + } - std::string pk0_str = std::string(pk.c_str() + 2, 16); - std::string pk1_str = std::string(pk.c_str() + 2 + 16, 16); - std::string pk2_str = std::string(pk.c_str() + 2 + 32, 16); - std::string pk3_str = std::string(pk.c_str() + 2 + 48, 16); + /// Create a buffer for 64 characters plus 4 nulls on 8-byte boundaries + char buf[68] = {}; - uint64_t pk0 = std::stoull(pk0_str, 0, 16); - uint64_t pk1 = std::stoull(pk1_str, 0, 16); - uint64_t pk2 = std::stoull(pk2_str, 0, 16); - uint64_t pk3 = std::stoull(pk3_str, 0, 16); + /// Note: pk is expected to contain two leading characters + /// (05 for the messenger) that do not participate in mapping - uint64_t res = pk0 ^ pk1 ^ pk2 ^ pk3; + memcpy(buf, pk.c_str() + 2, 16); + memcpy(buf + 17, pk.c_str() + 2 + 16, 16); + memcpy(buf + 34, pk.c_str() + 2 + 32, 16); + memcpy(buf + 51, pk.c_str() + 2 + 48, 16); - swarm_id_t cur_best = 0; - uint64_t cur_min = std::numeric_limits::max(); + /// Note: if conversion is not possible, we will still + /// get a value in res (possibly 0 or UINT64_MAX), which + /// we are not handling at the moment + uint64_t res = strtoull(buf, nullptr, 16); + res ^= strtoull(buf + 17, nullptr, 16); + res ^= strtoull(buf + 34, nullptr, 16); + res ^= strtoull(buf + 51, nullptr, 16); + + /// We reserve UINT64_MAX as a sentinel swarm id for unassigned snodes + constexpr swarm_id_t MAX_ID = std::numeric_limits::max() - 1; + constexpr swarm_id_t SENTINEL_ID = std::numeric_limits::max(); + + swarm_id_t cur_best = SENTINEL_ID; + uint64_t cur_min = SENTINEL_ID; + + /// We don't require that all_swarms is sorted, so we find + /// the smallest/largest elements in the same loop + swarm_id_t leftmost_id = SENTINEL_ID; + swarm_id_t rightmost_id = 0; for (const auto& si : all_swarms) { @@ -149,16 +167,30 @@ swarm_id_t get_swarm_by_pk(const std::vector& all_swarms, cur_best = si.swarm_id; cur_min = dist; } + + /// Find the letfmost + if (si.swarm_id < leftmost_id) { + leftmost_id = si.swarm_id; + } + + if (si.swarm_id > rightmost_id) { + rightmost_id = si.swarm_id; + } } // handle special case - - if (res > all_swarms[0].swarm_id) { - uint64_t dist = - std::numeric_limits::max() - res + all_swarms[0].swarm_id; - + if (res > leftmost_id) { + uint64_t dist = (MAX_ID - res) + leftmost_id; if (dist < cur_min) { - return all_swarms[0].swarm_id; + cur_best = leftmost_id; + } + } else { + // since rightmost is at least as large as leftmost, + // res <= rightmost in this branch, so the value will + // not overflow + uint64_t dist = res + (MAX_ID - rightmost_id); + if (dist < cur_min) { + cur_best = rightmost_id; } }