diff --git a/src/core/core.cpp b/src/core/core.cpp index a640ef3d5..c11718e28 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -846,7 +846,9 @@ void Core::bootstrapDht() PARSE_ERR(error); } if (dhtServer.statusTcp) { - tox_add_tcp_relay(tox.get(), address.constData(), dhtServer.udpPort, pkPtr, &error); + const auto ports = dhtServer.tcpPorts.size(); + const auto tcpPort = rand() % ports; + tox_add_tcp_relay(tox.get(), address.constData(), tcpPort, pkPtr, &error); PARSE_ERR(error); } diff --git a/src/core/dhtserver.cpp b/src/core/dhtserver.cpp index 083eab2fc..20b1689c5 100644 --- a/src/core/dhtserver.cpp +++ b/src/core/dhtserver.cpp @@ -33,7 +33,8 @@ bool DhtServer::operator==(const DhtServer& other) const && ipv6 == other.ipv6 && maintainer == other.maintainer && userId == other.userId - && udpPort == other.udpPort); + && udpPort == other.udpPort + && tcpPorts == other.tcpPorts); } /** diff --git a/src/core/dhtserver.h b/src/core/dhtserver.h index 3ab6f79a1..259a5e5f7 100644 --- a/src/core/dhtserver.h +++ b/src/core/dhtserver.h @@ -20,6 +20,7 @@ #pragma once #include +#include struct DhtServer { @@ -30,6 +31,7 @@ struct DhtServer QString maintainer; QString userId; quint16 udpPort; + std::vector tcpPorts; bool operator==(const DhtServer& other) const; bool operator!=(const DhtServer& other) const; diff --git a/src/net/bootstrapnodeupdater.cpp b/src/net/bootstrapnodeupdater.cpp index bd3555a57..601552559 100644 --- a/src/net/bootstrapnodeupdater.cpp +++ b/src/net/bootstrapnodeupdater.cpp @@ -29,6 +29,9 @@ #include #include #include +#include + +#include namespace NodeFields { const QLatin1String status_udp{"status_udp"}; @@ -38,9 +41,8 @@ const QLatin1String ipv6{"ipv6"}; const QLatin1String public_key{"public_key"}; const QLatin1String udp_port{"port"}; const QLatin1String maintainer{"maintainer"}; -// TODO(sudden6): make use of this field once we differentiate between TCP nodes, and bootstrap nodes const QLatin1String tcp_ports{"tcp_ports"}; -const QStringList neededFields{status_udp, status_tcp, ipv4, ipv6, public_key, udp_port, maintainer}; +const QStringList neededFields{status_udp, status_tcp, ipv4, ipv6, public_key, udp_port, tcp_ports, maintainer}; } // namespace NodeFields namespace { @@ -63,13 +65,22 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) return; } - // only use nodes that provide at least UDP connection - if (!node[NodeFields::status_udp].toBool(false)) { - return; - } - const QString public_key = node[NodeFields::public_key].toString({}); const auto udp_port = node[NodeFields::udp_port].toInt(-1); + const auto status_udp = node[NodeFields::status_udp].toBool(false); + const auto status_tcp = node[NodeFields::status_tcp].toBool(false); + const QString maintainer = node[NodeFields::maintainer].toString({}); + + std::vector tcp_ports; + const auto jsonTcpPorts = node[NodeFields::tcp_ports].toArray(); + for (int i = 0; i < jsonTcpPorts.count(); ++i) { + const auto port = jsonTcpPorts.at(i).toInt(); + if (port < 1 || port > std::numeric_limits::max()) { + qDebug () << "Invalid TCP port in nodes list:" << port; + return; + } + tcp_ports.emplace_back(static_cast(port)); + } // nodes.tox.chat doesn't use empty strings for empty addresses QString ipv6_address = node[NodeFields::ipv6].toString({}); @@ -86,7 +97,13 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) qWarning() << "Both ipv4 and ipv4 addresses are empty for" << public_key; } - const QString maintainer = node[NodeFields::maintainer].toString({}); + if (status_udp && udp_port == -1) { + qWarning() << "UDP enabled but no UDP port for" << public_key; + } + + if (status_tcp && tcp_ports.empty()) { + qWarning() << "TCP enabled but no TCP ports for:" << public_key; + } if (udp_port < 1 || udp_port > std::numeric_limits::max()) { qDebug() << "Invalid port in nodes list:" << udp_port; @@ -101,7 +118,8 @@ void jsonNodeToDhtServer(const QJsonObject& node, QList& outList) DhtServer server; server.statusUdp = true; - server.statusTcp = node[NodeFields::status_udp].toBool(false); + server.statusTcp = status_tcp; + server.tcpPorts = tcp_ports; server.userId = public_key; server.udpPort = udp_port_u16; server.maintainer = maintainer; @@ -167,6 +185,12 @@ QByteArray serialize(QList nodes) nodeJson.insert(NodeFields::public_key, node.userId); nodeJson.insert(NodeFields::udp_port, node.udpPort); nodeJson.insert(NodeFields::maintainer, node.maintainer); + + QJsonArray tcp_ports; + for (size_t i = 0; i < node.tcpPorts.size(); ++i) { + tcp_ports.push_back(node.tcpPorts.at(i)); + } + nodeJson.insert(NodeFields::tcp_ports, tcp_ports); jsonNodes.append(nodeJson); } QJsonObject rootObj;