aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2010-08-28 22:59:55 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2010-08-28 22:59:55 +0000
commit13b245f3bcc709b2a974b764bb209e1ea87768af (patch)
treeb3bbde11e5fd231bf059f09f308dddf776426a47 /src
parent8b58bfd72ad5d8e28e325c6cea61db270b9e626b (diff)
downloadqxmpp-13b245f3bcc709b2a974b764bb209e1ea87768af.tar.gz
update QXmppServer extensions API
Diffstat (limited to 'src')
-rw-r--r--src/QXmppIncomingClient.cpp25
-rw-r--r--src/QXmppServer.cpp42
-rw-r--r--src/QXmppServer.h2
-rw-r--r--src/QXmppServerExtension.cpp16
-rw-r--r--src/QXmppServerExtension.h4
-rw-r--r--src/server/mod_disco.cpp4
-rw-r--r--src/server/mod_disco.h16
-rw-r--r--src/server/mod_ping.cpp2
-rw-r--r--src/server/mod_proxy65.cpp183
-rw-r--r--src/server/mod_proxy65.h10
-rw-r--r--src/server/mod_version.cpp2
11 files changed, 197 insertions, 109 deletions
diff --git a/src/QXmppIncomingClient.cpp b/src/QXmppIncomingClient.cpp
index ace50158..f70d6edf 100644
--- a/src/QXmppIncomingClient.cpp
+++ b/src/QXmppIncomingClient.cpp
@@ -298,16 +298,37 @@ void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv)
}
}
- // unhandled stanza, emit it
+ // check the sender is legitimate
+ const QString from = nodeRecv.attribute("from");
+ if (!from.isEmpty() && from != jid() && from != jidToBareJid(jid()))
+ {
+ warning(QString("Received a stanza from unexpected JID %1").arg(from));
+ return;
+ }
+
+ // process unhandled stanzas
if (nodeRecv.tagName() == "iq" ||
nodeRecv.tagName() == "message" ||
nodeRecv.tagName() == "presence")
{
QDomElement nodeFull(nodeRecv);
- nodeFull.setAttribute("from", jid());
+
+ // if the sender is empty, set it to the appropriate JID
+ if (nodeFull.attribute("from").isEmpty())
+ {
+ if (nodeFull.tagName() == "presence" &&
+ (nodeFull.attribute("type") == "subscribe" ||
+ nodeFull.attribute("type") == "subscribed"))
+ nodeFull.setAttribute("from", jidToBareJid(jid()));
+ else
+ nodeFull.setAttribute("from", jid());
+ }
+
// if the recipient is empty, set it to the local domain
if (nodeFull.attribute("to").isEmpty())
nodeFull.setAttribute("to", d->domain);
+
+ // emit stanza for processing by server
emit elementReceived(nodeFull);
}
}
diff --git a/src/QXmppServer.cpp b/src/QXmppServer.cpp
index 1ba4c46c..40ebe57f 100644
--- a/src/QXmppServer.cpp
+++ b/src/QXmppServer.cpp
@@ -41,6 +41,7 @@
Q_IMPORT_PLUGIN(mod_disco)
Q_IMPORT_PLUGIN(mod_ping)
Q_IMPORT_PLUGIN(mod_proxy65)
+Q_IMPORT_PLUGIN(mod_stats)
Q_IMPORT_PLUGIN(mod_version)
class QXmppServerPrivate
@@ -56,7 +57,7 @@ public:
QString domain;
QList<QXmppServerExtension*> extensions;
- QMap<QString, QStringList> subscribers;
+ QMap<QString, QSet<QString> > subscribers;
QXmppLogger *logger;
QXmppPasswordChecker *passwordChecker;
@@ -194,6 +195,19 @@ QList<QXmppServerExtension*> QXmppServer::loadedExtensions()
return d->extensions;
}
+/// Returns the list of available resources for the given local JID.
+///
+/// \param bareJid
+
+QStringList QXmppServer::availableResources(const QString &bareJid)
+{
+ QStringList fullJids;
+ foreach (QXmppIncomingClient *client, d->incomingClients)
+ if (client->isConnected() && jidToBareJid(client->jid()) == bareJid)
+ fullJids << client->jid();
+ return fullJids;
+}
+
/// Returns the server's domain.
///
@@ -464,15 +478,10 @@ void QXmppServer::handleStanza(QXmppStream *stream, const QDomElement &element)
presence.parse(element);
const QString from = presence.from();
- QStringList subscribers = d->subscribers.value(from);
if (presence.type() == QXmppPresence::Available)
- {
- subscribers.append(to);
- d->subscribers[from] = subscribers;
- } else if (presence.type() == QXmppPresence::Unavailable) {
- subscribers.removeAll(to);
- d->subscribers[from] = subscribers;
- }
+ d->subscribers[from].insert(to);
+ else if (presence.type() == QXmppPresence::Unavailable)
+ d->subscribers[from].remove(to);
}
// route element or reply on behalf of missing peer
@@ -495,13 +504,18 @@ void QXmppServer::handleStanza(QXmppStream *stream, const QDomElement &element)
QStringList QXmppServer::subscribers(const QString &jid)
{
- QStringList recipients = d->subscribers.value(jid);
+ // start with directed presences
+ QSet<QString> recipients = d->subscribers.value(jid);
- // try extensions
+ // query extensions
foreach (QXmppServerExtension *extension, d->extensions)
- recipients += extension->presenceSubscribers(jid);
+ {
+ const QStringList extras = extension->presenceSubscribers(jid);
+ foreach (const QString &extra, extras)
+ recipients.insert(extra);
+ }
- return recipients;
+ return recipients.toList();
}
/// Route an XMPP stanza.
@@ -693,7 +707,7 @@ void QXmppServer::slotStreamDisconnected()
// notify subscribed peers of disconnection
if (!stream->jid().isEmpty())
{
- foreach (QString subscriber, d->subscribers.value(stream->jid()))
+ foreach (QString subscriber, subscribers(stream->jid()))
{
QXmppPresence presence;
presence.setFrom(stream->jid());
diff --git a/src/QXmppServer.h b/src/QXmppServer.h
index 75662e48..c5457299 100644
--- a/src/QXmppServer.h
+++ b/src/QXmppServer.h
@@ -74,6 +74,8 @@ public:
bool sendElement(const QDomElement &element);
bool sendPacket(const QXmppStanza &stanza);
+ QStringList availableResources(const QString &bareJid);
+
signals:
/// This signal is emitted when an XMPP stream is added.
void streamAdded(QXmppStream *stream);
diff --git a/src/QXmppServerExtension.cpp b/src/QXmppServerExtension.cpp
index e17304e9..9c5151a1 100644
--- a/src/QXmppServerExtension.cpp
+++ b/src/QXmppServerExtension.cpp
@@ -96,6 +96,22 @@ QStringList QXmppServerExtension::presenceSubscribers(const QString &jid)
return QStringList();
}
+/// Returns the extension's statistics.
+///
+
+QVariantMap QXmppServerExtension::statistics() const
+{
+ return QVariantMap();
+}
+
+/// Sets the extension's statistics.
+///
+
+void QXmppServerExtension::setStatistics(const QVariantMap &statistics)
+{
+ Q_UNUSED(statistics);
+}
+
/// Starts the extension.
///
/// Return true if the extension was started, false otherwise.
diff --git a/src/QXmppServerExtension.h b/src/QXmppServerExtension.h
index 7f860286..9b254986 100644
--- a/src/QXmppServerExtension.h
+++ b/src/QXmppServerExtension.h
@@ -25,6 +25,7 @@
#define QXMPPSERVEREXTENSION_H
#include <QObject>
+#include <QVariant>
class QDomElement;
class QStringList;
@@ -52,6 +53,9 @@ public:
virtual bool handleStanza(QXmppStream *stream, const QDomElement &stanza);
virtual QStringList presenceSubscribers(const QString &jid);
+ virtual QVariantMap statistics() const;
+ virtual void setStatistics(const QVariantMap &statistics);
+
virtual bool start();
virtual void stop();
diff --git a/src/server/mod_disco.cpp b/src/server/mod_disco.cpp
index 961f1f91..2c3d6fde 100644
--- a/src/server/mod_disco.cpp
+++ b/src/server/mod_disco.cpp
@@ -47,7 +47,7 @@ void QXmppServerDiscovery::setDiscoveryItems(const QStringList &items)
m_discoveryItems = items;
}
-bool QXmppServerDiscovery::handleStanza(QXmppStream *incoming, const QDomElement &element)
+bool QXmppServerDiscovery::handleStanza(QXmppStream *stream, const QDomElement &element)
{
if (element.attribute("to") != server()->domain())
return false;
@@ -95,7 +95,7 @@ bool QXmppServerDiscovery::handleStanza(QXmppStream *incoming, const QDomElement
features += extension->discoveryFeatures();
response.setFeatures(features);
}
- incoming->sendPacket(response);
+ server()->sendPacket(response);
return true;
}
return false;
diff --git a/src/server/mod_disco.h b/src/server/mod_disco.h
index 6816293a..b6101333 100644
--- a/src/server/mod_disco.h
+++ b/src/server/mod_disco.h
@@ -21,26 +21,30 @@
*
*/
-#ifndef QXMPP_SERVER_DISCOVERY_H
-#define QXMPP_SERVER_DISCOVERY_H
+#ifndef QXMPP_SERVER_DISCO_H
+#define QXMPP_SERVER_DISCO_H
#include <QStringList>
#include "QXmppServerExtension.h"
+/// \brief QXmppServer extension for XEP-0030: Service Discovery.
+///
+
class QXmppServerDiscovery : public QXmppServerExtension
{
Q_OBJECT
- Q_CLASSINFO("ExtensionName", "discovery");
+ Q_CLASSINFO("ExtensionName", "disco");
Q_PROPERTY(QStringList discoveryItems READ discoveryItems WRITE setDiscoveryItems);
public:
- QStringList discoveryFeatures() const;
-
QStringList discoveryItems() const;
void setDiscoveryItems(const QStringList &items);
- bool handleStanza(QXmppStream *incoming, const QDomElement &element);
+ /// \cond
+ QStringList discoveryFeatures() const;
+ bool handleStanza(QXmppStream *stream, const QDomElement &element);
+ /// \endcond
private:
QStringList m_discoveryItems;
diff --git a/src/server/mod_ping.cpp b/src/server/mod_ping.cpp
index 82837123..79d297e7 100644
--- a/src/server/mod_ping.cpp
+++ b/src/server/mod_ping.cpp
@@ -51,7 +51,7 @@ bool QXmppServerPing::handleStanza(QXmppStream *stream, const QDomElement &eleme
response.setId(request.id());
response.setFrom(request.to());
response.setTo(request.from());
- stream->sendPacket(response);
+ server()->sendPacket(response);
return true;
}
diff --git a/src/server/mod_proxy65.cpp b/src/server/mod_proxy65.cpp
index a5ce0744..76c9fb67 100644
--- a/src/server/mod_proxy65.cpp
+++ b/src/server/mod_proxy65.cpp
@@ -149,22 +149,25 @@ public:
quint16 port;
QMap<QString, QTcpSocketPair*> pairs;
- QList<TransferStats> recent;
QXmppSocksServer *server;
- QSettings *statistics;
- QString statisticsFile;
+
+ // statistics
+ QList<TransferStats> recent;
QTimer *statisticsTimer;
+ quint64 totalBytes;
+ quint64 totalTransfers;
};
QXmppServerProxy65::QXmppServerProxy65()
: d(new QXmppServerProxy65Private)
{
- d->statistics = 0;
+ d->port = 7777;
+ d->server = new QXmppSocksServer(this);
+
d->statisticsTimer = new QTimer(this);
d->statisticsTimer->setInterval(300 * 1000);
- d->statisticsTimer->start();
-
- d->server = new QXmppSocksServer(this);
+ d->totalBytes = 0;
+ d->totalTransfers = 0;
bool check = connect(d->server, SIGNAL(newConnection(QTcpSocket*, const QString&, quint16)),
this, SLOT(slotSocketConnected(QTcpSocket*, const QString &, quint16)));
@@ -180,6 +183,40 @@ QXmppServerProxy65::~QXmppServerProxy65()
delete d;
}
+/// Returns the proxy server's JID.
+///
+
+QString QXmppServerProxy65::jid() const
+{
+ return d->jid;
+}
+
+/// Set the proxy server's JID.
+///
+/// \param jid
+
+void QXmppServerProxy65::setJid(const QString &jid)
+{
+ d->jid = jid;
+}
+
+/// Returns the port on which to listen for SOCKS5 connections.
+///
+
+quint16 QXmppServerProxy65::port() const
+{
+ return d->port;
+}
+
+/// Sets the port on which to listen for SOCKS5 connections.
+///
+/// \param port
+
+void QXmppServerProxy65::setPort(quint16 port)
+{
+ d->port = port;
+}
+
QStringList QXmppServerProxy65::discoveryItems() const
{
return QStringList() << d->jid;
@@ -219,7 +256,7 @@ bool QXmppServerProxy65::handleStanza(QXmppStream *stream, const QDomElement &el
responseIq.setIdentities(identities);
}
- stream->sendPacket(responseIq);
+ server()->sendPacket(responseIq);
return true;
}
}
@@ -245,7 +282,7 @@ bool QXmppServerProxy65::handleStanza(QXmppStream *stream, const QDomElement &el
streamHosts.append(streamHost);
responseIq.setStreamHosts(streamHosts);
- stream->sendPacket(responseIq);
+ server()->sendPacket(responseIq);
}
else if (bsIq.type() == QXmppIq::Set)
{
@@ -268,43 +305,13 @@ bool QXmppServerProxy65::handleStanza(QXmppStream *stream, const QDomElement &el
qWarning() << "Not activating connection" << hash << "by" << bsIq.from();
responseIq.setType(QXmppIq::Error);
}
- stream->sendPacket(responseIq);
+ server()->sendPacket(responseIq);
}
return true;
}
return false;
}
-QString QXmppServerProxy65::jid() const
-{
- return d->jid;
-}
-
-void QXmppServerProxy65::setJid(const QString &jid)
-{
- d->jid = jid;
-}
-
-QString QXmppServerProxy65::statisticsFile() const
-{
- return d->statisticsFile;
-}
-
-void QXmppServerProxy65::setStatisticsFile(const QString &statisticsFile)
-{
- if (d->statistics)
- {
- delete d->statistics;
- d->statistics = 0;
- }
- d->statisticsFile = statisticsFile;
- if (!statisticsFile.isEmpty())
- {
- d->statistics = new QSettings(statisticsFile, QSettings::IniFormat, this);
- slotUpdateStatistics();
- }
-}
-
bool QXmppServerProxy65::start()
{
// determine jid
@@ -324,22 +331,69 @@ bool QXmppServerProxy65::start()
}
hostAddress = hostInfo.addresses().first();
}
- quint16 port = 7777;
// start listening
- if (!d->server->listen(hostAddress, port))
+ if (!d->server->listen(hostAddress, d->port))
return false;
d->host = hostAddress;
- d->port = port;
+
+ // start statistics update
+ d->statisticsTimer->start();
return true;
}
void QXmppServerProxy65::stop()
{
+ // refuse incoming connections
d->server->close();
+
+ // close socket pairs
foreach (QTcpSocketPair *pair, d->pairs)
delete pair;
d->pairs.clear();
+
+ // stop statistics update
+ d->statisticsTimer->stop();
+}
+
+QVariantMap QXmppServerProxy65::statistics() const
+{
+ // calculate stats
+ qint64 minimumSpeed = -1;
+ qint64 maximumSpeed = 0;
+ qint64 totalSize = 0;
+ qint64 totalElapsed = 0;
+ for (int i = d->recent.size() - 1; i >= 0; --i)
+ {
+ if (d->recent[i].elapsed > 0)
+ {
+ qint64 speed = (1000 * d->recent[i].size) / d->recent[i].elapsed;
+ if (speed > maximumSpeed)
+ maximumSpeed = speed;
+ if (minimumSpeed < 0 || speed < minimumSpeed)
+ minimumSpeed = speed;
+ totalSize += d->recent[i].size;
+ totalElapsed += d->recent[i].elapsed;
+ }
+ }
+ if (minimumSpeed < 0)
+ minimumSpeed = 0;
+ qint64 averageSpeed = totalElapsed > 0 ? (1000 * totalSize) / totalElapsed : 0;
+
+ // store stats
+ QVariantMap stats;
+ stats["total-bytes"] = d->totalBytes;
+ stats["total-transfers"] = d->totalTransfers;
+ stats["average-speed"] = averageSpeed;
+ stats["minimum-speed"] = minimumSpeed;
+ stats["maximum-speed"] = maximumSpeed;
+ return stats;
+}
+
+void QXmppServerProxy65::setStatistics(const QVariantMap &statistics)
+{
+ d->totalBytes = statistics.value("total-bytes").toULongLong();
+ d->totalTransfers = statistics.value("total-transfers").toULongLong();
}
void QXmppServerProxy65::slotSocketConnected(QTcpSocket *socket, const QString &hostName, quint16 port)
@@ -372,59 +426,28 @@ void QXmppServerProxy65::slotPairFinished()
d->recent.prepend(stats);
slotUpdateStatistics();
- // store total statistics
- if (d->statistics)
- {
- d->statistics->beginGroup("socks-proxy");
- d->statistics->setValue("total-bytes",
- d->statistics->value("total-bytes").toULongLong() + pair->transfer);
- d->statistics->setValue("total-transfers",
- d->statistics->value("total-transfers").toULongLong() + 1);
- d->statistics->endGroup();
- }
+ // update totals
+ d->totalBytes += pair->transfer;
+ d->totalTransfers++;
// remove socket pair
d->pairs.remove(pair->key);
pair->deleteLater();
}
+/// Prune obsolete statistics.
+///
+
void QXmppServerProxy65::slotUpdateStatistics()
{
- qint64 minimumSpeed = -1;
- qint64 maximumSpeed = 0;
- qint64 totalSize = 0;
- qint64 totalElapsed = 0;
QDateTime cutoff = QDateTime::currentDateTime().addDays(-1);
for (int i = d->recent.size() - 1; i >= 0; --i)
{
- // only keep 100 points, less than one day old
if (i >= 100 || d->recent[i].date < cutoff)
{
d->recent.removeAt(i);
- } else if (d->recent[i].elapsed > 0) {
- qint64 speed = (1000 * d->recent[i].size) / d->recent[i].elapsed;
- if (speed > maximumSpeed)
- maximumSpeed = speed;
- if (minimumSpeed < 0 || speed < minimumSpeed)
- minimumSpeed = speed;
- totalSize += d->recent[i].size;
- totalElapsed += d->recent[i].elapsed;
}
}
- if (minimumSpeed < 0)
- minimumSpeed = 0;
- qint64 averageSpeed = totalElapsed > 0 ? (1000 * totalSize) / totalElapsed : 0;
-
- // store statistics
- if (d->statistics)
- {
- d->statistics->beginGroup("socks-proxy");
- d->statistics->setValue("version", qApp->applicationVersion());
- d->statistics->setValue("average-speed", averageSpeed);
- d->statistics->setValue("minimum-speed", minimumSpeed);
- d->statistics->setValue("maximum-speed", maximumSpeed);
- d->statistics->endGroup();
- }
}
// PLUGIN
diff --git a/src/server/mod_proxy65.h b/src/server/mod_proxy65.h
index e9557383..137907ce 100644
--- a/src/server/mod_proxy65.h
+++ b/src/server/mod_proxy65.h
@@ -66,7 +66,7 @@ class QXmppServerProxy65 : public QXmppServerExtension
Q_OBJECT
Q_CLASSINFO("ExtensionName", "proxy65");
Q_PROPERTY(QString jid READ jid WRITE setJid);
- Q_PROPERTY(QString statisticsFile READ statisticsFile WRITE setStatisticsFile);
+ Q_PROPERTY(quint16 port READ port WRITE setPort);
public:
QXmppServerProxy65();
@@ -75,13 +75,17 @@ public:
QString jid() const;
void setJid(const QString &jid);
- QString statisticsFile() const;
- void setStatisticsFile(const QString &statisticsFile);
+ quint16 port() const;
+ void setPort(quint16 port);
+ /// \cond
QStringList discoveryItems() const;
bool handleStanza(QXmppStream *stream, const QDomElement &element);
bool start();
void stop();
+ QVariantMap statistics() const;
+ void setStatistics(const QVariantMap &statistics);
+ /// \endcond
private slots:
void slotPairFinished();
diff --git a/src/server/mod_version.cpp b/src/server/mod_version.cpp
index 71ed6e1e..eeacbd4d 100644
--- a/src/server/mod_version.cpp
+++ b/src/server/mod_version.cpp
@@ -56,7 +56,7 @@ bool QXmppServerVersion::handleStanza(QXmppStream *stream, const QDomElement &el
responseIq.setTo(versionIq.from());
responseIq.setName(qApp->applicationName());
responseIq.setVersion(qApp->applicationVersion());
- stream->sendPacket(responseIq);
+ server()->sendPacket(responseIq);
}
return true;
}