aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2010-10-20 13:55:08 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2010-10-20 13:55:08 +0000
commitdc42da2e630955262e7b1b0318c0528834a53969 (patch)
tree9fd1d1b1c85068dbe81f50ad34decab58edfa529 /src
parentf8c729d64378b062f721fe5fbf903f2d41a4f971 (diff)
downloadqxmpp-dc42da2e630955262e7b1b0318c0528834a53969.tar.gz
use asynchronous DNS SRV lookups to avoid freezing clients during lookup
Diffstat (limited to 'src')
-rw-r--r--src/QXmppOutgoingClient.cpp44
-rw-r--r--src/QXmppOutgoingClient.h2
-rw-r--r--src/QXmppOutgoingServer.cpp16
-rw-r--r--src/QXmppOutgoingServer.h2
-rw-r--r--src/QXmppSrvInfo.cpp31
-rw-r--r--src/QXmppSrvInfo_p.h60
-rw-r--r--src/src.pro1
7 files changed, 135 insertions, 21 deletions
diff --git a/src/QXmppOutgoingClient.cpp b/src/QXmppOutgoingClient.cpp
index ed51eb9c..08f557a9 100644
--- a/src/QXmppOutgoingClient.cpp
+++ b/src/QXmppOutgoingClient.cpp
@@ -144,25 +144,41 @@ QXmppConfiguration& QXmppOutgoingClient::configuration()
void QXmppOutgoingClient::connectToHost()
{
+ const QString host = configuration().host();
+ const quint16 port = configuration().port();
+
+ // if an explicit host was provided, connect to it
+ if (!host.isEmpty() && port)
+ {
+ info(QString("Connecting to %1:%2").arg(host, QString::number(port)));
+ socket()->setProxy(configuration().networkProxy());
+ socket()->connectToHost(host, port);
+ return;
+ }
+
+ // otherwise, lookup server
+ const QString domain = configuration().domain();
+ debug(QString("Looking up server for domain %1").arg(domain));
+ QXmppSrvInfo::lookupService("_xmpp-client._tcp." + domain, this,
+ SLOT(connectToHost(QXmppSrvInfo)));
+}
+
+void QXmppOutgoingClient::connectToHost(const QXmppSrvInfo &serviceInfo)
+{
const QString domain = configuration().domain();
QString host = configuration().host();
quint16 port = configuration().port();
- // if we do not have no explicit host was provided, look it up
- if (host.isEmpty() || !port)
+ if (!serviceInfo.records().isEmpty())
{
- debug(QString("Looking up server for domain %1").arg(domain));
- QXmppSrvInfo serviceInfo = QXmppSrvInfo::fromName("_xmpp-client._tcp." + domain);
- if (!serviceInfo.records().isEmpty())
- {
- // take the first returned record
- host = serviceInfo.records().first().target();
- port = serviceInfo.records().first().port();
- } else {
- // as a fallback, use domain as the host name
- warning(QString("Lookup for domain %1 failed: %2").arg(domain, serviceInfo.errorString()));
- host = domain;
- }
+ // take the first returned record
+ host = serviceInfo.records().first().target();
+ port = serviceInfo.records().first().port();
+ } else {
+ // as a fallback, use domain as the host name
+ warning(QString("Lookup for domain %1 failed: %2")
+ .arg(domain, serviceInfo.errorString()));
+ host = domain;
}
// connect to server
diff --git a/src/QXmppOutgoingClient.h b/src/QXmppOutgoingClient.h
index c87c5b14..3d744854 100644
--- a/src/QXmppOutgoingClient.h
+++ b/src/QXmppOutgoingClient.h
@@ -39,6 +39,7 @@ class QXmppIq;
class QXmppMessage;
class QXmppRpcResponseIq;
class QXmppRpcErrorIq;
+class QXmppSrvInfo;
class QXmppOutgoingClientPrivate;
@@ -87,6 +88,7 @@ protected:
/// \endcond
private slots:
+ void connectToHost(const QXmppSrvInfo &serviceInfo);
void socketError(QAbstractSocket::SocketError);
void socketSslErrors(const QList<QSslError>&);
diff --git a/src/QXmppOutgoingServer.cpp b/src/QXmppOutgoingServer.cpp
index a7c92a56..93fcc703 100644
--- a/src/QXmppOutgoingServer.cpp
+++ b/src/QXmppOutgoingServer.cpp
@@ -77,12 +77,18 @@ QXmppOutgoingServer::~QXmppOutgoingServer()
void QXmppOutgoingServer::connectToHost(const QString &domain)
{
d->remoteDomain = domain;
- QString host;
- quint16 port;
// lookup server for domain
debug(QString("Looking up server for domain %1").arg(domain));
- QXmppSrvInfo serviceInfo = QXmppSrvInfo::fromName("_xmpp-server._tcp." + domain);
+ QXmppSrvInfo::lookupService("_xmpp-server._tcp." + domain, this,
+ SLOT(connectHost(serviceInfo)));
+}
+
+void QXmppOutgoingServer::connectToHost(const QXmppSrvInfo &serviceInfo)
+{
+ QString host;
+ quint16 port;
+
if (!serviceInfo.records().isEmpty())
{
// take the first returned record
@@ -90,8 +96,8 @@ void QXmppOutgoingServer::connectToHost(const QString &domain)
port = serviceInfo.records().first().port();
} else {
// as a fallback, use domain as the host name
- warning(QString("Lookup for domain %1 failed: %2").arg(domain, serviceInfo.errorString()));
- host = domain;
+ warning(QString("Lookup for domain %1 failed: %2").arg(d->remoteDomain, serviceInfo.errorString()));
+ host = d->remoteDomain;
port = 5269;
}
diff --git a/src/QXmppOutgoingServer.h b/src/QXmppOutgoingServer.h
index 055fe133..8298d9c0 100644
--- a/src/QXmppOutgoingServer.h
+++ b/src/QXmppOutgoingServer.h
@@ -30,6 +30,7 @@ class QSslError;
class QXmppDialback;
class QXmppOutgoingServer;
class QXmppOutgoingServerPrivate;
+class QXmppSrvInfo;
/// \brief The QXmppOutgoingServer class represents an outgoing XMPP stream
/// to another XMPP server.
@@ -64,6 +65,7 @@ protected:
/// \endcond
private slots:
+ void connectToHost(const QXmppSrvInfo &serviceInfo);
void slotSslErrors(const QList<QSslError> &errors);
private:
diff --git a/src/QXmppSrvInfo.cpp b/src/QXmppSrvInfo.cpp
index 4a0a95ea..7c2b06d8 100644
--- a/src/QXmppSrvInfo.cpp
+++ b/src/QXmppSrvInfo.cpp
@@ -22,9 +22,12 @@
*/
#include "QXmppSrvInfo.h"
+#include "QXmppSrvInfo_p.h"
+#include <QCoreApplication>
#include <QLibrary>
#include <QMetaObject>
+#include <QMetaType>
#if defined(Q_OS_WIN)
#include <windows.h>
@@ -41,6 +44,8 @@
#include <resolv.h>
#endif
+Q_GLOBAL_STATIC(QXmppSrvInfoLookupManager, theSrvInfoLookupManager)
+
#if defined(Q_OS_WIN)
typedef DNS_STATUS (*dns_query_utf8_proto)(PCSTR,WORD,DWORD,PIP4_ARRAY,PDNS_RECORD*,PVOID*);
static dns_query_utf8_proto local_dns_query_utf8 = 0;
@@ -535,7 +540,29 @@ QXmppSrvInfo QXmppSrvInfo::fromName(const QString &dname)
void QXmppSrvInfo::lookupService(const QString &name, QObject *receiver, const char *member)
{
- QXmppSrvInfo result = QXmppSrvInfo::fromName(name);
- QMetaObject::invokeMethod(receiver, member, Qt::QueuedConnection, Q_ARG(QXmppSrvInfo, result));
+ qRegisterMetaType<QXmppSrvInfo>("QXmppSrvInfo");
+
+ QXmppSrvInfoLookupManager *manager = theSrvInfoLookupManager();
+ if (manager)
+ {
+ // the application is still alive
+ QXmppSrvInfoLookupRunnable *runnable = new QXmppSrvInfoLookupRunnable(name);
+ QObject::connect(runnable, SIGNAL(foundInfo(QXmppSrvInfo)), receiver, member);
+ manager->start(runnable);
+ }
+}
+
+QXmppSrvInfoLookupManager::QXmppSrvInfoLookupManager()
+{
+ moveToThread(QCoreApplication::instance()->thread());
+ connect(QCoreApplication::instance(), SIGNAL(destroyed()),
+ SLOT(waitForThreadPoolDone()), Qt::DirectConnection);
+ setMaxThreadCount(5); // do 5 SRV lookups in parallel
+}
+
+void QXmppSrvInfoLookupRunnable::run()
+{
+ const QXmppSrvInfo result = QXmppSrvInfo::fromName(lookupName);
+ emit foundInfo(result);
}
diff --git a/src/QXmppSrvInfo_p.h b/src/QXmppSrvInfo_p.h
new file mode 100644
index 00000000..59076c70
--- /dev/null
+++ b/src/QXmppSrvInfo_p.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifndef QXMPPSRVINFO_P_H
+#define QXMPPSRVINFO_P_H
+
+#include <QRunnable>
+#include <QThreadPool>
+
+class QXmppSrvInfo;
+
+class QXmppSrvInfoLookupManager : public QThreadPool
+{
+ Q_OBJECT
+
+public:
+ QXmppSrvInfoLookupManager();
+
+private slots:
+ void waitForThreadPoolDone() { waitForDone(); }
+};
+
+class QXmppSrvInfoLookupRunnable : public QObject, public QRunnable
+{
+ Q_OBJECT
+
+public:
+ QXmppSrvInfoLookupRunnable(const QString &name)
+ : lookupName(name)
+ { }
+ void run();
+
+signals:
+ void foundInfo(const QXmppSrvInfo &info);
+
+private:
+ QString lookupName;
+};
+
+#endif
diff --git a/src/src.pro b/src/src.pro
index 0ee158d5..7fc88239 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -81,6 +81,7 @@ INSTALL_HEADERS = QXmppUtils.h \
QXmppVersionManager.h
HEADERS += $$INSTALL_HEADERS
+HEADERS += QXmppSrvInfo_p.h
# Source files
SOURCES += QXmppUtils.cpp \