From 2ad0ca683dfade47078a2aafce9921ca238a9436 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sat, 17 Jul 2010 16:43:08 +0200 Subject: Implement UI and pvsDaemon components for outgoing Multicast Transfer --- src/gui/ui/clientFileSendDialog.ui | 15 +++++++++++---- src/gui/ui/clientNicklistDialog.ui | 7 +++++++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src/gui/ui') 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 @@ 0 0 - 186 - 108 + 528 + 144 @@ -33,7 +33,7 @@ - + @@ -61,10 +61,17 @@ + + + + + + + - + 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 @@ -28,6 +28,13 @@ + + + + Send to &all + + + -- cgit v1.2.3-55-g7522 From 88dbb997a823ff77f752ac08105d12474345dfcb Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 4 Aug 2010 17:24:21 +0200 Subject: Implement GUI for receiving incoming multicast transfers --- src/gui/clientFileReceiveDialog.cpp | 83 +++++++++++++++++++++++++++++++- src/gui/clientFileReceiveDialog.h | 14 ++++++ src/gui/ui/clientFileReceiveDialog.ui | 11 ++++- src/net/pvsIncomingMulticastTransfer.cpp | 37 +++++++------- src/net/pvsIncomingMulticastTransfer.h | 6 +-- src/pvs.cpp | 19 +++++++- src/pvs.h | 5 +- src/pvsgui.cpp | 7 +++ src/pvsgui.h | 1 + 9 files changed, 154 insertions(+), 29 deletions(-) (limited to 'src/gui/ui') diff --git a/src/gui/clientFileReceiveDialog.cpp b/src/gui/clientFileReceiveDialog.cpp index 669ca81..ff3226a 100644 --- a/src/gui/clientFileReceiveDialog.cpp +++ b/src/gui/clientFileReceiveDialog.cpp @@ -16,6 +16,9 @@ */ #include "clientFileReceiveDialog.h" +#include +#include +#include ClientFileReceiveDialog::ClientFileReceiveDialog(QTcpSocket *socket, QWidget *parent) : QDialog(parent) @@ -37,9 +40,44 @@ ClientFileReceiveDialog::ClientFileReceiveDialog(QTcpSocket *socket, QWidget *pa connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); } +ClientFileReceiveDialog::ClientFileReceiveDialog(QString const& sender, qulonglong transferID, + QString const& filename, qulonglong size, OrgOpenslxPvsInterface* ifaceDBus, QWidget* parent) +{ + setupUi(this); + + _transferID = transferID; + _filename = filename; + _ifaceDBus = ifaceDBus; + _bytesToRead = size; + _socket = 0; + _file = 0; + div = 1; + while((size / div) > INT_MAX) + { + div <<= 1; + } + + connect(ifaceDBus, SIGNAL(incomingMulticastTransferStarted(qulonglong)), SLOT(mcastTransferStarted(qulonglong))); + connect(ifaceDBus, SIGNAL(incomingMulticastTransferProgress(qulonglong, qulonglong, qulonglong)), + SLOT(mcastTransferProgress(qulonglong, qulonglong, qulonglong))); + connect(ifaceDBus, SIGNAL(incomingMulticastTransferFinished(qulonglong)), SLOT(mcastTransferFinished(qulonglong))); + connect(ifaceDBus, SIGNAL(incomingMulticastTransferFailed(qulonglong, QString)), SLOT(mcastTransferFailed(qulonglong, QString))); + connect(cancelButton, SIGNAL(clicked()), SLOT(cancelTransfer())); + + qDebug("[%s] New multicast incoming transfer: %s from %s", metaObject()->className(), + filename.toLocal8Bit().constData(), sender.toLocal8Bit().constData()); + + + filenameLabel->setText(QFileInfo(filename).baseName()); + labelNick->setText(sender); + progressBar->setRange(0, 0); +} + + ClientFileReceiveDialog::~ClientFileReceiveDialog() { - _socket->deleteLater(); + if(_socket) + _socket->deleteLater(); qDebug("[%s] Deleted!", metaObject()->className()); } @@ -168,6 +206,49 @@ void ClientFileReceiveDialog::error(QAbstractSocket::SocketError error) close(); } +void ClientFileReceiveDialog::mcastTransferStarted(qulonglong transferID) +{ + if(transferID != _transferID) + return; +} + +void ClientFileReceiveDialog::mcastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of) +{ + if(transferID != _transferID) + return; + + progressBar->setRange(0, of); + progressBar->setValue(bytes); +} + +void ClientFileReceiveDialog::mcastTransferFinished(qulonglong transferID) +{ + if(transferID != _transferID) + return; + + QString filename = QFileDialog::getSaveFileName(this, tr("Where should I save %1?").arg(_filename), _filename); + QFile* file = new QFile(_filename); + if(!file->rename(filename)) + { + QMessageBox::warning(this, tr("Could not rename file"), tr("Failed to rename %1 to %2").arg(_filename).arg(filename)); + } + accept(); +} + +void ClientFileReceiveDialog::mcastTransferFailed(qulonglong transferID, QString reason) +{ + if(transferID != _transferID) + return; + + QMessageBox::warning(this, tr("File transfer failed"), tr("File transfer failed for the following reason:\n%1").arg(reason)); + reject(); +} + +void ClientFileReceiveDialog::cancelTransfer() +{ + _ifaceDBus->cancelIncomingMulticastTransfer(_transferID); +} + QString ClientFileReceiveDialog::formatSize(qint64 size) { if (size >= 1000000000) // GB diff --git a/src/gui/clientFileReceiveDialog.h b/src/gui/clientFileReceiveDialog.h index c13d7b7..c9ed220 100644 --- a/src/gui/clientFileReceiveDialog.h +++ b/src/gui/clientFileReceiveDialog.h @@ -18,6 +18,8 @@ #include #include "ui_clientFileReceiveDialog.h" +class OrgOpenslxPvsInterface; + class ClientFileReceiveDialog: public QDialog, private Ui::ClientFileReceiveDialogClass { @@ -25,6 +27,7 @@ Q_OBJECT public: ClientFileReceiveDialog(QTcpSocket *socket, QWidget *parent = 0); + ClientFileReceiveDialog(QString const& sender, qulonglong transferID, QString const& basename, qulonglong size, OrgOpenslxPvsInterface* ifaceDBus, QWidget* parent = 0); ~ClientFileReceiveDialog(); private Q_SLOTS: @@ -33,6 +36,13 @@ private Q_SLOTS: void close(); void error(QAbstractSocket::SocketError error); + // multicast: + void mcastTransferStarted(qulonglong transferID); + void mcastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of); + void mcastTransferFinished(qulonglong transferID); + void mcastTransferFailed(qulonglong transferID, QString reason); + void cancelTransfer(); + private: void sendAck(bool b); QString formatSize(qint64 size); @@ -42,6 +52,10 @@ private: qint64 _bytesToRead; int div; + // multicast: + OrgOpenslxPvsInterface* _ifaceDBus; + QString _filename; + qulonglong _transferID; }; #endif /* CLIENTFILERECEIVEDIALOG_H_ */ diff --git a/src/gui/ui/clientFileReceiveDialog.ui b/src/gui/ui/clientFileReceiveDialog.ui index af3a135..a137def 100644 --- a/src/gui/ui/clientFileReceiveDialog.ui +++ b/src/gui/ui/clientFileReceiveDialog.ui @@ -6,8 +6,8 @@ 0 0 - 208 - 108 + 528 + 117 @@ -61,6 +61,13 @@ + + + + + + + diff --git a/src/net/pvsIncomingMulticastTransfer.cpp b/src/net/pvsIncomingMulticastTransfer.cpp index 01507a9..10b5307 100644 --- a/src/net/pvsIncomingMulticastTransfer.cpp +++ b/src/net/pvsIncomingMulticastTransfer.cpp @@ -21,7 +21,7 @@ #include "pvsIncomingMulticastTransfer.h" #include -PVSIncomingMulticastTransfer::PVSIncomingMulticastTransfer(QString const& sender, qulonglong transferID, qulonglong size, +PVSIncomingMulticastTransfer::PVSIncomingMulticastTransfer(QString const& sender, qulonglong transferID, qulonglong size, QString const& filename, ushort port, McastConfiguration const* configTemplate, QObject* parent) : QObject(parent), _sender(sender), @@ -29,19 +29,21 @@ PVSIncomingMulticastTransfer::PVSIncomingMulticastTransfer(QString const& sender _bytes(0), _size(size), _port(port), - _temporaryFile(new QTemporaryFile(QFileInfo(QDir::homePath(), "incoming.mcastft.XXXXXX").absolutePath(), this)), - _finalFile(0), + _file(new QFile(filename, this)), _receiver(0), _config(configTemplate ? new McastConfiguration(*configTemplate) : new McastConfiguration()), _progressTimer(new QTimer(this)) { + _file->open(QIODevice::WriteOnly); + _config->multicastUDPPortBase(port); - _config->multicastDPort(port); - _config->multicastSPort(port); + // _config->multicastDPort(port+1); + // _config->multicastSPort(port+2); connect(_progressTimer, SIGNAL(timeout()), SLOT(updateProgress())); + connect(this, SIGNAL(failed(qulonglong, QString const&)), SLOT(removeFile())); } PVSIncomingMulticastTransfer::~PVSIncomingMulticastTransfer() @@ -51,10 +53,10 @@ PVSIncomingMulticastTransfer::~PVSIncomingMulticastTransfer() bool PVSIncomingMulticastTransfer::start() { - QFile *dest = _finalFile ? _finalFile : _temporaryFile; - _receiver = new McastReceiver(dest, new McastConfiguration(*_config), this); + _file->open(QIODevice::WriteOnly); + _receiver = new McastReceiver(_file, new McastConfiguration(*_config), this); connect(_receiver, SIGNAL(finished(int)), SLOT(receiverFinished(int))); - connect(_receiver, SIGNAL(progress(quint64)), SLOT(receiverProgress(quint64))); + connect(_receiver, SIGNAL(progress(quint64)), SLOT(receiverProgressed(quint64))); if (!_receiver->start()) { @@ -76,17 +78,8 @@ void PVSIncomingMulticastTransfer::abort() delete _progressTimer; _progressTimer = 0; - if (_temporaryFile) - { - _temporaryFile->remove(); - } - delete _temporaryFile; - - if (_finalFile) - { - _finalFile->remove(); - } - delete _finalFile; + if(_file) + delete _file; } void PVSIncomingMulticastTransfer::updatePort(ushort port) @@ -124,6 +117,12 @@ void PVSIncomingMulticastTransfer::receiverFinished(int how) } } +void PVSIncomingMulticastTransfer::removeFile() +{ + if(_file) + _file->remove(); +} + void PVSIncomingMulticastTransfer::updateProgress() { if (!_started) diff --git a/src/net/pvsIncomingMulticastTransfer.h b/src/net/pvsIncomingMulticastTransfer.h index 9a33348..f96e176 100644 --- a/src/net/pvsIncomingMulticastTransfer.h +++ b/src/net/pvsIncomingMulticastTransfer.h @@ -31,7 +31,7 @@ class PVSIncomingMulticastTransfer : public QObject { Q_OBJECT public: - PVSIncomingMulticastTransfer(QString const& sender, qulonglong transferID, qulonglong size, ushort port, + PVSIncomingMulticastTransfer(QString const& sender, qulonglong transferID, qulonglong size, QString const& filename, ushort port, McastConfiguration const* configTemplate, QObject* parent = 0); virtual ~PVSIncomingMulticastTransfer(); @@ -53,6 +53,7 @@ private slots: void receiverProgressed(quint64 bytes); void receiverFinished(int reason); void updateProgress(); + void removeFile(); private: QString _sender; @@ -60,8 +61,7 @@ private: qulonglong _bytes; qulonglong _size; ushort _port; - QFile* _temporaryFile; - QFile* _finalFile; + QFile* _file; McastReceiver* _receiver; McastConfiguration* _config; bool _started; diff --git a/src/pvs.cpp b/src/pvs.cpp index 0e5aaf5..852c9f4 100644 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -716,9 +716,23 @@ void PVS::cancelOutgoingMulticastTransfer(quint64 transferID) } } +void PVS::cancelIncomingMulticastTransfer(qulonglong transferID) +{ + PVSIncomingMulticastTransfer* transfer = _incomingTransfers.value(transferID, 0); + + if(transfer) + { + _incomingTransfers.remove(transferID); + delete transfer; + } +} + void PVS::onIncomingMulticastTransfer(QString const& sender, qulonglong transferID, QString const& basename, qulonglong size, ushort port) { + if (_outgoingTransfers.contains(transferID)) + return; + PVSIncomingMulticastTransfer* transfer; if (_incomingTransfers.value(transferID, 0)) { @@ -727,7 +741,8 @@ void PVS::onIncomingMulticastTransfer(QString const& sender, qulonglong transfer } else { - transfer = new PVSIncomingMulticastTransfer(sender, transferID, size, port, _masterMcastConfig, this); + QString filename = QFileInfo(QDir::home(), QString("%1.part.%2").arg(basename).arg(transferID, 0, 16)).absoluteFilePath(); + transfer = new PVSIncomingMulticastTransfer(sender, transferID, size, filename, port, _masterMcastConfig, this); _incomingTransfers.insert(transferID, transfer); connect(transfer, SIGNAL(retry(QString const&, qulonglong)), SLOT(onIncomingMulticastTransferRetry(QString const&, qulonglong))); @@ -738,7 +753,7 @@ void PVS::onIncomingMulticastTransfer(QString const& sender, qulonglong transfer connect(transfer, SIGNAL(finished(qulonglong)), SLOT(incomingMulticastTransferDelete(qulonglong))); connect(transfer, SIGNAL(failed(qulonglong, QString const&)), SLOT(incomingMulticastTransferDelete(qulonglong))); - emit incomingMulticastTransferNew(transferID, sender, basename, size); + emit incomingMulticastTransferNew(transferID, sender, filename, size); QTimer::singleShot(0, transfer, SLOT(start())); } } diff --git a/src/pvs.h b/src/pvs.h index dc272f0..ef6454e 100644 --- a/src/pvs.h +++ b/src/pvs.h @@ -86,6 +86,7 @@ public Q_SLOTS: // Multicast File Transfer bool createMulticastTransfer(QString const& objectPath, quint64& transferID, QString& errorReason); void cancelOutgoingMulticastTransfer(quint64 transferID); + void cancelIncomingMulticastTransfer(qulonglong transferID); Q_SIGNALS: @@ -106,7 +107,7 @@ Q_SIGNALS: void outgoingMulticastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of); void outgoingMulticastTransferFinished(qulonglong transferID); void outgoingMulticastTransferFailed(qulonglong transferID, QString reason); - void incomingMulticastTransferNew(qulonglong transferID, QString sender, QString basename, qulonglong size); + void incomingMulticastTransferNew(qulonglong transferID, QString sender, QString filename, qulonglong size); void incomingMulticastTransferStarted(qulonglong transferID); void incomingMulticastTransferProgress(qulonglong transferID, qulonglong bytes, qulonglong of); void incomingMulticastTransferFinished(qulonglong transferID); @@ -166,12 +167,12 @@ private: QHash _incomingTransfers; void onIncomingMulticastTransfer(QString const& sender, qulonglong transferID, QString const& basename, qulonglong size, ushort port); - void onIncomingMulticastTransferRetry(QString const& sender, qulonglong transferID); static quint64 generateMcastTransferID(); private Q_SLOTS: // housekeeping void outgoingMulticastTransferDelete(qulonglong transferID); void incomingMulticastTransferDelete(qulonglong transferID); + void onIncomingMulticastTransferRetry(QString const& sender, qulonglong transferID); }; #endif /* PVSCLIENT_H_ */ diff --git a/src/pvsgui.cpp b/src/pvsgui.cpp index 25f1cd6..e949d5b 100644 --- a/src/pvsgui.cpp +++ b/src/pvsgui.cpp @@ -119,6 +119,7 @@ PVSGUI::PVSGUI(QWidget *parent) : connect(_ifaceDBus, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(_ifaceDBus, SIGNAL(addHost(QString)), this, SLOT(addHost(QString))); connect(_ifaceDBus, SIGNAL(delHost(QString)), this, SLOT(delHost(QString))); + connect(_ifaceDBus, SIGNAL(incomingMulticastTransferNew(qulonglong, QString, QString, qulonglong)), SLOT(incomingMulticastFile(qulonglong, QString, QString, qulonglong))); // show toolbar setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); @@ -421,6 +422,12 @@ void PVSGUI::receiveFile() d->open(); } +void PVSGUI::incomingMulticastFile(qulonglong transferID, QString sender, QString basename, qulonglong size) +{ + ClientFileReceiveDialog *d = new ClientFileReceiveDialog(sender, transferID, basename, size, _ifaceDBus, this); + d->open(); +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/src/pvsgui.h b/src/pvsgui.h index f9a0ab8..2883b60 100644 --- a/src/pvsgui.h +++ b/src/pvsgui.h @@ -65,6 +65,7 @@ private Q_SLOTS: void setVncAllow(int i); void sendFile(); void receiveFile(); + void incomingMulticastFile(qulonglong, QString sender, QString basename, qulonglong size); private: void setupMenu(); -- cgit v1.2.3-55-g7522 From f8e6e94b25a092d51acdec600465074b4eb32cb8 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 4 Aug 2010 17:28:45 +0200 Subject: Make PGM interface configurable --- src/gui/clientConfigDialog.cpp | 61 +++++++++++++++++++++++++++++++++++++- src/gui/clientConfigDialog.h | 2 ++ src/gui/ui/clientConfigDialog.ui | 64 ++++++++++++++++++++++++++++++++++++++-- src/pvs.cpp | 7 +++++ src/pvs.h | 2 +- src/pvsgui.cpp | 3 ++ 6 files changed, 134 insertions(+), 5 deletions(-) (limited to 'src/gui/ui') diff --git a/src/gui/clientConfigDialog.cpp b/src/gui/clientConfigDialog.cpp index 76b4f5e..3867118 100644 --- a/src/gui/clientConfigDialog.cpp +++ b/src/gui/clientConfigDialog.cpp @@ -16,15 +16,32 @@ # ----------------------------------------------------------------------------- */ +#include #include "clientConfigDialog.h" +#include +#include +#include + +// For getting the network interface list: +#ifdef __linux +# include +# include +#endif + +using namespace std; ClientConfigDialog::ClientConfigDialog(QWidget *parent) : - QDialog(parent) + QDialog(parent), + _interfaceListModel(0) { setupUi(this); connect(this, SIGNAL(accepted()), this, SLOT(writeSettings())); connect(radioButtonOtherRO, SIGNAL(clicked()), this, SLOT(checkPermissions())); + connect(reloadInterfaceListButton, SIGNAL(clicked()), this, SLOT(reloadNetworkInterfaceList())); + reloadNetworkInterfaceList(); + interfaceList->setModel(_interfaceListModel); + interfaceList->setModelColumn(0); } @@ -66,6 +83,9 @@ void ClientConfigDialog::readSettings() checkBoxAllowFiletransfer->setChecked(_settings.value( "Permissions/allow_filetransfer").toBool()); + if(!_settings.value("Muticast/interface").isNull()) + interfaceList->setEditText(_settings.value("Multicast/interface").toString()); + qDebug("[%s] Setting read from: '%s'", metaObject()->className(), qPrintable(_settings.fileName())); } @@ -88,6 +108,7 @@ void ClientConfigDialog::writeSettings() _settings.setValue("Permissions/allow_chat", checkBoxAllowChat->isChecked()); _settings.setValue("Permissions/allow_filetransfer", checkBoxAllowFiletransfer->isChecked()); + _settings.setValue("Multicast/interface", interfaceList->currentText()); _settings.sync(); emit configChanged(); @@ -103,3 +124,41 @@ void ClientConfigDialog::checkPermissions() if (radioButtonLecturerNO->isChecked() && radioButtonOtherRO->isChecked()) radioButtonLecturerRO->setChecked(true); } + +void ClientConfigDialog::reloadNetworkInterfaceList() +{ +#ifdef __linux + static struct ifreq ifreqs[20]; + ifconf ifconfigs; + memset(&ifconfigs, 0, sizeof(ifconfigs)); + ifconfigs.ifc_len = sizeof(ifreqs); + ifconfigs.ifc_buf = (char*)&ifreqs; + + int nosock = socket(AF_INET, SOCK_STREAM, 0); + if (nosock < 0) + { + qWarning() << "Could not get a socket descriptor:" << strerror(errno); + } + int retval; + if ((retval = ioctl(nosock, SIOCGIFCONF, (char*)(&ifconfigs))) < 0) + { + qWarning() << "Could not get the list of interfaces:" << strerror(errno); + return; + } + + QStringList interfaces; + for(int i = 0; i < ifconfigs.ifc_len/sizeof(struct ifreq); i++) + { + char ifname[IFNAMSIZ + 1]; + strncpy(ifname, ifreqs[i].ifr_name, IFNAMSIZ); + ifname[IFNAMSIZ] = '\0'; + interfaces << QString::fromLocal8Bit(ifname); + } + if(!_interfaceListModel) + _interfaceListModel = new QStringListModel(interfaces, this); + else + _interfaceListModel->setStringList(interfaces); +#else +# warning "We have no way to get your system's network interface list. Some porting may be required." +#endif +} diff --git a/src/gui/clientConfigDialog.h b/src/gui/clientConfigDialog.h index 706bd8a..803f2c8 100644 --- a/src/gui/clientConfigDialog.h +++ b/src/gui/clientConfigDialog.h @@ -35,9 +35,11 @@ Q_SIGNALS: private Q_SLOTS: void checkPermissions(); + void reloadNetworkInterfaceList(); private: QSettings _settings; + QStringListModel* _interfaceListModel; }; diff --git a/src/gui/ui/clientConfigDialog.ui b/src/gui/ui/clientConfigDialog.ui index 3262b6b..bb4bdc9 100644 --- a/src/gui/ui/clientConfigDialog.ui +++ b/src/gui/ui/clientConfigDialog.ui @@ -6,8 +6,8 @@ 0 0 - 438 - 257 + 445 + 266 @@ -27,7 +27,7 @@ QTabWidget::North - 0 + 2 @@ -197,6 +197,64 @@ + + + + 0 + 0 + + + + false + + + Network + + + + + + + 0 + 0 + + + + true + + + QComboBox::NoInsert + + + true + + + + + + + + 0 + 0 + + + + Network Interface + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Reload List + + + + + diff --git a/src/pvs.cpp b/src/pvs.cpp index 202aa32..c217d52 100644 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -728,6 +728,13 @@ void PVS::cancelIncomingMulticastTransfer(qulonglong transferID) } } +void PVS::setMulticastInterface(QString const& interfaceName) +{ + QSettings settings; + settings.setValue("multicast/interface", interfaceName); + settings.sync(); +} + void PVS::onIncomingMulticastTransfer(QString const& sender, qulonglong transferID, QString const& basename, qulonglong size, ushort port) { diff --git a/src/pvs.h b/src/pvs.h index ef6454e..4c61ffd 100644 --- a/src/pvs.h +++ b/src/pvs.h @@ -87,7 +87,7 @@ public Q_SLOTS: bool createMulticastTransfer(QString const& objectPath, quint64& transferID, QString& errorReason); void cancelOutgoingMulticastTransfer(quint64 transferID); void cancelIncomingMulticastTransfer(qulonglong transferID); - + void setMulticastInterface(QString const& interfaceName); Q_SIGNALS: void project(QString host, int port, QString passwd, bool fullscreen, diff --git a/src/pvsgui.cpp b/src/pvsgui.cpp index e949d5b..40112b4 100644 --- a/src/pvsgui.cpp +++ b/src/pvsgui.cpp @@ -143,6 +143,9 @@ void PVSGUI::updateConfig() setLocation(POSITION_TOP_CENTER); else setLocation(_settings.value("Display/location").toInt()); + + if (!_settings.value("Multicast/interface").isNull()) + _ifaceDBus->setMulticastInterface(_settings.value("Multicast/interface").toString()); } //////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3-55-g7522 From 5bcf831e1734be78d9468631926e875a5b05e11f Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 3 Oct 2010 23:27:39 +0200 Subject: Implement Network-wide Configuration Interface for Multicast File Transfer --- CMakeLists.txt | 6 ++ pvsmgr.qrc | 1 + src/gui/mainWindow.cpp | 17 +++- src/gui/mainWindow.h | 1 + src/gui/multicastConfigDialog.cpp | 170 ++++++++++++++++++++++++++++++++++++ src/gui/multicastConfigDialog.h | 38 ++++++++ src/gui/ui/mainwindow.ui | 15 ++++ src/gui/ui/mainwindowtouch.ui | 11 +++ src/gui/ui/multicastConfigDialog.ui | 156 +++++++++++++++++++++++++++++++++ src/net/mcast/McastConfiguration.h | 17 ++++ src/net/pvsListenServer.cpp | 60 +++++++++++++ src/net/pvsListenServer.h | 10 +++ src/pvs.cpp | 58 +++++++++++- src/pvs.h | 1 + 14 files changed, 559 insertions(+), 2 deletions(-) create mode 100644 src/gui/multicastConfigDialog.cpp create mode 100644 src/gui/multicastConfigDialog.h create mode 100644 src/gui/ui/multicastConfigDialog.ui (limited to 'src/gui/ui') diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f2089a..0899bdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ SET( PVSMGR_SRCS src/util/TextFile.cpp src/util/serviceDiscoveryUtil.cpp src/gui/aboutDialog.cpp + src/gui/multicastConfigDialog.cpp ) # pvs @@ -131,6 +132,7 @@ SET( PVSMGR_UIS src/gui/ui/aboutDialog.ui src/gui/ui/serverChatDialog.ui src/gui/ui/clientFileSendDialog.ui + src/gui/ui/multicastConfigDialog.ui ) SET( PVSMGRTOUCH_UIS @@ -140,6 +142,7 @@ SET( PVSMGRTOUCH_UIS src/gui/ui/projectionDialog.ui src/gui/ui/aboutDialog.ui src/gui/ui/serverChatDialog.ui + src/gui/ui/multicastConfigDialog.ui ) SET( PVSGUI_UIS @@ -186,6 +189,7 @@ SET( PVSMGR_MOC_HDRS src/net/pvsServiceBroadcast.h src/net/SslServer.h src/gui/aboutDialog.h + src/gui/multicastConfigDialog.h ) SET( PVS_MOC_HDRS @@ -317,12 +321,14 @@ TARGET_LINK_LIBRARIES( pvsmgr ${QT_LIBRARIES} ${VNC_LIBRARIES} ${X11_LIBRARIES} + pvsmcast ) TARGET_LINK_LIBRARIES( pvsmgrtouch ${QT_LIBRARIES} ${VNC_LIBRARIES} ${X11_LIBRARIES} + pvsmcast ) TARGET_LINK_LIBRARIES( pvs diff --git a/pvsmgr.qrc b/pvsmgr.qrc index 171412e..e0b6b51 100644 --- a/pvsmgr.qrc +++ b/pvsmgr.qrc @@ -19,6 +19,7 @@ icons/dozent.png icons/chat.png icons/cam32.svg + icons/network_configure.png AUTHORS TRANSLATION diff --git a/src/gui/mainWindow.cpp b/src/gui/mainWindow.cpp index eb15e82..c911721 100644 --- a/src/gui/mainWindow.cpp +++ b/src/gui/mainWindow.cpp @@ -16,7 +16,10 @@ #include #include +#include +#include #include +#include using namespace std; // setting the IF-DEF Block for the touchgui and the normal gui, for later use @@ -34,6 +37,7 @@ using namespace std; #include //#include #include +#include #include MainWindow::MainWindow(QWidget *parent) : @@ -129,6 +133,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->actionFoto->setStatusTip(tr("Make a screenshot for the selected client(s)")); ui->actionLock->setStatusTip(tr("Lock or Unlock all Clients")); connect(ui->actionCreate_profile, SIGNAL(triggered()), this, SLOT(createProfile())); + connect(ui->actionConfigure_Network, SIGNAL(triggered()), this, SLOT(configureNetwork())); connect(ui->actionShow_Username, SIGNAL(triggered()), this, SLOT(showusername())); connect(ui->actionShow_Hostname_IP, SIGNAL(triggered()), this, SLOT(showip())); @@ -1197,7 +1202,17 @@ void MainWindow::startChatDialog() sChatDialog.raise();//show the chat dialog on top level } - +void MainWindow::configureNetwork() +{ + PVSServer* server = PVSConnectionManager::getManager()->getServer(); + McastConfiguration mc(*(server->getMulticastConfiguration())); + MulticastConfigDialog* mcd = new MulticastConfigDialog(&mc, this); + int result = mcd->exec(); + if(result == QDialog::Accepted) + { + server->multicastReconfigure(&mc); + } +} MainWindow* MainWindow::myself = NULL; ConnectionList* MainWindow::conList = NULL; diff --git a/src/gui/mainWindow.h b/src/gui/mainWindow.h index 00bd927..41d9cfa 100644 --- a/src/gui/mainWindow.h +++ b/src/gui/mainWindow.h @@ -194,6 +194,7 @@ private slots: void setPasswordForConnection(int enabled); void combobox1(int menuindex1); // Funktion um index der combobox auszulesen und weiterzuverarbeiten s. Ticker 671 //void combobox2(int menuindex2); // Funktion um index der combobox auszulesen und weiterzuverarbeiten + void configureNetwork(); }; diff --git a/src/gui/multicastConfigDialog.cpp b/src/gui/multicastConfigDialog.cpp new file mode 100644 index 0000000..ff370c7 --- /dev/null +++ b/src/gui/multicastConfigDialog.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include "multicastConfigDialog.h" +#include +// #include "multicastValidators.h" + +MulticastConfigDialog::MulticastConfigDialog(QWidget* parent) : + QDialog(parent) +{ + setupUi(); +} + +MulticastConfigDialog::MulticastConfigDialog(McastConfiguration* config, + QWidget *parent) : + QDialog(parent) +{ + setupUi(); + _config = config; + + _ui.groupAddressEdit->setText(config->multicastAddress()); + _ui.dataPortEdit->setText(QString::number(config->multicastUDPPortBase())); + + connect(_ui.buttonBox, SIGNAL(accepted()), this, SLOT(dialogAccepted())); + connect(_ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +void MulticastConfigDialog::setupUi() +{ + _ui.setupUi(this); + + QIntValidator* portValidator = new QIntValidator(1024, 65535, this); + _ui.dataPortEdit->setValidator(portValidator); + + connect(_ui.groupAddressEdit, SIGNAL(textChanged(QString const&)), this, + SLOT(validateGroupAddress(QString const&))); + connect(_ui.dataPortEdit, SIGNAL(textChanged(QString const&)), this, + SLOT(validateDataPort(QString const&))); + + connect(_ui.buttonBox, SIGNAL(accepted()), this, SLOT(dialogAccepted())); + connect(_ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + validateGroupAddress(_ui.groupAddressEdit->text()); + validateDataPort(_ui.dataPortEdit->text()); +} + +MulticastConfigDialog::~MulticastConfigDialog() +{ +} + +void MulticastConfigDialog::dialogAccepted() +{ + QHostAddress addr; + bool addressParses = addr.setAddress(_ui.groupAddressEdit->text()); + _config->multicastAddress(_ui.groupAddressEdit->text()); + quint16 port = _ui.dataPortEdit->text().toInt(); + _config->multicastUDPPortBase(port); + _config->multicastDPort(port + 1); + _config->multicastSPort(port + 2); + _config->multicastRate(_ui.rateSpinbox->value() * 1024); + accept(); +} + +void MulticastConfigDialog::setError(QWidget* widget, + QLabel* errorMessageLabel, QString text) +{ + if (errorMessageLabel) + errorMessageLabel->setText(QString( + "") + text + + ""); + if (widget) + widget->setStyleSheet("background-color: #ffcccc;"); +} + +void MulticastConfigDialog::setOK(QWidget* widget, QLabel* errorMessageLabel) +{ + if (errorMessageLabel) + errorMessageLabel->setText(QString( + "") + + tr("OK") + ""); + if (widget) + widget->setStyleSheet("background-color: #ccffcc;"); +} + +void MulticastConfigDialog::validateGroupAddress(QString const& input) +{ + QHostAddress a; + + _isAddressValid = false; + + if (!a.setAddress(input)) + { + setError(_ui.groupAddressEdit, _ui.groupAddressMessage, tr( + "Not a valid IP Address")); + revalidateButtons(); + return; + } + + // check if it is IPv4 + if (a.protocol() != QAbstractSocket::IPv4Protocol) + { + setError(_ui.groupAddressEdit, _ui.groupAddressMessage, tr( + "Not a valid IPv4 Address")); + revalidateButtons(); + return; + } + + // check if it is a valid multicast address + quint32 addr = a.toIPv4Address(); + if ((addr & 0xf0000000) != 0xe0000000) + { + setError(_ui.groupAddressEdit, _ui.groupAddressMessage, tr( + "Not an IPv4 multicast address")); + revalidateButtons(); + return; + } + + _isAddressValid = true; + setOK(_ui.groupAddressEdit, _ui.groupAddressMessage); + revalidateButtons(); +} + +void MulticastConfigDialog::validateDataPort(QString const& input) +{ + bool ok; + int p = input.toInt(&ok, 0); + + _isPortValid = false; + + if (!ok) + { + setError(_ui.dataPortEdit, _ui.dataPortMessage, tr("Not a number")); + revalidateButtons(); + return; + } + + if (p < 0) + { + setError(_ui.dataPortEdit, _ui.dataPortMessage, tr("Must be positive")); + revalidateButtons(); + return; + } + + if (p < 1024) + { + setError(_ui.dataPortEdit, _ui.dataPortMessage, tr( + "Must not be a privileged port")); + revalidateButtons(); + return; + } + + if (p > 65535) + { + setError(_ui.dataPortEdit, _ui.dataPortMessage, tr( + "Port number too large")); + revalidateButtons(); + return; + } + + _isPortValid = true; + setOK(_ui.dataPortEdit, _ui.dataPortMessage); + revalidateButtons(); +} + +void MulticastConfigDialog::revalidateButtons() +{ + _ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(_isAddressValid + && _isPortValid); +} diff --git a/src/gui/multicastConfigDialog.h b/src/gui/multicastConfigDialog.h new file mode 100644 index 0000000..6421813 --- /dev/null +++ b/src/gui/multicastConfigDialog.h @@ -0,0 +1,38 @@ +#ifndef MULTICASTCONFIGDIALOG_H +#define MULTICASTCONFIGDIALOG_H + +#include +#include +#include "ui_multicastConfigDialog.h" +#include + +class McastConfiguration; + +class MulticastConfigDialog : public QDialog +{ + Q_OBJECT + +public: + MulticastConfigDialog(QWidget* parent = 0); + MulticastConfigDialog(McastConfiguration* dbusIface, QWidget *parent = 0); + ~MulticastConfigDialog(); + +private: + Ui::MulticastConfigDialogClass _ui; + McastConfiguration* _config; + bool _isAddressValid; + bool _isPortValid; + + void setupUi(); + + void setError(QWidget* input, QLabel* messageLabel, QString text); + void setOK(QWidget* input, QLabel* messageLabel); + void revalidateButtons(); + +private slots: + void dialogAccepted(); + void validateGroupAddress(QString const&); + void validateDataPort(QString const&); +}; + +#endif // MULTICASTCONFIGDIALOG_H diff --git a/src/gui/ui/mainwindow.ui b/src/gui/ui/mainwindow.ui index eb49d1b..7b8f2b4 100644 --- a/src/gui/ui/mainwindow.ui +++ b/src/gui/ui/mainwindow.ui @@ -243,9 +243,16 @@ + + + Network + + + + @@ -531,6 +538,14 @@ - + + + &Configure... + + + Configure Network Parameters + + diff --git a/src/gui/ui/mainwindowtouch.ui b/src/gui/ui/mainwindowtouch.ui index 9030b17..cf7e411 100644 --- a/src/gui/ui/mainwindowtouch.ui +++ b/src/gui/ui/mainwindowtouch.ui @@ -365,6 +365,8 @@ + + @@ -636,6 +638,15 @@ Ctrl+D + + + + :/netconf:/netconf + + + Configure Network... + + diff --git a/src/gui/ui/multicastConfigDialog.ui b/src/gui/ui/multicastConfigDialog.ui new file mode 100644 index 0000000..1ddf02c --- /dev/null +++ b/src/gui/ui/multicastConfigDialog.ui @@ -0,0 +1,156 @@ + + + MulticastConfigDialogClass + + + + 0 + 0 + 331 + 314 + + + + + 0 + 0 + + + + PVS - Multicast Configuration + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You need to specify connection parameters for multicast messaging on your network. These parameters will automatically be distributed to client computers, so you need to assign them only once.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You will probably want to assign an address from the <span style=" text-decoration: underline;">239.0.0.0/8</span> &quot;Administratively Scoped&quot; range.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Do not assign arbitrary numbers without checking with your network administrator!</span></p></td></tr></table></body></html> + + + true + + + + + + + + + Multicast Group Address + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 009.009.009.009; + + + ... + + + + + + + <span style=" font-weight:600; color:#008800;">OK</span> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Data Port (1024-65535) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 00009; + + + 5 + + + + + + + <span style=" font-weight:600; color:#008800;">OK</span> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Transmission Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + KiB/s + + + 10240 + + + 10 + + + 100 + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + diff --git a/src/net/mcast/McastConfiguration.h b/src/net/mcast/McastConfiguration.h index 6884036..53f7a54 100644 --- a/src/net/mcast/McastConfiguration.h +++ b/src/net/mcast/McastConfiguration.h @@ -166,6 +166,23 @@ public: emit changed(); } + McastConfiguration& operator=(McastConfiguration const& source) + { + if(this != &source) + { + _multicastInterface = source._multicastInterface; + _multicastAddress = source._multicastAddress; + _multicastRate = source._multicastRate; + _multicastSPort = source._multicastSPort; + _multicastDPort = source._multicastDPort; + _multicastWinSize = source._multicastWinSize; + _multicastMTU = source._multicastMTU; + _multicastUDPPortBase = source._multicastUDPPortBase; + _multicastUseUDP = source._multicastUseUDP; + } + return *this; + } + void loadFrom(QSettings* settings, char const* group = 0); void writeTo(QSettings* settings, char const* group = 0) const; diff --git a/src/net/pvsListenServer.cpp b/src/net/pvsListenServer.cpp index f21303e..1c1387b 100644 --- a/src/net/pvsListenServer.cpp +++ b/src/net/pvsListenServer.cpp @@ -21,9 +21,13 @@ #include "pvsClientConnection.h" #include "src/util/consoleLogger.h" #include +#include +#include +#include #include "SslServer.h" #include //#define verbose +#include "mcast/McastConfiguration.h" // Create listener PVSListenServer::PVSListenServer(int port, int clients) @@ -36,6 +40,7 @@ PVSListenServer::PVSListenServer(int port, int clients) else _clientsMax = clients; _port = port; + _mcastConfig = 0; init(); } @@ -178,6 +183,7 @@ void PVSListenServer::onClientConnected(PVSClientConnection* connected) { connected->setServerID(_id); connected->setID(generateID()); + connected->push_back_send(mcastConfigMessage()); } void PVSListenServer::onClientDisconnected(PVSClientConnection* disconnected) @@ -227,6 +233,11 @@ PVSClientConnection* PVSListenServer::getConnectionFromID(int id) // Initialize listening socket bool PVSListenServer::init() { + if (_mcastConfig) + delete _mcastConfig; + _mcastConfig = new McastConfiguration(this); + loadMcastConfig(); + if (_listenSocket != NULL) shutdown(); @@ -306,3 +317,52 @@ bool PVSListenServer::isListening() { return _listenSocket != NULL && _listenSocket->isListening(); } + +void PVSListenServer::loadMcastConfig() +{ + QSettings settings; + _mcastConfig->loadFrom(&settings, "multicast-filetransfer"); +} + +void PVSListenServer::saveMcastConfig() +{ + QSettings settings; + _mcastConfig->writeTo(&settings, "multicast-filetransfer"); + settings.sync(); +} + +PVSMsg PVSListenServer::mcastConfigMessage() +{ + // If anything is changed here, do not forget to + // 1. assign a new version number + // 2. adapt PVS::onCommand(PVSMsg) in pvs.cpp + QByteArray ba; + QDataStream strm(&ba, QIODevice::WriteOnly); + strm << (quint16)1 // version + << _mcastConfig->multicastAddress() + << _mcastConfig->multicastUDPPortBase() + << _mcastConfig->multicastDPort() + << _mcastConfig->multicastSPort() + << _mcastConfig->multicastMTU() + << _mcastConfig->multicastWinSize() + << _mcastConfig->multicastRate() + << _mcastConfig->multicastUseUDP(); + + QByteArray b64 = ba.toBase64(); + QString message = QString::fromAscii(b64.constData(), b64.length()); + PVSMsg msg(PVSCOMMAND, "MCASTFTCONFIG", message); + return msg; +} + +void PVSListenServer::multicastReconfigure(McastConfiguration const* source) +{ + _mcastConfig->multicastAddress(source->multicastAddress()); + *_mcastConfig = *source; + saveMcastConfig(); + sendToAll(mcastConfigMessage()); +} + +McastConfiguration const* PVSListenServer::getMulticastConfiguration() +{ + return _mcastConfig; +} diff --git a/src/net/pvsListenServer.h b/src/net/pvsListenServer.h index ab021c7..90d2a77 100644 --- a/src/net/pvsListenServer.h +++ b/src/net/pvsListenServer.h @@ -10,6 +10,7 @@ class SslServer; class PVSClientConnection; class PVSMsg; +class McastConfiguration; class PVSListenServer : public QObject { @@ -40,6 +41,12 @@ private: bool init(); unsigned int generateID(); + McastConfiguration* _mcastConfig; + + void loadMcastConfig(); + void saveMcastConfig(); + PVSMsg mcastConfigMessage(); + protected: void timerEvent(QTimerEvent *event); @@ -60,6 +67,9 @@ public: bool disconnectClient(PVSClientConnection* delinquent); void onConnectionRemoved(PVSClientConnection* delinquent); + void multicastReconfigure(McastConfiguration const* source); + McastConfiguration const* getMulticastConfiguration(); + std::list* getClientListPtr() { return &_clients; diff --git a/src/pvs.cpp b/src/pvs.cpp index 9bd36d6..df21468 100644 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -45,7 +45,10 @@ PVS::PVS() : loadCommands(); _blankScreen = NULL; _vncPort = -1; + + QSettings settings; _masterMcastConfig = new McastConfiguration(this); + _masterMcastConfig->loadFrom(&settings); // add a notify to the allow file, so we get informed when the file is changed QString watchPath("/home/"); @@ -234,6 +237,11 @@ void PVS::onCommand(PVSMsg cmdMessage) qDebug() << "Ignoring malformed MCASTFTANNOUNCE command: " << message; return; } + if (ident.compare("MCASTFTCONFIG") == 0) + { + loadMcastConfig(message); + return; + } #ifdef never // prototype @@ -735,7 +743,8 @@ void PVS::cancelIncomingMulticastTransfer(qulonglong transferID) void PVS::setMulticastInterface(QString const& interfaceName) { QSettings settings; - settings.setValue("multicast/interface", interfaceName); + _masterMcastConfig->multicastInterface(interfaceName); + _masterMcastConfig->writeTo(&settings, "multicast"); settings.sync(); } @@ -814,3 +823,50 @@ void PVS::incomingMulticastTransferDelete(qulonglong transferID) _incomingTransfers.remove(transferID); transfer->deleteLater(); } + +void PVS::loadMcastConfig(QString const& message) +{ + QByteArray ba = QByteArray::fromBase64(message.toAscii()); + QDataStream d(&ba, QIODevice::ReadOnly); + quint16 ver, udpp, dp, sp, mtu, wsz; + quint32 rate; + QString addr; + bool useudp; + + d >> ver; + if(ver != 1) + { + ConsoleLog writeLine(QString("Unable to decode multicast configuration message: Unknown version %1").arg(ver)); + return; + } + + d >> addr + >> udpp + >> dp + >> sp + >> mtu + >> wsz + >> rate + >> useudp; + if(d.status() != QDataStream::Ok) + { + ConsoleLog writeLine(QString("Unable to decode multicast configuration message: There was an error reading")); + return; + } + + _masterMcastConfig->multicastUDPPortBase(udpp); + _masterMcastConfig->multicastDPort(dp); + _masterMcastConfig->multicastSPort(sp); + _masterMcastConfig->multicastMTU(mtu); + _masterMcastConfig->multicastWinSize(wsz); + _masterMcastConfig->multicastRate(rate); + _masterMcastConfig->multicastAddress(addr); + _masterMcastConfig->multicastUseUDP(useudp); + + QSettings settings; + _masterMcastConfig->writeTo(&settings, "multicast"); + settings.sync(); + + ConsoleLog writeLine(QString("Reconfigured multicast filetransfer to IP %1, UDP port base %2, destination port %3, source port %4, MTU %5, Window Size %6, rate %7, %8using UDP") + .arg(addr).arg(udpp).arg(dp).arg(sp).arg(mtu).arg(wsz).arg(rate).arg(useudp ? "" : "not ")); +} diff --git a/src/pvs.h b/src/pvs.h index 4c61ffd..3b3365c 100644 --- a/src/pvs.h +++ b/src/pvs.h @@ -88,6 +88,7 @@ public Q_SLOTS: void cancelOutgoingMulticastTransfer(quint64 transferID); void cancelIncomingMulticastTransfer(qulonglong transferID); void setMulticastInterface(QString const& interfaceName); + void loadMcastConfig(QString const& encoded); Q_SIGNALS: void project(QString host, int port, QString passwd, bool fullscreen, -- cgit v1.2.3-55-g7522