From 2b76b05b4005d461b15902e00f973ae64c1291c9 Mon Sep 17 00:00:00 2001 From: Sergei Ilinykh Date: Fri, 24 May 2024 11:52:43 +0300 Subject: [PATCH] Implemented XEP-0368 SRV records for XMPP over TLS --- src/irisnet/corelib/netnames.cpp | 191 +++++++++++++--------- src/irisnet/corelib/netnames.h | 39 +++-- src/irisnet/noncore/cutestuff/bsocket.cpp | 38 +++-- src/irisnet/noncore/cutestuff/bsocket.h | 7 +- src/xmpp/xmpp-core/connector.cpp | 10 +- src/xmpp/xmpp-core/xmpp.h | 2 +- 6 files changed, 172 insertions(+), 115 deletions(-) diff --git a/src/irisnet/corelib/netnames.cpp b/src/irisnet/corelib/netnames.cpp index 64be6fbe..560226c1 100644 --- a/src/irisnet/corelib/netnames.cpp +++ b/src/irisnet/corelib/netnames.cpp @@ -19,7 +19,7 @@ #include "netnames.h" -#include "addressresolver.h" +// #include "addressresolver.h" #include "corelib/irisnetglobal_p.h" #include "irisnetplugin.h" @@ -308,8 +308,8 @@ QDebug operator<<(QDebug dbg, XMPP::NameRecord::Type type) QDebug operator<<(QDebug dbg, const XMPP::NameRecord &record) { - dbg.nospace() << "XMPP::NameRecord(" << "owner=" << record.owner() << ", ttl=" << record.ttl() - << ", type=" << record.type(); + dbg.nospace() << "XMPP::NameRecord(" + << "owner=" << record.owner() << ", ttl=" << record.ttl() << ", type=" << record.type(); switch (record.type()) { case XMPP::NameRecord::A: @@ -444,7 +444,7 @@ class ServiceResolver::Private : public QObject { QAbstractSocket::NetworkLayerProtocol protocol; //!< IP protocol we are currently looking up XMPP::WeightedNameRecordList srvList; //!< List of resolved SRV names - QList hostList; //!< List or resolved hostnames for current SRV name + QList hostList; //!< List or resolved hostnames for current SRV name QList resolverList; //!< NameResolvers currently in use, needed for cleanup }; @@ -452,7 +452,7 @@ WeightedNameRecordList::WeightedNameRecordList() : currentPriorityGroup(priority { } -WeightedNameRecordList::WeightedNameRecordList(const QList &list) { append(list); } +WeightedNameRecordList::WeightedNameRecordList(const QList &list) { append(list); } WeightedNameRecordList::WeightedNameRecordList(const WeightedNameRecordList &other) { *this = other; } @@ -474,7 +474,7 @@ bool WeightedNameRecordList::isEmpty() const return currentPriorityGroup == const_cast(this)->priorityGroups.end(); } -XMPP::NameRecord WeightedNameRecordList::takeNext() +ServiceBoundRecord WeightedNameRecordList::takeNext() { /* Find the next useful priority group */ while (currentPriorityGroup != priorityGroups.end() && currentPriorityGroup->second.empty()) { @@ -485,13 +485,13 @@ XMPP::NameRecord WeightedNameRecordList::takeNext() #ifdef NETNAMES_DEBUG NNDEBUG << "No more SRV records left"; #endif - return XMPP::NameRecord(); + return {}; } /* Find the new total weight of this priority group */ int totalWeight = 0; for (const auto &record : std::as_const(currentPriorityGroup->second)) { - totalWeight += record.weight(); + totalWeight += record.record.weight(); } #ifdef NETNAMES_DEBUG @@ -499,11 +499,7 @@ XMPP::NameRecord WeightedNameRecordList::takeNext() #endif /* Pick a random entry */ -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) int randomWeight = totalWeight ? QRandomGenerator::global()->bounded(totalWeight) : 0; -#else - int randomWeight = qrand() / static_cast(RAND_MAX) * totalWeight; -#endif #ifdef NETNAMES_DEBUG NNDEBUG << "Picked weight:" << randomWeight; @@ -511,18 +507,19 @@ XMPP::NameRecord WeightedNameRecordList::takeNext() /* Iterate through the priority group until we found the randomly selected entry */ WeightedNameRecordPriorityGroup::iterator it(currentPriorityGroup->second.begin()); - for (int currentWeight = it->weight(); currentWeight < randomWeight; currentWeight += (++it)->weight()) { } + for (int currentWeight = it->record.weight(); currentWeight < randomWeight; + currentWeight += (++it)->record.weight()) { } Q_ASSERT(it != currentPriorityGroup->second.end()); /* We are going to delete the entry in the list, so save it */ - XMPP::NameRecord result(*it); + auto result { *it }; #ifdef NETNAMES_DEBUG NNDEBUG << "Picked record:" << result; #endif /* Delete the entry from list, to prevent it from being tried multiple times */ - currentPriorityGroup->second.remove(it->weight(), *it); + currentPriorityGroup->second.remove(it->record.weight(), *it); if (currentPriorityGroup->second.isEmpty()) { currentPriorityGroup = priorityGroups.erase(currentPriorityGroup); } @@ -542,7 +539,7 @@ void WeightedNameRecordList::append(const XMPP::WeightedNameRecordList &list) { /* Copy over all records from all groups */ for (const auto &group : list.priorityGroups) { - for (const NameRecord &record : group.second) + for (const auto &record : group.second) append(record); } @@ -550,21 +547,21 @@ void WeightedNameRecordList::append(const XMPP::WeightedNameRecordList &list) currentPriorityGroup = priorityGroups.begin(); } -void WeightedNameRecordList::append(const QList &list) +void WeightedNameRecordList::append(const QList &list) { - for (const XMPP::NameRecord &record : list) - if (record.type() == XMPP::NameRecord::Srv) + for (const auto &record : list) + if (record.record.type() == XMPP::NameRecord::Srv) append(record); /* Reset to beginning */ currentPriorityGroup = priorityGroups.begin(); } -void WeightedNameRecordList::append(const XMPP::NameRecord &record) +void WeightedNameRecordList::append(const ServiceBoundRecord &record) { - Q_ASSERT(record.type() == XMPP::NameRecord::Srv); - auto [it, _] = priorityGroups.try_emplace(record.priority(), WeightedNameRecordPriorityGroup {}); - it->second.insert(record.weight(), record); + Q_ASSERT(record.record.type() == XMPP::NameRecord::Srv); + auto [it, _] = priorityGroups.try_emplace(record.record.priority(), WeightedNameRecordPriorityGroup {}); + it->second.insert(record.record.weight(), record); /* Reset to beginning */ currentPriorityGroup = priorityGroups.begin(); @@ -575,7 +572,7 @@ void WeightedNameRecordList::append(const QString &hostname, quint16 port) NameRecord record(hostname.toLocal8Bit(), std::numeric_limits::max()); record.setSrv(hostname.toLocal8Bit(), port, std::numeric_limits::max(), 0); - append(record); + append(ServiceBoundRecord { {}, record }); /* Reset to beginning */ currentPriorityGroup = priorityGroups.begin(); @@ -587,18 +584,37 @@ XMPP::WeightedNameRecordList &WeightedNameRecordList::operator<<(const XMPP::Wei return *this; } -WeightedNameRecordList &WeightedNameRecordList::operator<<(const QList &list) +WeightedNameRecordList &WeightedNameRecordList::operator<<(const QList &list) { append(list); return *this; } -XMPP::WeightedNameRecordList &WeightedNameRecordList::operator<<(const XMPP::NameRecord &record) +XMPP::WeightedNameRecordList &WeightedNameRecordList::operator<<(const ServiceBoundRecord &record) { append(record); return *this; } +QDebug operator<<(QDebug dbg, const ServiceBoundRecord &r) +{ + dbg.nospace() << "XMPP::ServiceBoundRecor(\n"; + dbg.nospace() << "service=" << r.service +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + << Qt::endl; +#else + << endl; +#endif + dbg.nospace() << "record=" << r.record +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + << Qt::endl; +#else + << endl; +#endif + dbg.nospace() << "})"; + return dbg; +} + QDebug operator<<(QDebug dbg, const XMPP::WeightedNameRecordList &list) { dbg.nospace() << "XMPP::WeightedNameRecordList(\n"; @@ -810,7 +826,7 @@ class NameManager : public QObject { p_serv, &ServiceProvider::resolve_resultsReady, this, [this](int id, const QList &results) { ServiceResolver::Private *np = sres_instances.value(id); - emit np->q->resultReady(results[0].address, quint16(results[0].port), results[0].hostName); + emit np->q->resultReady(results[0].address, quint16(results[0].port), results[0].hostName, {}); }, Qt::QueuedConnection); } @@ -1126,7 +1142,7 @@ void ServiceResolver::setProtocol(ServiceResolver::Protocol p) { d->requestedPro void ServiceResolver::start(const QByteArray &name) { NameManager::instance()->resolve_instance_start(d, name); } /* normal host lookup */ -void ServiceResolver::start(const QString &host, quint16 port) +void ServiceResolver::start(const QString &host, quint16 port, const QString &service) { #ifdef NETNAMES_DEBUG NNDEBUG << "h:" << host << "p:" << port; @@ -1148,8 +1164,8 @@ void ServiceResolver::start(const QString &host, quint16 port) XMPP::NameRecord::Type querytype = (d->protocol == QAbstractSocket::IPv6Protocol ? XMPP::NameRecord::Aaaa : XMPP::NameRecord::A); XMPP::NameResolver *resolver = new XMPP::NameResolver; - connect(resolver, SIGNAL(resultsReady(QList)), this, - SLOT(handle_host_ready(QList))); + connect(resolver, &XMPP::NameResolver::resultsReady, this, + [this, service](const QList records) { handle_host_ready(service, records); }); connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), this, SLOT(handle_host_error(XMPP::NameResolver::Error))); resolver->start(host.toLocal8Bit(), querytype); @@ -1157,17 +1173,13 @@ void ServiceResolver::start(const QString &host, quint16 port) } /* SRV lookup */ -void ServiceResolver::start(const QString &service, const QString &transport, const QString &domain, int port) +void ServiceResolver::start(const QStringList &services, const QString &transport, const QString &domain, int port) { #ifdef NETNAMES_DEBUG NNDEBUG << "s:" << service << "t:" << transport << "d:" << domain << "p:" << port; #endif - - QString srv_request("_" + service + "._" + transport + "." + domain + "."); - /* clear SRV list */ d->srvList.clear(); - d->domain = domain; /* after we tried all SRV hosts, we shall connect directly (if requested) */ @@ -1178,55 +1190,68 @@ void ServiceResolver::start(const QString &service, const QString &transport, co Q_ASSERT(port == std::numeric_limits::max()); } - /* initiate the SRV lookup */ - XMPP::NameResolver *resolver = new XMPP::NameResolver; - connect(resolver, SIGNAL(resultsReady(QList)), this, - SLOT(handle_srv_ready(QList))); - connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)), this, - SLOT(handle_srv_error(XMPP::NameResolver::Error))); - resolver->start(srv_request.toLocal8Bit(), XMPP::NameRecord::Srv); - d->resolverList << resolver; -} + struct SrvStats { + std::function callback; + int counter = 0; + int success = 0; + SrvStats(std::function &&cb, int cnt) : callback(std::move(cb)), counter(cnt) { } + void finishOne(bool success) + { + if (success) + this->success++; + if (--counter == 0) + callback(this->success > 0); + } + }; + + auto stats = std::make_shared( + [this](bool success) { + if (success) { + emit srvReady(); + } else { + /* srvList already contains a failsafe host, try that */ + emit srvFailed(); + } + if (d->requestedProtocol != HappyEyeballs) { + try_next_srv(); + } + }, + services.size()); -/* SRV request resolved, now try to connect to the hosts */ -void ServiceResolver::handle_srv_ready(const QList &r) -{ + for (auto const &service : services) { + QString srv_request("_" + service + "._" + transport + "." + domain + "."); + + /* initiate the SRV lookup */ + auto resolver = new XMPP::NameResolver; + connect(resolver, &XMPP::NameResolver::resultsReady, this, + [this, resolver, stats, service](const QList &r) { #ifdef NETNAMES_DEBUG - NNDEBUG << "sl:" << r; + NNDEBUG << "sl:" << r; #endif - - /* cleanup resolver */ - cleanup_resolver(static_cast(sender())); - - /* lookup srv pointers */ - d->srvList << r; - emit srvReady(); - if (d->requestedProtocol != HappyEyeballs) { - try_next_srv(); - } -} - -/* failed the srv lookup, but we might have a fallback host in the srvList */ -void ServiceResolver::handle_srv_error(XMPP::NameResolver::Error e) -{ + QList sbr; + std::transform(r.begin(), r.end(), std::back_inserter(sbr), + [service](auto const &r) { return ServiceBoundRecord { service, r }; }); + d->srvList << sbr; + stats->finishOne(true); + cleanup_resolver(resolver); + }); + connect(resolver, &XMPP::NameResolver::error, this, [this, resolver, stats](XMPP::NameResolver::Error e) { + /* failed the srv lookup, but we might have a fallback host in the srvList */ #ifdef NETNAMES_DEBUG - NNDEBUG << "e:" << e; + NNDEBUG << "e:" << e; #else - Q_UNUSED(e) + Q_UNUSED(e) #endif - - /* cleanup resolver */ - cleanup_resolver(static_cast(sender())); - - /* srvList already contains a failsafe host, try that */ - emit srvFailed(); - if (d->requestedProtocol != HappyEyeballs) { - try_next_srv(); + stats->finishOne(false); + cleanup_resolver(resolver); + }); + resolver->start(srv_request.toLocal8Bit(), XMPP::NameRecord::Srv); + d->resolverList << resolver; } } /* hosts resolved, now try to connect to them */ -void ServiceResolver::handle_host_ready(const QList &r) +void ServiceResolver::handle_host_ready(const QString &service, const QList &rl) { #ifdef NETNAMES_DEBUG NNDEBUG << "hl:" << r; @@ -1236,7 +1261,9 @@ void ServiceResolver::handle_host_ready(const QList &r) cleanup_resolver(static_cast(sender())); /* connect to host */ - d->hostList << r; + for (auto const &r : rl) { + d->hostList << ServiceBoundRecord { service, r }; + } try_next_host(); } @@ -1322,9 +1349,9 @@ bool ServiceResolver::try_next_host() /* if there is a host left for current protocol (AAAA or A) */ if (!d->hostList.empty()) { - XMPP::NameRecord record(d->hostList.takeFirst()); + auto record { d->hostList.takeFirst() }; /* emit found address and the port specified earlier */ - emit resultReady(record.address(), d->port, record.owner()); + emit resultReady(record.record.address(), d->port, record.record.owner(), record.service); return true; } @@ -1340,10 +1367,10 @@ void ServiceResolver::try_next_srv() #endif /* if there are still hosts we did not try */ - XMPP::NameRecord record = d->srvList.takeNext(); - if (!record.isNull()) { + auto record = d->srvList.takeNext(); + if (!record.record.isNull()) { /* lookup host by name and specify port for later use */ - start(record.name(), quint16(record.port())); + start(record.record.name(), quint16(record.record.port()), record.service); } else { #ifdef NETNAMES_DEBUG NNDEBUG << "SRV list empty, failing"; @@ -1374,11 +1401,15 @@ ServiceResolver::ProtoSplit ServiceResolver::happySplit() s.ipv4->d->srvList = d->srvList; s.ipv4->d->hostList = d->hostList; s.ipv4->d->domain = d->domain; + s.ipv4->d->host = d->host; + s.ipv4->d->port = d->port; s.ipv6 = new ServiceResolver(this); s.ipv6->setProtocol(IPv6); s.ipv6->d->srvList = d->srvList; s.ipv6->d->hostList = d->hostList; s.ipv6->d->domain = d->domain; + s.ipv4->d->host = d->host; + s.ipv4->d->port = d->port; return s; } diff --git a/src/irisnet/corelib/netnames.h b/src/irisnet/corelib/netnames.h index 81767f63..ba48c27b 100644 --- a/src/irisnet/corelib/netnames.h +++ b/src/irisnet/corelib/netnames.h @@ -501,36 +501,47 @@ class IRISNET_EXPORT NameResolver : public QObject { IRISNET_EXPORT QDebug operator<<(QDebug, XMPP::NameResolver::Error); +struct ServiceBoundRecord { + QString service; + NameRecord record; + + bool operator==(const ServiceBoundRecord &other) const + { + return service == other.service && record == other.record; + }; +}; + class IRISNET_EXPORT WeightedNameRecordList { friend QDebug operator<<(QDebug, const WeightedNameRecordList &); public: WeightedNameRecordList(); - WeightedNameRecordList(const QList &list); + WeightedNameRecordList(const QList &list); WeightedNameRecordList(const WeightedNameRecordList &other); WeightedNameRecordList &operator=(const WeightedNameRecordList &other); ~WeightedNameRecordList(); - bool isEmpty() const; //!< Returns true if the list contains no items; otherwise returns false. - NameRecord takeNext(); //!< Removes the next host to try from the list and returns it. + bool isEmpty() const; //!< Returns true if the list contains no items; otherwise returns false. + ServiceBoundRecord takeNext(); //!< Removes the next host to try from the list and returns it. void clear(); //!< Removes all items from the list. void append(const WeightedNameRecordList &); - void append(const QList &); - void append(const NameRecord &); + void append(const QList &); + void append(const ServiceBoundRecord &); void append(const QString &hostname, quint16 port); WeightedNameRecordList &operator<<(const WeightedNameRecordList &); - WeightedNameRecordList &operator<<(const QList &); - WeightedNameRecordList &operator<<(const NameRecord &); + WeightedNameRecordList &operator<<(const QList &); + WeightedNameRecordList &operator<<(const ServiceBoundRecord &); private: - typedef QMultiMap WeightedNameRecordPriorityGroup; + typedef QMultiMap WeightedNameRecordPriorityGroup; typedef std::map WNRL; WNRL priorityGroups; WNRL::iterator currentPriorityGroup; }; +QDebug operator<<(QDebug, const ServiceBoundRecord &); QDebug operator<<(QDebug, const XMPP::WeightedNameRecordList &); class IRISNET_EXPORT ServiceBrowser : public QObject { @@ -620,15 +631,15 @@ class IRISNET_EXPORT ServiceResolver : public QObject { * \param host Hostname to lookup * \param port Port to signal via resultReady (for convenience) */ - void start(const QString &host, quint16 port); + void start(const QString &host, quint16 port, const QString &service = {}); /*! * Start an indirect (SRV) lookup for the service - * \param service Service type, like "ssh" or "ftp" + * \param services List of services considered to be the same type, like "ssh" or "ftp" * \param transport IP transport, like "tcp" or "udp" * \param domain Domainname to lookup * \param port Specify a valid port number to make ServiceResolver fallback to domain:port */ - void start(const QString &service, const QString &transport, const QString &domain, + void start(const QStringList &services, const QString &transport, const QString &domain, int port = std::numeric_limits::max()); /*! Announce the next resolved host, \sa resultReady */ @@ -651,7 +662,7 @@ class IRISNET_EXPORT ServiceResolver : public QObject { * \param port Port the service resides on * \param hostname Hostname form DNS reply with address:port */ - void resultReady(const QHostAddress &address, quint16 port, const QString &hostname); + void resultReady(const QHostAddress &address, quint16 port, const QString &hostname, const QString &service); /*! The lookup failed */ void error(XMPP::ServiceResolver::Error); /*! SRV domain:port records received. No IP yet. */ @@ -659,9 +670,7 @@ class IRISNET_EXPORT ServiceResolver : public QObject { void srvFailed(); private slots: - void handle_srv_ready(const QList &); - void handle_srv_error(XMPP::NameResolver::Error); - void handle_host_ready(const QList &); + void handle_host_ready(const QString &service, const QList &); void handle_host_error(XMPP::NameResolver::Error); void handle_host_fallback_error(XMPP::NameResolver::Error); diff --git a/src/irisnet/noncore/cutestuff/bsocket.cpp b/src/irisnet/noncore/cutestuff/bsocket.cpp index 3f677077..deb53564 100644 --- a/src/irisnet/noncore/cutestuff/bsocket.cpp +++ b/src/irisnet/noncore/cutestuff/bsocket.cpp @@ -27,7 +27,7 @@ #include #include -#include +// #include // if it's still needed please comment why // #define BS_DEBUG #ifdef BS_DEBUG @@ -83,11 +83,12 @@ class HappyEyeballsConnector : public QObject { QTcpSocketSignalRelay *relay; State state; QString hostname; // last resolved name + QString service; // one of services passed to service (SRV) resolver XMPP::ServiceResolver *resolver; }; /*! source data */ - QString service; + // QString service; QString transport; QString domain; quint16 port = 0; @@ -175,23 +176,23 @@ class HappyEyeballsConnector : public QObject { } } - void connectToHost(const QString &service, const QString &transport, const QString &domain, quint16 port) + void connectToHost(const QStringList &services, const QString &transport, const QString &domain, quint16 port) { #ifdef BS_DEBUG BSDEBUG << "s:" << service << "t:" << transport << "d:" << domain; #endif - this->service = service; + // this->service = service; this->transport = transport; this->domain = domain; this->port = port; SockData &sd = addSocket(); sd.resolver = new XMPP::ServiceResolver(this); sd.resolver->setProtocol(XMPP::ServiceResolver::HappyEyeballs); - connect(sd.resolver, SIGNAL(srvReady()), SLOT(splitSrvResolvers())); + connect(sd.resolver, &XMPP::ServiceResolver::srvReady, this, &HappyEyeballsConnector::splitSrvResolvers); // we don't care about special handling of fail. we have fallback host there anyway - connect(sd.resolver, SIGNAL(srvFailed()), SLOT(splitSrvResolvers())); + connect(sd.resolver, &XMPP::ServiceResolver::error, this, &HappyEyeballsConnector::splitSrvResolvers); sd.state = Resolve; - sd.resolver->start(service, transport, domain, port); + sd.resolver->start(services, transport, domain, port); } SockData takeCurrent(QObject *parent) @@ -300,9 +301,13 @@ private slots: BSDEBUG << "splitting resolvers"; #endif setCurrentByResolver(static_cast(sender())); - SockData &sdv4 = sockets[lastIndex]; - SockData &sdv6 = addSocket(); - XMPP::ServiceResolver::ProtoSplit ps = sdv4.resolver->happySplit(); + Q_ASSERT(lastIndex >= 0); + + auto tmp = lastIndex; + SockData &sdv6 = addSocket(); + SockData &sdv4 = sockets[tmp]; + + XMPP::ServiceResolver::ProtoSplit ps = sdv4.resolver->happySplit(); initResolver(ps.ipv4); initResolver(ps.ipv6); @@ -324,7 +329,7 @@ private slots: } /* host resolved, now try to connect to it */ - void handleDnsReady(const QHostAddress &address, quint16 port, const QString &hostname) + void handleDnsReady(const QHostAddress &address, quint16 port, const QString &hostname, const QString &service) { #ifdef BS_DEBUG BSDEBUG << "a:" << address << "p:" << port; @@ -332,6 +337,7 @@ private slots: setCurrentByResolver(static_cast(sender())); sockets[lastIndex].state = Connecting; sockets[lastIndex].hostname = hostname; + sockets[lastIndex].service = service; sockets[lastIndex].sock->connectToHost(address, port); } @@ -388,6 +394,7 @@ class BSocket::Private { QTcpSocketSignalRelay *qsock_relay; int state; + QString service; //!< One of passed to BSocket::connectToHost(QList) QString domain; //!< Domain we are currently connected to QString host; //!< Hostname we are currently connected to QHostAddress address; //!< IP address we are currently connected to @@ -483,15 +490,15 @@ void BSocket::connectToHost(const QString &host, quint16 port, QAbstractSocket:: d->connector->connectToHost(host, port, protocol); } -/* Connect to the hosts for the specified service */ -void BSocket::connectToHost(const QString &service, const QString &transport, const QString &domain, quint16 port) +/* Connect to the hosts for the specified services */ +void BSocket::connectToHost(const QStringList &services, const QString &transport, const QString &domain, quint16 port) { resetConnection(true); d->domain = domain; d->state = Connecting; ensureConnector(); - d->connector->connectToHost(service, transport, domain, port); + d->connector->connectToHost(services, transport, domain, port); } QAbstractSocket *BSocket::abstractSocket() const { return d->qsock; } @@ -622,12 +629,15 @@ quint16 BSocket::peerPort() const return 0; } +QString BSocket::service() const { return d->service; } + void BSocket::qs_connected() { HappyEyeballsConnector::SockData sd = d->connector->takeCurrent(this); d->qsock = sd.sock; d->qsock_relay = sd.relay; d->host = sd.hostname; + d->service = sd.service; d->connector->deleteLater(); qs_connected_step2(true); } diff --git a/src/irisnet/noncore/cutestuff/bsocket.h b/src/irisnet/noncore/cutestuff/bsocket.h index 17498585..99f68dd2 100644 --- a/src/irisnet/noncore/cutestuff/bsocket.h +++ b/src/irisnet/noncore/cutestuff/bsocket.h @@ -49,8 +49,9 @@ class BSocket : public ByteStream { void connectToHost(const QString &host, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::UnknownNetworkLayerProtocol); /*! Connect to the hosts for the specified service */ - void connectToHost(const QString &service, const QString &transport, const QString &domain, - quint16 port = std::numeric_limits::max()); + void connectToHost(const QStringList &services, const QString &transport, const QString &domain, + quint16 port = std::numeric_limits::max()); + virtual QAbstractSocket *abstractSocket() const; qintptr socket() const; void setSocket(QTcpSocket *); @@ -72,6 +73,8 @@ class BSocket : public ByteStream { QHostAddress peerAddress() const; quint16 peerPort() const; + QString service() const; + protected: qint64 writeData(const char *data, qint64 maxSize); qint64 readData(char *data, qint64 maxSize); diff --git a/src/xmpp/xmpp-core/connector.cpp b/src/xmpp/xmpp-core/connector.cpp index f73e8bd5..aea6a8b8 100644 --- a/src/xmpp/xmpp-core/connector.cpp +++ b/src/xmpp/xmpp-core/connector.cpp @@ -51,6 +51,7 @@ using namespace XMPP; static const int XMPP_DEFAULT_PORT = 5222; static const int XMPP_LEGACY_PORT = 5223; static const char *XMPP_CLIENT_SRV = "xmpp-client"; +static const char *XMPP_CLIENT_TLS_SRV = "xmpps-client"; static const char *XMPP_CLIENT_TRANSPORT = "tcp"; //---------------------------------------------------------------------------- @@ -326,7 +327,10 @@ void AdvancedConnector::connectToServer(const QString &server) XDEBUG << "Adding socket:" << s; #endif - connect(s, SIGNAL(connected()), SLOT(bs_connected())); + connect(s, &BSocket::connected, this, [this, s]() { + setUseSSL(s->service() == QLatin1String(XMPP_CLIENT_TLS_SRV)); + bs_connected(); + }); connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); if (!d->opt_host.isEmpty()) { /* if custom host:port */ @@ -337,8 +341,8 @@ void AdvancedConnector::connectToServer(const QString &server) } else if (d->opt_ssl != Never) { /* if ssl forced or should be probed */ d->port = XMPP_LEGACY_PORT; } - - s->connectToHost(XMPP_CLIENT_SRV, XMPP_CLIENT_TRANSPORT, d->host, quint16(d->port)); + QStringList services = { XMPP_CLIENT_SRV, XMPP_CLIENT_TLS_SRV }; + s->connectToHost(services, XMPP_CLIENT_TRANSPORT, d->host, quint16(d->port)); } } diff --git a/src/xmpp/xmpp-core/xmpp.h b/src/xmpp/xmpp-core/xmpp.h index 70e058fb..fa235974 100644 --- a/src/xmpp/xmpp-core/xmpp.h +++ b/src/xmpp/xmpp-core/xmpp.h @@ -76,7 +76,6 @@ class Connector : public QObject { quint16 peerPort() const; virtual QString host() const; - signals: void connected(); void error(); @@ -85,6 +84,7 @@ class Connector : public QObject { void setUseSSL(bool b); void setPeerAddressNone(); void setPeerAddress(const QHostAddress &addr, quint16 port); + void setRequireDirectTLS(bool require); private: bool ssl; // a flag to start ssl handshake immediately