aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2010-02-25 16:16:23 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2010-02-25 16:16:23 +0000
commitfadaa31cbe9ba78cc0abc8538f97ff57b77c88ce (patch)
treeee3c234cb8dbab7360792ccee8b37a3c4d73d806 /source
parenta0de7d05622d74decbae5b26f3423f53aad45b85 (diff)
downloadqxmpp-fadaa31cbe9ba78cc0abc8538f97ff57b77c88ce.tar.gz
improve termination of file transfers
Diffstat (limited to 'source')
-rw-r--r--source/QXmppSocks.cpp13
-rw-r--r--source/QXmppSocks.h2
-rw-r--r--source/QXmppTransferManager.cpp94
-rw-r--r--source/QXmppTransferManager.h17
4 files changed, 93 insertions, 33 deletions
diff --git a/source/QXmppSocks.cpp b/source/QXmppSocks.cpp
index 6b8bfa5d..ab386114 100644
--- a/source/QXmppSocks.cpp
+++ b/source/QXmppSocks.cpp
@@ -114,6 +114,11 @@ QXmppSocksClient::QXmppSocksClient(const QHostAddress &proxyAddress, quint16 pro
m_socket = new QTcpSocket(this);
}
+void QXmppSocksClient::close()
+{
+ m_socket->close();
+}
+
void QXmppSocksClient::connectToHost(const QString &hostName, quint16 hostPort)
{
m_hostName = hostName;
@@ -203,6 +208,13 @@ QXmppSocksServer::QXmppSocksServer(QObject *parent)
connect(m_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
}
+void QXmppSocksServer::close()
+{
+ m_server->close();
+ if (m_socket)
+ m_socket->close();
+}
+
bool QXmppSocksServer::listen(const QHostAddress &address, quint16 port)
{
return m_server->listen(address, port);
@@ -287,6 +299,7 @@ void QXmppSocksServer::slotNewConnection()
m_socket->write(buffer);
// connect signals
+ m_server->close();
connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)), this, SIGNAL(bytesWritten(qint64)));
}
diff --git a/source/QXmppSocks.h b/source/QXmppSocks.h
index f9a7e71c..ab2c84ec 100644
--- a/source/QXmppSocks.h
+++ b/source/QXmppSocks.h
@@ -36,6 +36,7 @@ class QXmppSocksClient : public QObject
public:
QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent=0);
+ void close();
void connectToHost(const QString &hostName, quint16 hostPort);
QString errorString() const;
QByteArray readAll();
@@ -59,6 +60,7 @@ class QXmppSocksServer : public QObject
public:
QXmppSocksServer(QObject *parent=0);
+ void close();
bool listen(const QHostAddress &address, quint16 port = 0);
QHostAddress serverAddress() const;
quint16 serverPort() const;
diff --git a/source/QXmppTransferManager.cpp b/source/QXmppTransferManager.cpp
index ad9ae231..1b0274df 100644
--- a/source/QXmppTransferManager.cpp
+++ b/source/QXmppTransferManager.cpp
@@ -44,9 +44,10 @@ static QString streamHash(const QString &sid, const QString &initiatorJid, const
return hash.result().toHex();
}
-QXmppTransferJob::QXmppTransferJob(const QString &jid, QXmppTransferManager *manager)
- : QObject(manager),
+QXmppTransferJob::QXmppTransferJob(const QString &jid, QXmppTransferJob::Direction direction, QObject *parent)
+ : QObject(parent),
m_blockSize(16384),
+ m_direction(direction),
m_done(0),
m_error(NoError),
m_iodevice(0),
@@ -66,6 +67,11 @@ void QXmppTransferJob::accept(QIODevice *iodevice)
m_iodevice = iodevice;
}
+QXmppTransferJob::Direction QXmppTransferJob::direction() const
+{
+ return m_direction;
+}
+
QXmppTransferJob::Error QXmppTransferJob::error() const
{
return m_error;
@@ -76,6 +82,16 @@ QString QXmppTransferJob::jid() const
return m_jid;
}
+QString QXmppTransferJob::localFilePath() const
+{
+ return m_localFilePath;
+}
+
+void QXmppTransferJob::setLocalFilePath(const QString &path)
+{
+ m_localFilePath = path;
+}
+
QDateTime QXmppTransferJob::fileDate() const
{
return m_fileDate;
@@ -117,14 +133,25 @@ void QXmppTransferJob::setState(QXmppTransferJob::State state)
void QXmppTransferJob::terminate(QXmppTransferJob::Error cause)
{
- // close IO device
- m_iodevice->close();
+ if (m_state == FinishedState)
+ return;
// change state
- setState(FinishedState);
-
- // emit signal
m_error = cause;
+ m_state = FinishedState;
+
+ // close IO device
+ if (m_iodevice)
+ m_iodevice->close();
+
+ // close sockets
+ if (m_socksClient)
+ m_socksClient->close();
+ if (m_socksServer)
+ m_socksServer->close();
+
+ // emit signals
+ emit stateChanged(m_state);
if (cause == NoError)
emit finished();
else
@@ -155,10 +182,7 @@ void QXmppTransferManager::byteStreamResponseReceived(const QXmppIq &iq)
return;
if (iq.getType() == QXmppIq::Error)
- {
- // FIXME : close sockets?
job->terminate(QXmppTransferJob::ProtocolError);
- }
}
/// Handle a bytestream result, i.e. after the remote party has connected to our stream host.
@@ -440,13 +464,17 @@ void QXmppTransferManager::iqReceived(const QXmppIq &iq)
ibbResponseReceived(iq);
else if (job->method() == QXmppTransferJob::SocksMethod)
byteStreamResponseReceived(iq);
+ else if (iq.getType() == QXmppIq::Error) {
+ // remote user cancelled stream initiation
+ job->terminate(QXmppTransferJob::ProtocolError);
+ }
}
QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QString &fileName)
{
// create job
- QXmppTransferJob *job = new QXmppTransferJob(jid, this);
+ QXmppTransferJob *job = new QXmppTransferJob(jid, QXmppTransferJob::OutgoingDirection, this);
// open file
QFile *fileIo = new QFile(fileName, job);
@@ -454,7 +482,6 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QStri
QFileInfo info(*fileIo);
job->m_iodevice = fileIo;
- job->m_methods = m_supportedMethods;
job->m_sid = generateStanzaHash();
job->m_fileDate = info.lastModified();
job->m_fileName = info.fileName();
@@ -489,7 +516,7 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QStri
x.appendChild(field);
// add supported stream methods
- if (job->m_methods & QXmppTransferJob::InBandMethod)
+ if (m_supportedMethods & QXmppTransferJob::InBandMethod)
{
QXmppElement option;
option.setTagName("option");
@@ -500,7 +527,7 @@ QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QStri
value.setValue(ns_ibb);
option.appendChild(value);
}
- if (job->m_methods & QXmppTransferJob::SocksMethod)
+ if (m_supportedMethods & QXmppTransferJob::SocksMethod)
{
QXmppElement option;
option.setTagName("option");
@@ -530,7 +557,7 @@ void QXmppTransferManager::socksClientDataReceived()
{
QXmppSocksClient *socks = qobject_cast<QXmppSocksClient*>(sender());
QXmppTransferJob *job = getJobBySocksClient(socks);
- if (!job)
+ if (!job || job->state() != QXmppTransferJob::TransferState)
return;
QByteArray data = job->m_socksClient->readAll();
@@ -543,7 +570,7 @@ void QXmppTransferManager::socksClientDisconnected()
{
QXmppSocksClient *socks = qobject_cast<QXmppSocksClient*>(sender());
QXmppTransferJob *job = getJobBySocksClient(socks);
- if (!job)
+ if (!job || job->state() == QXmppTransferJob::FinishedState)
return;
// terminate the transfer
@@ -557,8 +584,7 @@ void QXmppTransferManager::socksServerDataSent()
{
QXmppSocksServer *socksServer = qobject_cast<QXmppSocksServer*>(sender());
QXmppTransferJob *job = getJobBySocksServer(socksServer);
- if (!job ||
- job->state() != QXmppTransferJob::TransferState)
+ if (!job || job->state() != QXmppTransferJob::TransferState)
return;
// send next data block
@@ -567,7 +593,13 @@ void QXmppTransferManager::socksServerDataSent()
void QXmppTransferManager::socksServerDisconnected()
{
- qWarning("Socks server disconnected");
+ QXmppSocksServer *socksServer = qobject_cast<QXmppSocksServer*>(sender());
+ QXmppTransferJob *job = getJobBySocksServer(socksServer);
+ if (!job || job->state() == QXmppTransferJob::FinishedState)
+ return;
+
+ // terminate transfer
+ job->terminate(QXmppTransferJob::ProtocolError);
}
void QXmppTransferManager::socksServerSendData(QXmppTransferJob *job)
@@ -609,10 +641,10 @@ void QXmppTransferManager::streamInitiationResultReceived(const QXmppStreamIniti
if (field.attribute("var") == "stream-method")
{
if ((field.firstChildElement("value").value() == ns_ibb) &&
- (job->m_methods & QXmppTransferJob::InBandMethod))
+ (m_supportedMethods & QXmppTransferJob::InBandMethod))
job->m_method = QXmppTransferJob::InBandMethod;
else if ((field.firstChildElement("value").value() == ns_bytestreams) &&
- (job->m_methods & QXmppTransferJob::SocksMethod))
+ (m_supportedMethods & QXmppTransferJob::SocksMethod))
job->m_method = QXmppTransferJob::SocksMethod;
}
field = field.nextSiblingElement("field");
@@ -636,7 +668,6 @@ void QXmppTransferManager::streamInitiationResultReceived(const QXmppStreamIniti
streamIq.setTo(job->m_jid);
streamIq.setSid(job->m_sid);
- quint16 port = 40123;
const QString ownJid = m_client->getConfiguration().getJid();
QList<QXmppByteStreamIq::StreamHost> streamHosts;
@@ -657,7 +688,8 @@ void QXmppTransferManager::streamInitiationResultReceived(const QXmppStreamIniti
entry.netmask() == QHostAddress::Broadcast)
continue;
- if (!job->m_socksServer->listen(entry.ip(), port))
+ // we let the server pick a port
+ if (!job->m_socksServer->listen(entry.ip()))
{
qWarning() << "QXmppSocksServer could not listen on address" << entry.ip();
continue;
@@ -705,8 +737,8 @@ void QXmppTransferManager::streamInitiationSetReceived(const QXmppStreamInitiati
}
// check the stream type
- QXmppTransferJob *job = new QXmppTransferJob(iq.getFrom(), this);
- job->m_methods = QXmppTransferJob::NoMethod;
+ QXmppTransferJob *job = new QXmppTransferJob(iq.getFrom(), QXmppTransferJob::IncomingDirection, this);
+ int offeredMethods = QXmppTransferJob::NoMethod;
job->m_sid = iq.getSiId();
job->m_mimeType = iq.getMimeType();
foreach (const QXmppElement &item, iq.getSiItems())
@@ -722,9 +754,9 @@ void QXmppTransferManager::streamInitiationSetReceived(const QXmppStreamInitiati
while (!option.isNull())
{
if (option.firstChildElement("value").value() == ns_ibb)
- job->m_methods = job->m_methods | QXmppTransferJob::InBandMethod;
+ offeredMethods = offeredMethods | QXmppTransferJob::InBandMethod;
else if (option.firstChildElement("value").value() == ns_bytestreams)
- job->m_methods = job->m_methods | QXmppTransferJob::SocksMethod;
+ offeredMethods = offeredMethods | QXmppTransferJob::SocksMethod;
option = option.nextSiblingElement("option");
}
}
@@ -740,11 +772,13 @@ void QXmppTransferManager::streamInitiationSetReceived(const QXmppStreamInitiati
}
}
- if (job->m_methods & QXmppTransferJob::SocksMethod)
+ // select a method supported by both parties
+ int sharedMethods = (offeredMethods & m_supportedMethods);
+ if (sharedMethods & QXmppTransferJob::SocksMethod)
job->m_method = QXmppTransferJob::SocksMethod;
- else if (job->m_methods & QXmppTransferJob::InBandMethod)
+ else if (sharedMethods & QXmppTransferJob::InBandMethod)
job->m_method = QXmppTransferJob::InBandMethod;
- if (!job->m_methods)
+ else
{
// FIXME : we should add:
// <no-valid-streams xmlns='http://jabber.org/protocol/si'/>
diff --git a/source/QXmppTransferManager.h b/source/QXmppTransferManager.h
index 927d5c8e..ca743f51 100644
--- a/source/QXmppTransferManager.h
+++ b/source/QXmppTransferManager.h
@@ -37,13 +37,18 @@ class QXmppIbbOpenIq;
class QXmppSocksClient;
class QXmppSocksServer;
class QXmppStreamInitiationIq;
-class QXmppTransferManager;
class QXmppTransferJob : public QObject
{
Q_OBJECT
public:
+ enum Direction
+ {
+ IncomingDirection,
+ OutgoingDirection,
+ };
+
enum Error
{
NoError = 0,
@@ -68,7 +73,10 @@ public:
void accept(QIODevice *output);
+ QXmppTransferJob::Direction direction() const;
QXmppTransferJob::Error error() const;
+ QString localFilePath() const;
+ void setLocalFilePath(const QString &path);
QString jid() const;
QXmppTransferJob::Method method() const;
QXmppTransferJob::State state() const;
@@ -86,22 +94,25 @@ signals:
void stateChanged(QXmppTransferJob::State state);
private:
- QXmppTransferJob(const QString &jid, QXmppTransferManager *manager);
+ QXmppTransferJob(const QString &jid, QXmppTransferJob::Direction direction, QObject *parent);
void setState(QXmppTransferJob::State state);
void terminate(QXmppTransferJob::Error error);
int m_blockSize;
+ QXmppTransferJob::Direction m_direction;
int m_done;
QXmppTransferJob::Error m_error;
QIODevice *m_iodevice;
QString m_jid;
QString m_sid;
Method m_method;
- int m_methods;
QString m_mimeType;
QString m_requestId;
State m_state;
+ // local path to file
+ QString m_localFilePath;
+
// file meta-data
QDateTime m_fileDate;
QString m_fileHash;