summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Braun2010-07-17 16:43:08 +0200
committerSebastien Braun2010-07-17 16:58:25 +0200
commit2ad0ca683dfade47078a2aafce9921ca238a9436 (patch)
tree1a0d8f8ef5c4b52c9016077ba0ea7b0f2609143e
parentMake McastSender work with a pre-opened socket (diff)
downloadpvs-2ad0ca683dfade47078a2aafce9921ca238a9436.tar.gz
pvs-2ad0ca683dfade47078a2aafce9921ca238a9436.tar.xz
pvs-2ad0ca683dfade47078a2aafce9921ca238a9436.zip
Implement UI and pvsDaemon components for outgoing Multicast Transfer
-rw-r--r--CMakeLists.txt7
-rw-r--r--src/gui/clientFileSendDialog.cpp201
-rw-r--r--src/gui/clientFileSendDialog.h21
-rw-r--r--src/gui/ui/clientFileSendDialog.ui15
-rw-r--r--src/gui/ui/clientNicklistDialog.ui7
-rw-r--r--src/net/mcast/McastConfiguration.cpp39
-rw-r--r--src/net/mcast/McastConfiguration.h5
-rw-r--r--src/net/mcast/McastPGMSocket.cpp12
-rw-r--r--src/net/mcast/McastSender.cpp2
-rw-r--r--src/net/pvsOutgoingMulticastTransfer.cpp209
-rw-r--r--src/net/pvsOutgoingMulticastTransfer.h92
-rw-r--r--src/net/pvsServerConnection.h7
-rw-r--r--src/pvs.cpp60
-rw-r--r--src/pvs.h17
14 files changed, 661 insertions, 33 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8eb1961..93e281e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,6 +99,7 @@ SET( PVS_SRCS
src/net/pvsDiscoveredServer.cpp
src/util/TextFile.cpp
src/util/serviceDiscoveryUtil.cpp
+ src/net/pvsOutgoingMulticastTransfer.cpp
)
# pvsgui
@@ -192,6 +193,7 @@ SET( PVS_MOC_HDRS
src/net/pvsServerConnection.h
src/net/pvsServiceDiscovery.h
src/net/pvsDiscoveredServer.h
+ src/net/pvsOutgoingMulticastTransfer.h
)
SET( PVSGUI_MOC_HDRS
@@ -313,27 +315,24 @@ TARGET_LINK_LIBRARIES( pvsmgr
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
- pgm
)
TARGET_LINK_LIBRARIES( pvsmgrtouch
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
- pgm
)
TARGET_LINK_LIBRARIES( pvs
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
- pgm
+ pvsmcast
)
TARGET_LINK_LIBRARIES( pvsgui
${QT_LIBRARIES}
${VNC_LIBRARIES}
- pgm
)
SET_PROPERTY(TARGET pvsmgrtouch PROPERTY COMPILE_DEFINITIONS MAINWINDOW_USE_TOUCHGUI)
diff --git a/src/gui/clientFileSendDialog.cpp b/src/gui/clientFileSendDialog.cpp
index ccb44b3..25e3eaa 100644
--- a/src/gui/clientFileSendDialog.cpp
+++ b/src/gui/clientFileSendDialog.cpp
@@ -22,6 +22,10 @@ ClientFileSendDialog::ClientFileSendDialog(QWidget *parent) :
{
setupUi(this);
+ _transferID = 0;
+ _error = false;
+ _isMulticast = false;
+
_file = NULL;
_socket = NULL;
_clientNicklistDialog = new ClientNicklistDialog(this);
@@ -60,7 +64,15 @@ void ClientFileSendDialog::open()
reject();
return;
}
- open(_clientNicklistDialog->getNick());
+
+ if (_clientNicklistDialog->isSendToAll())
+ {
+ sendToAll();
+ }
+ else
+ {
+ open(_clientNicklistDialog->getNick());
+ }
}
void ClientFileSendDialog::open(QString nick)
@@ -75,6 +87,70 @@ void ClientFileSendDialog::open(QString nick)
open(nick, filename);
}
+void ClientFileSendDialog::sendToAll()
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("Send File"), QDir::homePath(), "");
+ if (filename == "")
+ {
+ reject();
+ return;
+ }
+ sendToAll(filename);
+}
+
+void ClientFileSendDialog::sendToAll(QString filename)
+{
+ _isMulticast = true;
+
+ connect(_ifaceDBus, SIGNAL(outgoingMulticastTransferStarted(qulonglong)), SLOT(multicastTransferStarted(qulonglong)));
+ connect(_ifaceDBus, SIGNAL(outgoingMulticastTransferProgress(qulonglong,qulonglong,qulonglong)), SLOT(multicastTransferProgress(qulonglong, qulonglong, qulonglong)));
+ connect(_ifaceDBus, SIGNAL(outgoingMulticastTransferFinished(qulonglong)), SLOT(multicastTransferFinished(qulonglong)));
+ connect(_ifaceDBus, SIGNAL(outgoingMulticastTransferFailed(qulonglong, QString const&)), SLOT(multicastTransferFailed(qulonglong, QString const&)));
+
+ filenameLabel->setText(filename);
+ progressBar->setRange(0, 0);
+ labelNick->setText(tr("all"));
+ labelStatus->setText(tr("Waiting to start"));
+
+ QString errorMessage("Backend error");
+
+ // We need to jump through a lot of hoops because this call is prone to time out, and
+ // QtDBus does not support specifying timeouts in generated interfaces.
+ QDBusMessage call = QDBusMessage::createMethodCall("org.openslx.pvs", "/", "org.openslx.pvs", "createMulticastTransfer");
+ call << filename;
+
+ QDBusMessage reply = _ifaceDBus->connection().call(call, QDBus::Block, 5000);
+ if (reply.type() == QDBusMessage::ErrorMessage)
+ {
+ QMessageBox::critical(this, tr("File Send error"), tr("Error communicating with backend: %1: %2").arg(reply.errorName()).arg(reply.errorMessage()));
+ reject();
+ return;
+ }
+ else if (reply.type() == QDBusMessage::InvalidMessage)
+ {
+ QMessageBox::critical(this, tr("File Send error"), tr("Something went wrong while communicating with backend, but I don't know what."));
+ reject();
+ return;
+ }
+ else if (reply.type() == QDBusMessage::ReplyMessage)
+ {
+ QList<QVariant> args = reply.arguments();
+ bool created = args.at(0).toBool();
+ _transferID = args.at(1).toULongLong();
+ QString errorMessage = args.at(2).toString();
+ if (!created)
+ {
+ QMessageBox::critical(this, tr("File Send error"), tr("Could not create a multicast transfer: %1").arg(errorMessage));
+ reject();
+ return;
+ }
+ }
+
+ connect(cancelButton, SIGNAL(clicked()), SLOT(canceled()));
+
+ show();
+}
+
void ClientFileSendDialog::open(QString nick, QString filename)
{
// open file
@@ -129,6 +205,8 @@ void ClientFileSendDialog::receiveAck()
QString ack = QString::fromUtf8(_socket->readLine());
if (ack != "ok\n")
{
+ _error = true;
+ _reason = tr("Receiver declined");
qDebug("[%s] Received nack!", metaObject()->className());
close();
return;
@@ -160,27 +238,30 @@ void ClientFileSendDialog::sendFile()
void ClientFileSendDialog::close()
{
- if (_file && _file->isOpen())
- {
- _file->close();
- qDebug("[%s] File closed.", metaObject()->className());
- }
-
- if (_socket && _socket->isOpen())
+ if (!_isMulticast)
{
- disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck()));
- disconnect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile()));
- disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close()));
- disconnect(_socket, SIGNAL(connected()), this, SLOT(sendHeader()));
- disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SLOT(error(QAbstractSocket::SocketError)));
- _socket->disconnectFromHost();
- qDebug("[%s] Connection closed.", metaObject()->className());
+ if (_file && _file->isOpen())
+ {
+ _file->close();
+ qDebug("[%s] File closed.", metaObject()->className());
+ }
+
+ if (_socket && _socket->isOpen())
+ {
+ disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck()));
+ disconnect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile()));
+ disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close()));
+ disconnect(_socket, SIGNAL(connected()), this, SLOT(sendHeader()));
+ disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(error(QAbstractSocket::SocketError)));
+ _socket->disconnectFromHost();
+ qDebug("[%s] Connection closed.", metaObject()->className());
+ }
}
- disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
+ disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(canceled()));
- if (_bytesToWrite == 0)
+ if (!_error)
{
accept();
QMessageBox::information(0, tr("PVS - File Transfer"),
@@ -190,12 +271,26 @@ void ClientFileSendDialog::close()
{
reject();
QMessageBox::warning(0, tr("PVS - File Transfer"),
- tr("File Transfer canceled!"));
+ tr("File Transfer canceled: %1").arg(_reason));
}
}
+void ClientFileSendDialog::canceled()
+{
+ if(_isMulticast)
+ {
+ _ifaceDBus->cancelOutgoingMulticastTransfer(_transferID);
+ }
+
+ _error = true;
+ _reason = tr("You clicked 'Cancel'");
+ close();
+}
+
void ClientFileSendDialog::error(QAbstractSocket::SocketError error)
{
+ _error = true;
+ _reason = tr("Socket Error");
qDebug("[%s] Socket error: %i", metaObject()->className(), error);
close();
}
@@ -212,6 +307,55 @@ QString ClientFileSendDialog::formatSize(qint64 size)
return QString("%1B").arg((qreal)size, 0, 'f',1);
}
+void ClientFileSendDialog::multicastTransferStarted(qulonglong transferID)
+{
+ qDebug() << "multicastTransferStarted(" << transferID << ")";
+ if (transferID != _transferID)
+ {
+ return;
+ }
+ labelStatus->setText("Started");
+}
+
+void ClientFileSendDialog::multicastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of)
+{
+ qDebug() << "multicastTransferProgress(" << transferID << bytes << of << ")";
+ if (transferID != _transferID)
+ {
+ return;
+ }
+
+ if(bytes < of)
+ {
+ labelStatus->setText("Transferring");
+ progressBar->setRange(0, of);
+ progressBar->setValue(bytes);
+ }
+ else
+ {
+ labelStatus->setText("Waiting to finish");
+ progressBar->setRange(0, 0);
+ }
+
+ labelA->setText(formatSize(bytes));
+ labelB->setText(formatSize(of));
+}
+
+void ClientFileSendDialog::multicastTransferFinished(quint64 transferID)
+{
+ qDebug() << "multicastTransferFinished(" << transferID << ")";
+ qDebug("[%s] MulticastTransfer finished", metaObject()->className());
+ close();
+}
+
+void ClientFileSendDialog::multicastTransferFailed(quint64 transferID, QString const& reason)
+{
+ qDebug() << "multicastTransferFailed(" << transferID << reason << ")";
+ _error = true;
+ _reason = reason;
+ close();
+}
+
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -235,6 +379,25 @@ ClientNicklistDialog::ClientNicklistDialog(QWidget *parent) :
listWidget->addItems(nicknames);
listWidget->setCurrentRow(0);
+
+ connect(sendToAllCheckBox, SIGNAL(stateChanged(int)), SLOT(sendToAllStateChanged(int)));
+
+ sendToAllCheckBox->setCheckState(Qt::Unchecked);
+ _isSendToAll = false;
+}
+
+void ClientNicklistDialog::sendToAllStateChanged(int state)
+{
+ if (state)
+ {
+ listWidget->setEnabled(false);
+ _isSendToAll = true;
+ }
+ else
+ {
+ listWidget->setEnabled(true);
+ _isSendToAll = false;
+ }
}
ClientNicklistDialog::~ClientNicklistDialog()
diff --git a/src/gui/clientFileSendDialog.h b/src/gui/clientFileSendDialog.h
index d8afc3a..7abdcc7 100644
--- a/src/gui/clientFileSendDialog.h
+++ b/src/gui/clientFileSendDialog.h
@@ -30,9 +30,17 @@ public:
~ClientNicklistDialog();
QString getNick();
+ bool isSendToAll() const
+ {
+ return _isSendToAll;
+ }
+
+private Q_SLOTS:
+ void sendToAllStateChanged(int state);
private:
OrgOpenslxPvsInterface *_ifaceDBus;
+ bool _isSendToAll;
};
@@ -51,14 +59,22 @@ public:
void open();
void open(QString nick);
void open(QString nick, QString filename);
+ void sendToAll();
+ void sendToAll(QString filename);
private Q_SLOTS:
void sendHeader();
void receiveAck();
void sendFile();
void close();
+ void canceled();
void error(QAbstractSocket::SocketError error);
+ void multicastTransferStarted(qulonglong transferID);
+ void multicastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of);
+ void multicastTransferFinished(qulonglong transferID);
+ void multicastTransferFailed(qulonglong transferID, QString const& reason);
+
private:
QString formatSize(qint64 size);
@@ -71,6 +87,11 @@ private:
OrgOpenslxPvsInterface *_ifaceDBus;
QString _nickname;
+ quint64 _transferID;
+ bool _error;
+ QString _reason;
+ bool _isMulticast;
+
};
#endif /* CLIENTFILESENDDIALOG_H_ */
diff --git a/src/gui/ui/clientFileSendDialog.ui b/src/gui/ui/clientFileSendDialog.ui
index d2d9c75..85462ba 100644
--- a/src/gui/ui/clientFileSendDialog.ui
+++ b/src/gui/ui/clientFileSendDialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>186</width>
- <height>108</height>
+ <width>528</width>
+ <height>144</height>
</rect>
</property>
<property name="windowTitle">
@@ -33,7 +33,7 @@
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
@@ -61,10 +61,17 @@
</property>
</spacer>
</item>
+ <item>
+ <widget class="QLabel" name="labelStatus">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="labelA">
<property name="text">
diff --git a/src/gui/ui/clientNicklistDialog.ui b/src/gui/ui/clientNicklistDialog.ui
index afd84f1..3679b55 100644
--- a/src/gui/ui/clientNicklistDialog.ui
+++ b/src/gui/ui/clientNicklistDialog.ui
@@ -29,6 +29,13 @@
<widget class="QListWidget" name="listWidget"/>
</item>
<item>
+ <widget class="QCheckBox" name="sendToAllCheckBox">
+ <property name="text">
+ <string>Send to &amp;all</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
diff --git a/src/net/mcast/McastConfiguration.cpp b/src/net/mcast/McastConfiguration.cpp
index 1a1c0a8..489eb3f 100644
--- a/src/net/mcast/McastConfiguration.cpp
+++ b/src/net/mcast/McastConfiguration.cpp
@@ -5,5 +5,44 @@
* Author: brs
*/
+#include <QSettings>
+
#include "McastConfiguration.h"
+void McastConfiguration::loadFrom(QSettings* _settings, char const* group)
+{
+ if (group)
+ _settings->beginGroup(group);
+
+ _multicastAddress = _settings->value("groupAddress", DEFAULT_MULTICAST_ADDRESS).toString();
+ _multicastInterface = _settings->value("interface", DEFAULT_MULTICAST_INTERFACE).toString();
+ _multicastMTU = _settings->value("mtu", DEFAULT_MULTICAST_MTU).value<quint16>();
+ _multicastRate = _settings->value("rate", DEFAULT_MULTICAST_RATE).value<quint32>();
+ _multicastUseUDP = _settings->value("use-udp", DEFAULT_MULTICAST_USEUDP).toBool();
+ _multicastWinSize = _settings->value("winsize", DEFAULT_MULTICAST_WSIZ).value<quint16>();
+ _multicastUDPPortBase = _settings->value("portbase", DEFAULT_MULTICAST_UDPPORT).value<quint16>();
+ _multicastDPort = _settings->value("dport", DEFAULT_MULTICAST_DPORT).value<quint16>();
+ _multicastSPort = _settings->value("sport", DEFAULT_MULTICAST_SPORT).value<quint16>();
+
+ if (group)
+ _settings->endGroup();
+}
+
+void McastConfiguration::writeTo(QSettings* _settings, char const* group) const
+{
+ if (group)
+ _settings->beginGroup(group);
+
+ _settings->setValue("groupAddress", _multicastAddress);
+ _settings->setValue("interface", _multicastInterface);
+ _settings->setValue("mtu", _multicastMTU);
+ _settings->setValue("rate", _multicastRate);
+ _settings->setValue("use-udp", _multicastUseUDP);
+ _settings->setValue("winsize", _multicastWinSize);
+ _settings->setValue("portbase", _multicastUDPPortBase);
+ _settings->setValue("dport", _multicastDPort);
+ _settings->setValue("sport", _multicastSPort);
+
+ if (group)
+ _settings->endGroup();
+}
diff --git a/src/net/mcast/McastConfiguration.h b/src/net/mcast/McastConfiguration.h
index 2e64678..b010f60 100644
--- a/src/net/mcast/McastConfiguration.h
+++ b/src/net/mcast/McastConfiguration.h
@@ -23,6 +23,8 @@
#include "McastConstants.h"
+class QSettings;
+
class McastConfiguration: public QObject
{
Q_OBJECT
@@ -164,6 +166,9 @@ public:
emit changed();
}
+ void loadFrom(QSettings* settings, char const* group = 0);
+ void writeTo(QSettings* settings, char const* group = 0) const;
+
signals:
void changed();
diff --git a/src/net/mcast/McastPGMSocket.cpp b/src/net/mcast/McastPGMSocket.cpp
index 105bea9..7952f00 100644
--- a/src/net/mcast/McastPGMSocket.cpp
+++ b/src/net/mcast/McastPGMSocket.cpp
@@ -567,6 +567,11 @@ void McastPGMSocket::sendPacket(QByteArray const& bytes)
void McastPGMSocket::finish()
{
+ if (_finished)
+ {
+ return;
+ }
+
qDebug() << "finish()";
Q_FOREACH(QSocketNotifier* notif, _priv->_notifs)
@@ -582,8 +587,11 @@ void McastPGMSocket::finish()
_priv->send_notif = 0;
}
- pgm_close(_priv->socket, 1);
- _priv->socket = 0;
+ if (_priv->socket)
+ {
+ pgm_close(_priv->socket, 1);
+ _priv->socket = 0;
+ }
_finished = true;
diff --git a/src/net/mcast/McastSender.cpp b/src/net/mcast/McastSender.cpp
index 322b751..e25ec86 100644
--- a/src/net/mcast/McastSender.cpp
+++ b/src/net/mcast/McastSender.cpp
@@ -111,6 +111,6 @@ void McastSender::close()
void McastSender::socketFinished()
{
- delete _socket;
+ _socket->deleteLater();
emit finished();
}
diff --git a/src/net/pvsOutgoingMulticastTransfer.cpp b/src/net/pvsOutgoingMulticastTransfer.cpp
new file mode 100644
index 0000000..2f24d49
--- /dev/null
+++ b/src/net/pvsOutgoingMulticastTransfer.cpp
@@ -0,0 +1,209 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsOutgoingMulticastTransfer.cpp
+# - wrap McastSender functionality in PVS daemon
+# -----------------------------------------------------------------------------
+*/
+
+#include "pvsOutgoingMulticastTransfer.h"
+
+#include <QDataStream>
+#include <QFile>
+#include <QFileInfo>
+#include <QHostInfo>
+#include <QSettings>
+#include <QTimer>
+
+#include <src/net/pvsMsg.h>
+#include <src/net/mcast/McastConfiguration.h>
+#include <src/net/mcast/McastPGMSocket.h>
+#include <src/net/mcast/McastSender.h>
+#include <src/util/consoleLogger.h>
+
+PVSOutgoingMulticastTransfer::PVSOutgoingMulticastTransfer(QString senderName, quint64 id, QString filename, QObject* parent) :
+ QObject(parent),
+ _file(0),
+ _progress(0),
+ _config(0),
+ _socket(0),
+ _progressTimer(0),
+ _prepareTimer(0),
+ _senderName(senderName),
+ _id(id),
+ _error(false)
+{
+ QFileInfo finfo(filename);
+ if(!finfo.exists())
+ {
+ error("File does not exist");
+ }
+
+ if(!finfo.isReadable())
+ {
+ error("File is not readable");
+ }
+
+ _file = new QFile(filename, this);
+ _length = _file->size();
+}
+
+PVSOutgoingMulticastTransfer::~PVSOutgoingMulticastTransfer()
+{
+ if(_file)
+ delete _file;
+ if(_config)
+ delete _config;
+}
+
+void PVSOutgoingMulticastTransfer::prepare()
+{
+ if (_socket && !_socketInacceptable)
+ {
+ _prepareTimer->stop();
+ delete _prepareTimer;
+ _prepareTimer = 0;
+
+ QTimer::singleShot(0, this, SLOT(doStart()));
+ return;
+ }
+ else if (_socket)
+ {
+ delete _socket;
+ _socket = 0;
+ }
+
+ QSettings settings;
+ quint16 portbase = settings.value("multicast/port-base", "6966").value<quint16>();
+ quint16 portlimit = settings.value("multicast/port-limit", "7966").value<quint16>();
+
+ int tries_remaining = 5;
+ while(tries_remaining > 0)
+ {
+ quint16 port = portbase + (qrand() % (portlimit - portbase + 1));
+
+ if (!_config)
+ {
+ _config = new McastConfiguration();
+ }
+ _config->loadFrom(&settings, "multicast");
+ _config->multicastUDPPortBase(port);
+
+ _socket = new McastPGMSocket(this);
+ if(_socket->open(_config, McastPGMSocket::PSOCK_WRITE))
+ {
+ break;
+ }
+ else
+ {
+ delete _socket;
+ _socket = 0;
+ }
+ }
+
+ if (!_socket)
+ {
+ emit failed(_id, "Could not open socket");
+ delete _prepareTimer;
+ _prepareTimer = 0;
+ return;
+ }
+ else
+ {
+ _socketInacceptable = false;
+ // announce the transfer:
+ QFileInfo info(*_file);
+ QString message = QString("%1:%2:%3:%4:%5").arg(_senderName).arg(_id).arg(info.baseName()).arg(info.size()).arg(_config->multicastUDPPortBase());
+ PVSMsg msg(PVSCOMMAND, "MCASTFTANNOUNCE", message);
+ emit announce(msg);
+ _prepareTimer->start(5000);
+ }
+}
+
+void PVSOutgoingMulticastTransfer::doStart()
+{
+ ConsoleLog writeLine(QString("Starting multicast transfer %1").arg(_id));
+
+ _file->open(QIODevice::ReadOnly);
+
+ _sender = new McastSender(_file, _config, this);
+ connect(_sender, SIGNAL(finished()), SLOT(senderFinished()));
+ connect(_sender, SIGNAL(progress(quint64)), SLOT(senderProgress(quint64)));
+ // connect(_sender, SIGNAL(allSent()), SIGNAL(allSent()));
+ _socket->setParent(_sender);
+ _sender->start(_socket);
+
+ emit started(_id);
+
+ _progressTimer = new QTimer(this);
+ connect(_progressTimer, SIGNAL(timeout()), SLOT(reportTimeout()));
+ _progressTimer->setInterval(333);
+ _progressTimer->start();
+}
+
+void PVSOutgoingMulticastTransfer::senderProgress(quint64 bytes)
+
+{
+ _progress = bytes;
+}
+
+void PVSOutgoingMulticastTransfer::senderFinished()
+{
+ if(_progressTimer)
+ {
+ _progressTimer->stop();
+ delete _progressTimer;
+ _progressTimer = 0;
+ }
+ emit finished(_id);
+ _sender->close();
+ delete _sender;
+}
+
+void PVSOutgoingMulticastTransfer::reportTimeout()
+{
+ emit progress(_id, _progress, _length);
+}
+
+void PVSOutgoingMulticastTransfer::retry()
+{
+ bool first = !_socketInacceptable;
+ _socketInacceptable = true;
+
+ if(first)
+ {
+ _prepareTimer->setInterval(1000);
+ }
+}
+
+void PVSOutgoingMulticastTransfer::start()
+{
+ if (!_prepareTimer)
+ {
+ _prepareTimer = new QTimer(this);
+ _prepareTimer->setSingleShot(true);
+ connect(_prepareTimer, SIGNAL(timeout()), SLOT(prepare()));
+ }
+ QTimer::singleShot(0, this, SLOT(prepare()));
+}
+
+void PVSOutgoingMulticastTransfer::abort()
+{
+ if (_sender)
+ _sender->close();
+}
+
+void PVSOutgoingMulticastTransfer::error(QString const& reason)
+{
+ qCritical() << "Could not create an outgoing mcast transfer: " << reason;
+ _error = true;
+ _reason = reason;
+}
diff --git a/src/net/pvsOutgoingMulticastTransfer.h b/src/net/pvsOutgoingMulticastTransfer.h
new file mode 100644
index 0000000..5fd6a3d
--- /dev/null
+++ b/src/net/pvsOutgoingMulticastTransfer.h
@@ -0,0 +1,92 @@
+/*
+# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+#
+# This program is free software distributed under the GPL version 2.
+# See http://openslx.org/COPYING
+#
+# If you have any feedback please consult http://openslx.org/feedback and
+# send your suggestions, praise, or complaints to feedback@openslx.org
+#
+# General information about OpenSLX can be found at http://openslx.org/
+# -----------------------------------------------------------------------------
+# src/net/pvsOutgoingMulticastTransfer.h
+# - wrap McastSender functionality in PVS daemon
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef PVSOUTGOINGMULTICASTTRANSFER_H_
+#define PVSOUTGOINGMULTICASTTRANSFER_H_
+
+#include <QtGlobal>
+#include <QObject>
+#include <QString>
+
+#include <src/net/pvsMsg.h>
+
+class QFile;
+class QTimer;
+class McastConfiguration;
+class McastPGMSocket;
+class McastSender;
+
+class PVSOutgoingMulticastTransfer : public QObject
+{
+ Q_OBJECT
+public:
+ PVSOutgoingMulticastTransfer(QString senderName, quint64 id, QString filename, QObject* parent = 0);
+ virtual ~PVSOutgoingMulticastTransfer();
+
+ quint64 id() const
+ {
+ return _id;
+ }
+
+ bool isError() const
+ {
+ return _error;
+ }
+
+ QString reason() const
+ {
+ return _reason;
+ }
+
+signals:
+ void started(qulonglong id);
+ void progress(qulonglong id, qulonglong bytes, qulonglong of);
+ void allSent(qulonglong id);
+ void finished(qulonglong id);
+ void failed(qulonglong id, QString const reason);
+ void announce(PVSMsg announcement);
+
+private slots:
+ void senderProgress(quint64 bytes);
+ void senderFinished();
+ void reportTimeout();
+ void doStart();
+ void prepare();
+
+public slots:
+ void start();
+ void abort();
+ void retry();
+
+private:
+ QFile* _file;
+ quint64 _length;
+ quint64 _progress;
+ McastConfiguration* _config;
+ McastPGMSocket* _socket;
+ McastSender* _sender;
+ QTimer* _progressTimer;
+ QTimer* _prepareTimer;
+ QString _senderName;
+ quint64 _id;
+ bool _error;
+ QString _reason;
+ bool _socketInacceptable;
+
+ void error(QString const& reason);
+};
+
+#endif /* PVSOUTGOINGMULTICASTTRANSFER_H_ */
diff --git a/src/net/pvsServerConnection.h b/src/net/pvsServerConnection.h
index 0669d88..c6ef015 100644
--- a/src/net/pvsServerConnection.h
+++ b/src/net/pvsServerConnection.h
@@ -11,9 +11,9 @@
#define _PVSSERVERCONNECTION_H_
#include "src/util/dispatcher.h"
+#include "src/net/pvsMsg.h"
#include <QtNetwork/QSslSocket>
-class PVSMsg;
class PVS;
class PVSDiscoveredServer;
@@ -30,8 +30,6 @@ public:
return _socket != NULL && _socket->state() == QAbstractSocket::ConnectedState;
}
- void sendMessage(PVSMsg newMessage);
-
void ping();
QString getServerName();
@@ -63,6 +61,9 @@ public:
_commandDispatcher.removeListener(ident, who, func);
};
+public Q_SLOTS:
+ void sendMessage(PVSMsg newMessage);
+
protected:
void timerEvent(QTimerEvent *event);
diff --git a/src/pvs.cpp b/src/pvs.cpp
index 2069e36..c7fe5ce 100644
--- a/src/pvs.cpp
+++ b/src/pvs.cpp
@@ -15,6 +15,8 @@
#include "src/net/pvsMsg.h"
#include "src/net/pvsServiceDiscovery.h"
#include "src/net/pvsDiscoveredServer.h"
+#include "src/net/mcast/McastConfiguration.h"
+#include "src/net/pvsOutgoingMulticastTransfer.h"
// D-Bus
#include "pvsadaptor.h"
@@ -38,6 +40,7 @@ PVS::PVS() :
loadCommands();
_blankScreen = NULL;
_vncPort = -1;
+ _masterMcastConfig = new McastConfiguration(this);
// add a notify to the allow file, so we get informed when the file is changed
QString watchPath("/home/");
@@ -176,6 +179,17 @@ void PVS::onCommand(PVSMsg cmdMessage)
unlock();
return;
}
+ if (ident.compare("MCASTFTRETRY") == 0)
+ {
+ QStringList fields = message.split(':');
+ if (fields[0].compare(getUserName()) == 0)
+ {
+ quint64 id = fields[0].toULongLong();
+ PVSOutgoingMulticastTransfer* transfer = _outgoingTransfers.value(id, 0);
+ if (transfer)
+ transfer->retry();
+ }
+ }
#ifdef never
// prototype
@@ -627,3 +641,49 @@ void PVS::signalHandler(int signal)
}
+bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID, QString& errorReason)
+{
+ transferID = generateMcastTransferID();
+
+ PVSOutgoingMulticastTransfer* transfer = new PVSOutgoingMulticastTransfer(getUserName(), transferID, objectPath, this);
+ if (transfer->isError())
+ {
+ errorReason = transfer->reason();
+ delete transfer;
+ return false;
+ }
+
+ _outgoingTransfers.insert(transferID, transfer);
+ connect(transfer, SIGNAL(started(qulonglong)), SIGNAL(outgoingMulticastTransferStarted(qulonglong)));
+ connect(transfer, SIGNAL(finished(qulonglong)), SIGNAL(outgoingMulticastTransferFinished(qulonglong)));
+ connect(transfer, SIGNAL(failed(qulonglong, QString const)), SIGNAL(outgoingMulticastTransferFailed(qulonglong, QString const)));
+ connect(transfer, SIGNAL(progress(qulonglong, qulonglong, qulonglong)), SIGNAL(outgoingMulticastTransferProgress(qulonglong, qulonglong, qulonglong)));
+ connect(transfer, SIGNAL(announce(PVSMsg)), _pvsServerConnection, SLOT(sendMessage(PVSMsg)));
+ QTimer::singleShot(0, transfer, SLOT(start()));
+ errorReason = "";
+ return true;
+}
+
+void PVS::cancelOutgoingMulticastTransfer(quint64 transferID)
+{
+ PVSOutgoingMulticastTransfer* transfer = _outgoingTransfers.value(transferID, 0);
+
+ if (transfer)
+ {
+ delete transfer;
+ }
+}
+
+quint64 PVS::generateMcastTransferID()
+{
+ static quint64 nodeID = 0;
+ static quint16 counter = 0;
+
+ if (!nodeID)
+ {
+ QDataStream(QCryptographicHash::hash(getUserName().toLocal8Bit(), QCryptographicHash::Md5)) >> nodeID;
+ }
+
+ return (nodeID & Q_UINT64_C(0xffffffffffff0000)) | (quint64)(++counter);
+}
+
diff --git a/src/pvs.h b/src/pvs.h
index 4b1e29e..93596d2 100644
--- a/src/pvs.h
+++ b/src/pvs.h
@@ -28,6 +28,8 @@
class PVSServiceDiscovery;
class PVSDiscoveredServer;
+class McastConfiguration;
+class PVSOutgoingMulticastTransfer;
/**
* PVSClient
@@ -80,6 +82,11 @@ public Q_SLOTS:
QStringList getAvailableHosts();
QString getIpByNick(QString nick);
+ // Multicast File Transfer
+ bool createMulticastTransfer(QString const& objectPath, quint64& transferID, QString& errorReason);
+ void cancelOutgoingMulticastTransfer(quint64 transferID);
+
+
Q_SIGNALS:
void project(QString host, int port, QString passwd, bool fullscreen,
bool smoothTransformation, int quality);
@@ -93,6 +100,12 @@ Q_SIGNALS:
void addHost(QString host);
void delHost(QString host);
+ // Multicast File Transfer
+ void outgoingMulticastTransferStarted(qulonglong transferID);
+ void outgoingMulticastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of);
+ void outgoingMulticastTransferFinished(qulonglong transferID);
+ void outgoingMulticastTransferFailed(qulonglong transferID, QString reason);
+
protected:
void timerEvent(QTimerEvent *event);
@@ -142,5 +155,9 @@ private:
int _timerLockTest;
int _timerLockDelay;
+ McastConfiguration* _masterMcastConfig;
+ QHash<quint64, PVSOutgoingMulticastTransfer*> _outgoingTransfers;
+
+ static quint64 generateMcastTransferID();
};
#endif /* PVSCLIENT_H_ */