diff options
| author | Jeremy Lainé <jeremy.laine@m4x.org> | 2010-08-28 22:59:55 +0000 |
|---|---|---|
| committer | Jeremy Lainé <jeremy.laine@m4x.org> | 2010-08-28 22:59:55 +0000 |
| commit | 13b245f3bcc709b2a974b764bb209e1ea87768af (patch) | |
| tree | b3bbde11e5fd231bf059f09f308dddf776426a47 /src | |
| parent | 8b58bfd72ad5d8e28e325c6cea61db270b9e626b (diff) | |
| download | qxmpp-13b245f3bcc709b2a974b764bb209e1ea87768af.tar.gz | |
update QXmppServer extensions API
Diffstat (limited to 'src')
| -rw-r--r-- | src/QXmppIncomingClient.cpp | 25 | ||||
| -rw-r--r-- | src/QXmppServer.cpp | 42 | ||||
| -rw-r--r-- | src/QXmppServer.h | 2 | ||||
| -rw-r--r-- | src/QXmppServerExtension.cpp | 16 | ||||
| -rw-r--r-- | src/QXmppServerExtension.h | 4 | ||||
| -rw-r--r-- | src/server/mod_disco.cpp | 4 | ||||
| -rw-r--r-- | src/server/mod_disco.h | 16 | ||||
| -rw-r--r-- | src/server/mod_ping.cpp | 2 | ||||
| -rw-r--r-- | src/server/mod_proxy65.cpp | 183 | ||||
| -rw-r--r-- | src/server/mod_proxy65.h | 10 | ||||
| -rw-r--r-- | src/server/mod_version.cpp | 2 |
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; } |
