1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
#include "NetworkServerLookup.h"
#include <stdexcept>
#include <QHostInfo>
#include <QString>
std::tuple<QHostAddress, quint16>
network_server_lookup(QString query, quint16 default_service_port,
QHostAddress default_host_address,
QAbstractSocket::NetworkLayerProtocol required_protocol) {
query = query.trimmed();
QHostAddress host_address{default_host_address};
quint16 service_port{default_service_port};
QString host_name;
if (!query.isEmpty()) {
qsizetype port_colon_index = -1;
if ('[' == query[0]) {
// assume IPv6 combined address/port syntax [<address>]:<port>
auto close_bracket_index = query.lastIndexOf(']');
host_name = query.mid(1, close_bracket_index - 1);
port_colon_index = query.indexOf(':', close_bracket_index);
} else {
port_colon_index = query.lastIndexOf(':');
host_name = query.left(port_colon_index);
}
host_name = host_name.trimmed();
if (port_colon_index >= 0) {
bool ok;
service_port =
query.mid(port_colon_index + 1).trimmed().toUShort(&ok);
if (!ok) {
throw std::runtime_error{
"network server lookup error: invalid port"};
}
}
}
if (!host_name.isEmpty()) {
auto host_info = QHostInfo::fromName(host_name);
if (host_info.addresses().isEmpty()) {
throw std::runtime_error{
"network server lookup error: host name lookup failed"};
}
bool found{false};
for (int i{0}; i < host_info.addresses().size() && !found; ++i) {
host_address = host_info.addresses().at(i);
switch (required_protocol) {
case QAbstractSocket::IPv4Protocol:
case QAbstractSocket::IPv6Protocol:
if (required_protocol != host_address.protocol()) {
break;
}
[[fallthrough]];
case QAbstractSocket::AnyIPProtocol:
found = true;
break;
default:
throw std::runtime_error{
"network server lookup error: invalid required protocol"};
}
}
if (!found) {
throw std::runtime_error{
"network server lookup error: no suitable host address found"};
}
}
return std::make_tuple(host_address, service_port);
}
|