diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index 683755aad28b6dc1f4a2efa63a402194561afaf9..25a8f4574a45e63badd1f29d1a95a61344592d7e 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -106,6 +106,12 @@ struct OPENDHT_PUBLIC Config { /** If set, the dht will load its state from this file on start and save its state in this file on shutdown */ std::string persist_path {}; + + /** If non-0, overrides the default global rate-limit.-1 means no limit. */ + ssize_t max_req_per_sec {0}; + + /** If non-0, overrides the default per-IP address rate-limit. -1 means no limit. */ + ssize_t max_peer_req_per_sec {0}; }; /** diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index f4b0eeec2ae4b1ce84396f3cf29381182edecfa8..f4b034c300810e4b7c4db5aa5f289642ead4bb6a 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -48,6 +48,12 @@ struct TransId; #define MSG_CONFIRM 0 #endif +struct NetworkConfig { + NetId network {0}; + ssize_t max_req_per_sec {0}; + ssize_t max_peer_req_per_sec {0}; +}; + class DhtProtocolException : public DhtException { public: // sent to another peer (http-like). @@ -207,7 +213,12 @@ public: using RequestExpiredCb = std::function<void(const Request&, bool)>; NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock); - NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler, + NetworkEngine( + InfoHash& myid, + NetworkConfig config, + std::unique_ptr<DatagramSocket>&& sock, + Logger& log, + Scheduler& scheduler, decltype(NetworkEngine::onError)&& onError, decltype(NetworkEngine::onNewNode)&& onNewNode, decltype(NetworkEngine::onReportedAddr)&& onReportedAddr, @@ -425,7 +436,6 @@ private: /*************** * Constants * ***************/ - static constexpr size_t MAX_REQUESTS_PER_SEC {1600}; /* the length of a node info buffer in ipv4 format */ static const constexpr size_t NODE4_INFO_BUF_LEN {HASH_LEN + sizeof(in_addr) + sizeof(in_port_t)}; /* the length of a node info buffer in ipv6 format */ @@ -513,17 +523,17 @@ private: /* DHT info */ const InfoHash& myid; - const NetId network {0}; + const NetworkConfig config {}; const std::unique_ptr<DatagramSocket> dht_socket; const Logger& DHT_LOG; NodeCache cache {}; // global limiting should be triggered by at least 8 different IPs - using IpLimiter = RateLimiter<MAX_REQUESTS_PER_SEC/8>; + using IpLimiter = RateLimiter; using IpLimiterMap = std::map<SockAddr, IpLimiter, SockAddr::ipCmp>; - IpLimiterMap address_rate_limiter {}; - RateLimiter<MAX_REQUESTS_PER_SEC> rate_limiter {}; + IpLimiterMap address_rate_limiter; + RateLimiter rate_limiter; size_t limiter_maintenance {0}; // requests handling diff --git a/include/opendht/rate_limiter.h b/include/opendht/rate_limiter.h index f9626700e5801996c76b94fb2b92fc6f101e8cdc..97abfea2dcb431f99ab5bb534ee3bebd79d0a93f 100644 --- a/include/opendht/rate_limiter.h +++ b/include/opendht/rate_limiter.h @@ -23,19 +23,23 @@ namespace dht { -template<size_t Quota, unsigned long Period=1> class RateLimiter { public: + RateLimiter() = delete; + RateLimiter(size_t quota) : quota_(quota) {} + /** Clear outdated records and return current quota usage */ size_t maintain(const time_point& now) { - auto limit = now - std::chrono::seconds(Period); + auto limit = now - std::chrono::seconds(1); while (not records.empty() and records.front() < limit) records.pop(); return records.size(); } /** Return false if quota is reached, insert record and return true otherwise. */ bool limit(const time_point& now) { - if (maintain(now) >= Quota) + if (quota_ == (size_t)-1) + return true; + if (maintain(now) >= quota_) return false; records.emplace(now); return true; @@ -43,7 +47,11 @@ public: bool empty() const { return records.empty(); } + size_t quota() const { + return quota_; + } private: + const size_t quota_; std::queue<time_point> records {}; }; diff --git a/python/opendht.pyx b/python/opendht.pyx index c0cc8d53e2a0625b847756cae9eb5e6bed5792fe..c888c0fc187fbee013b29c6efc0a80ab1d7fa508 100644 --- a/python/opendht.pyx +++ b/python/opendht.pyx @@ -458,6 +458,9 @@ cdef class DhtConfig(object): self._config.dht_config.node_config.network = netid def setMaintainStorage(self, bool maintain_storage): self._config.dht_config.node_config.maintain_storage = maintain_storage + def setRateLimit(self, ssize_t max_req_per_sec, ssize_t max_peer_req_per_sec): + self._config.dht_config.node_config.max_req_per_sec = max_req_per_sec + self._config.dht_config.node_config.max_peer_req_per_sec = max_peer_req_per_sec cdef class DhtRunner(_WithID): cdef cpp.shared_ptr[cpp.DhtRunner] thisptr diff --git a/python/opendht_cpp.pxd b/python/opendht_cpp.pxd index 34843eb1fc68862b08dd65ff8dbb13997322ceec..1bc866a0faf480aef893111491a0773d0bf5c568 100644 --- a/python/opendht_cpp.pxd +++ b/python/opendht_cpp.pxd @@ -211,6 +211,9 @@ cdef extern from "opendht/callbacks.h" namespace "dht": uint32_t network bool is_bootstrap bool maintain_storage + string persist_path + size_t max_req_per_sec + size_t max_peer_req_per_sec cppclass SecureDhtConfig: Config node_config Identity id diff --git a/python/tools/pingpong.py b/python/tools/pingpong.py index 23b5b1454f44b4cf6b21d10859c60680b624c2b1..71bd9f31268e49661c2964630aabb56d84616b12 100755 --- a/python/tools/pingpong.py +++ b/python/tools/pingpong.py @@ -19,13 +19,16 @@ import opendht as dht import time import asyncio +config = dht.DhtConfig() +config.setRateLimit(-1, -1) + ping_node = dht.DhtRunner() -ping_node.run() +ping_node.run(config=config) #ping_node.enableLogging() #ping_node.bootstrap("bootstrap.ring.cx", "4222") pong_node = dht.DhtRunner() -pong_node.run() +pong_node.run(config=config) #pong_node.enableLogging() pong_node.ping(ping_node.getBound()) @@ -42,7 +45,6 @@ def done(h, ok): def ping(node, h): global i - time.sleep(0.0075) i += 1 if i < MAX: node.put(h, dht.Value(b"hey"), lambda ok, nodes: done(node.getNodeId().decode(), ok)) diff --git a/src/dht.cpp b/src/dht.cpp index 1ac6ddd7702a9e4e3cf37a2f1d96c8e4a4e07512..16312e98739fa8c49b39a00fbe1ed2b5cdee21bc 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -39,6 +39,7 @@ constexpr std::chrono::minutes Dht::MAX_STORAGE_MAINTENANCE_EXPIRE_TIME; constexpr std::chrono::minutes Dht::SEARCH_EXPIRE_TIME; constexpr std::chrono::seconds Dht::LISTEN_EXPIRE_TIME; constexpr std::chrono::seconds Dht::REANNOUNCE_MARGIN; +static constexpr size_t MAX_REQUESTS_PER_SEC {1600}; NodeStatus Dht::getStatus(sa_family_t af) const @@ -1688,11 +1689,21 @@ Dht::~Dht() s.second->clear(); } +net::NetworkConfig +fromDhtConfig(const Config& config) +{ + net::NetworkConfig netConf; + netConf.network = config.network; + netConf.max_req_per_sec = config.max_req_per_sec ? config.max_req_per_sec : MAX_REQUESTS_PER_SEC; + netConf.max_peer_req_per_sec = config.max_peer_req_per_sec ? config.max_peer_req_per_sec : MAX_REQUESTS_PER_SEC/8; + return netConf; +} + Dht::Dht() : store(), network_engine(DHT_LOG, scheduler, {}) {} Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Logger& l) : DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(), - network_engine(myid, config.network, std::move(sock), DHT_LOG, scheduler, + network_engine(myid, fromDhtConfig(config), std::move(sock), DHT_LOG, scheduler, std::bind(&Dht::onError, this, _1, _2), std::bind(&Dht::onNewNode, this, _1, _2), std::bind(&Dht::onReportedAddr, this, _1, _2), diff --git a/src/network_engine.cpp b/src/network_engine.cpp index b7736d3d3b8fa2dddb5af86c413549fa245a2e62..3530a12be83274d813cc615acf08029c85216d9d 100644 --- a/src/network_engine.cpp +++ b/src/network_engine.cpp @@ -41,7 +41,6 @@ constexpr std::chrono::seconds NetworkEngine::RX_MAX_PACKET_TIME; constexpr std::chrono::seconds NetworkEngine::RX_TIMEOUT; const std::string NetworkEngine::my_v {"RNG1"}; -constexpr size_t NetworkEngine::MAX_REQUESTS_PER_SEC; static constexpr uint8_t v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0}; @@ -100,10 +99,10 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg) {} NetworkEngine::NetworkEngine(Logger& log, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock) - : myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler) + : myid(zeroes), dht_socket(std::move(sock)), DHT_LOG(log), rate_limiter((size_t)-1), scheduler(scheduler) {} -NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler, +NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c, std::unique_ptr<DatagramSocket>&& sock, Logger& log, Scheduler& scheduler, decltype(NetworkEngine::onError)&& onError, decltype(NetworkEngine::onNewNode)&& onNewNode, decltype(NetworkEngine::onReportedAddr)&& onReportedAddr, @@ -122,7 +121,9 @@ NetworkEngine::NetworkEngine(InfoHash& myid, NetId net, std::unique_ptr<Datagram onListen(std::move(onListen)), onAnnounce(std::move(onAnnounce)), onRefresh(std::move(onRefresh)), - myid(myid), network(net), dht_socket(std::move(sock)), DHT_LOG(log), scheduler(scheduler) + myid(myid), config(c), dht_socket(std::move(sock)), DHT_LOG(log), + rate_limiter(config.max_req_per_sec), + scheduler(scheduler) {} NetworkEngine::~NetworkEngine() { @@ -148,7 +149,7 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&, { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_U); pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0)); @@ -165,8 +166,8 @@ NetworkEngine::tellListenerRefreshed(Sp<Node> n, Tid socket_id, const InfoHash&, pk.pack(KEY_TID); pk.pack(socket_id); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } // send response @@ -178,7 +179,7 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_U); pk.pack_map(1 + (not values.empty()?1:0) + (not token.empty()?1:0)); @@ -195,8 +196,8 @@ NetworkEngine::tellListenerExpired(Sp<Node> n, Tid socket_id, const InfoHash&, c pk.pack(KEY_TID); pk.pack(socket_id); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } // send response @@ -300,7 +301,7 @@ NetworkEngine::rateLimit(const SockAddr& addr) const auto& now = scheduler.time(); // occasional IP limiter maintenance (a few times every second at max rate) - if (limiter_maintenance++ == MAX_REQUESTS_PER_SEC/8) { + if (limiter_maintenance++ == config.max_peer_req_per_sec) { for (auto it = address_rate_limiter.begin(); it != address_rate_limiter.end();) { if (it->second.maintain(now) == 0) address_rate_limiter.erase(it++); @@ -311,7 +312,11 @@ NetworkEngine::rateLimit(const SockAddr& addr) } // invoke per IP, then global rate limiter - return address_rate_limiter[addr].limit(now) and rate_limiter.limit(now); + return (config.max_peer_req_per_sec < 0 + or address_rate_limiter + .emplace(addr, config.max_peer_req_per_sec).first->second + .limit(now)) + and rate_limiter.limit(now); } bool @@ -380,8 +385,8 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f) return; } - if (msg->network != network) { - DHT_LOG.d("Received message from other network %u", msg->network); + if (msg->network != config.network) { + DHT_LOG.d("Received message from other config.network %u", msg->network); return; } @@ -619,7 +624,7 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o TransId tid (node->getNewTid()); msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); pk.pack(KEY_A); pk.pack_map(1); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -629,8 +634,8 @@ NetworkEngine::sendPing(Sp<Node> node, RequestCb&& on_done, RequestExpiredCb&& o pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::Ping, tid.toInt(), node, @@ -656,7 +661,7 @@ void NetworkEngine::sendPong(const SockAddr& addr, Tid tid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_R); pk.pack_map(2); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -667,8 +672,8 @@ NetworkEngine::sendPong(const SockAddr& addr, Tid tid) { pk.pack_bin_body((const char*)t.data(), t.size()); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } send(addr, buffer.data(), buffer.size()); @@ -680,7 +685,7 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want, TransId tid (n->getNewTid()); msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); pk.pack(KEY_A); pk.pack_map(2 + (want>0?1:0)); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -697,8 +702,8 @@ NetworkEngine::sendFindNode(Sp<Node> n, const InfoHash& target, want_t want, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::FindNode, tid.toInt(), n, @@ -726,7 +731,7 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query& TransId tid (n->getNewTid()); msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); pk.pack(KEY_A); pk.pack_map(2 + (query.where.getFilter() or not query.select.getSelection().empty() ? 1:0) + @@ -746,8 +751,8 @@ NetworkEngine::sendGetValues(Sp<Node> n, const InfoHash& info_hash, const Query& pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::GetValues, tid.toInt(), n, @@ -861,9 +866,9 @@ NetworkEngine::sendValueParts(const TransId& tid, const std::vector<Blob>& svals end = std::min(start + MTU, v.size()); buffer.clear(); msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(3+(network?1:0)); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + pk.pack_map(3+(config.network?1:0)); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } pk.pack(KEY_Y); pk.pack(KEY_V); pk.pack(KEY_TID); pk.pack_bin(tid.size()); @@ -886,7 +891,7 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes, { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_R); pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0)); @@ -927,8 +932,8 @@ NetworkEngine::sendNodesValues(const SockAddr& addr, Tid tid, const Blob& nodes, pk.pack_bin_body((const char*)t.data(), t.size()); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } // send response @@ -1017,7 +1022,7 @@ NetworkEngine::sendListen(Sp<Node> n, msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); auto has_query = query.where.getFilter() or not query.select.getSelection().empty(); pk.pack(KEY_A); pk.pack_map(4 + has_query); @@ -1035,8 +1040,8 @@ NetworkEngine::sendListen(Sp<Node> n, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::Listen, tid.toInt(), n, @@ -1060,7 +1065,7 @@ void NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_R); pk.pack_map(2); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -1071,8 +1076,8 @@ NetworkEngine::sendListenConfirmation(const SockAddr& addr, Tid tid) { pk.pack_bin_body((const char*)t.data(), t.size()); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } send(addr, buffer.data(), buffer.size()); @@ -1090,7 +1095,7 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n, TransId tid (n->getNewTid()); msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); pk.pack(KEY_A); pk.pack_map((created < scheduler.time() ? 5 : 4)); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -1107,8 +1112,8 @@ NetworkEngine::sendAnnounceValue(Sp<Node> n, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::AnnounceValue, tid.toInt(), n, @@ -1148,7 +1153,7 @@ NetworkEngine::sendRefreshValue(Sp<Node> n, TransId tid (n->getNewTid()); msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5+(network?1:0)); + pk.pack_map(5+(config.network?1:0)); pk.pack(KEY_A); pk.pack_map(4); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -1161,8 +1166,8 @@ NetworkEngine::sendRefreshValue(Sp<Node> n, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(KEY_Y); pk.pack(KEY_Q); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } auto req = std::make_shared<Request>(MessageType::Refresh, tid.toInt(), n, @@ -1193,7 +1198,7 @@ void NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4+(network?1:0)); + pk.pack_map(4+(config.network?1:0)); pk.pack(KEY_R); pk.pack_map(3); pk.pack(KEY_REQ_ID); pk.pack(myid); @@ -1205,8 +1210,8 @@ NetworkEngine::sendValueAnnounced(const SockAddr& addr, Tid tid, Value::Id vid) pk.pack_bin_body((const char*)t.data(), t.size()); pk.pack(KEY_Y); pk.pack(KEY_R); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } send(addr, buffer.data(), buffer.size()); @@ -1237,8 +1242,8 @@ NetworkEngine::sendError(const SockAddr& addr, pk.pack_bin_body((const char*)t.data(), t.size()); pk.pack(KEY_Y); pk.pack(KEY_E); pk.pack(KEY_UA); pk.pack(my_v); - if (network) { - pk.pack(KEY_NETID); pk.pack(network); + if (config.network) { + pk.pack(KEY_NETID); pk.pack(config.network); } send(addr, buffer.data(), buffer.size());