diff --git a/README.md b/README.md index a78174d..2d646f0 100644 --- a/README.md +++ b/README.md @@ -107,4 +107,12 @@ qDebug() << zcs->txt["Qt"]; Qt5 -On Linux, libavahi-client-dev and libavahi-common-dev \ No newline at end of file +On Linux, libavahi-client-dev and libavahi-common-dev + +### Apple App Store deployment + +Publishing GPL software in the App Store is a [violation of the GPL](https://news.ycombinator.com/item?id=3488833). If you need to publish an app in the Apple App Store that uses QZeroConf, please contact me for a copy of QZeroConf with a BSD licence. + +### iOS device sleep + +When iOS puts the device to sleep, it breaks the DNS-SD browser and service publisher. The only way around this is to call stopServicePublish() and stopBrowser() when the application state changes to Qt::ApplicationSuspended (sleep) and then call startPublish() and startBrowser() when the application state changes to Qt::ApplicationActive (wake). See appStateChanged() in example. diff --git a/avahiclient.cpp b/avahiclient.cpp index 589be89..c755aaf 100644 --- a/avahiclient.cpp +++ b/avahiclient.cpp @@ -207,6 +207,12 @@ public: avahi_service_browser_free(browser); browser = NULL; + QMap::iterator i; + for (i = pub->services.begin(); i != pub->services.end(); i++) { + emit pub->serviceRemoved(i.value()); + + } + pub->services.clear(); QMap::iterator r; @@ -227,6 +233,7 @@ public: }; + QZeroConf::QZeroConf(QObject *parent) : QObject(parent) { pri = new QZeroConfPrivate(this); @@ -266,6 +273,14 @@ void QZeroConf::stopServicePublish(void) } } +bool QZeroConf::publishExists(void) +{ + if (pri->group) + return true; + else + return false; +} + // http://www.zeroconf.org/rendezvous/txtrecords.html void QZeroConf::addServiceTxtRecord(QString nameOnly) @@ -309,3 +324,11 @@ void QZeroConf::stopBrowser(void) { pri->broswerCleanUp(); } + +bool QZeroConf::browserExists(void) +{ + if (pri->browser) + return true; + else + return false; +} diff --git a/avahicore.cpp b/avahicore.cpp index c9536cf..091514b 100644 --- a/avahicore.cpp +++ b/avahicore.cpp @@ -220,8 +220,10 @@ public: browser = NULL; QMap::iterator i; - for (i = pub->services.begin(); i != pub->services.end(); i++) + for (i = pub->services.begin(); i != pub->services.end(); i++) { + emit pub->serviceRemoved(*i); delete *i; + } pub->services.clear(); QMap::iterator r; @@ -269,7 +271,7 @@ public: }; -QZeroConf::QZeroConf() +QZeroConf::QZeroConf(QObject *parent) : QObject (parent) { pri = new QZeroConfPrivate(this); } @@ -309,6 +311,14 @@ void QZeroConf::stopServicePublish(void) } } +bool QZeroConf::publishExists(void) +{ + if (pri->group) + return true; + else + return false; +} + // http://www.zeroconf.org/rendezvous/txtrecords.html void QZeroConf::addServiceTxtRecord(QString nameOnly) @@ -352,3 +362,11 @@ void QZeroConf::stopBrowser(void) { pri->broswerCleanUp(); } + +bool QZeroConf::browserExists(void) +{ + if (pri->browser) + return true; + else + return false; +} diff --git a/bonjour.cpp b/bonjour.cpp index 9076eb3..041b974 100644 --- a/bonjour.cpp +++ b/bonjour.cpp @@ -245,6 +245,12 @@ void QZeroConfPrivate::cleanUp(DNSServiceRef toClean) delete browserSocket; browserSocket = NULL; } + + QMap::iterator i; + for (i = pub->services.begin(); i != pub->services.end(); i++) { + emit pub->serviceRemoved(*i); + } + pub->services.clear(); } else if (toClean == dnssRef) { @@ -311,6 +317,14 @@ void QZeroConf::stopServicePublish(void) pri->cleanUp(pri->dnssRef); } +bool QZeroConf::publishExists(void) +{ + if (pri->dnssRef) + return true; + else + return false; +} + void QZeroConf::addServiceTxtRecord(QString nameOnly) { pri->txt.append((quint8) nameOnly.size()); @@ -367,3 +381,11 @@ void QZeroConf::stopBrowser(void) { pri->cleanUp(pri->browser); } + +bool QZeroConf::browserExists(void) +{ + if (pri->browser) + return true; + else + return false; +} diff --git a/example/window.cpp b/example/window.cpp index df73dde..cc10272 100644 --- a/example/window.cpp +++ b/example/window.cpp @@ -24,6 +24,7 @@ Example app to demonstrate service publishing and service discovery --------------------------------------------------------------------------------------------------- **************************************************************************************************/ +#include #include #include #include @@ -52,11 +53,13 @@ mainWindow::mainWindow() publishEnabled = 0; buildGUI(); - connect(&zeroConf, SIGNAL(serviceAdded(QZeroConfService )), this, SLOT(addService(QZeroConfService ))); - connect(&zeroConf, SIGNAL(serviceRemoved(QZeroConfService )), this, SLOT(removeService(QZeroConfService ))); - zeroConf.startBrowser("_qtzeroconf_test._tcp"); - startPublish(); + connect(&zeroConf, &QZeroConf::serviceAdded, this, &mainWindow::addService); + connect(&zeroConf, &QZeroConf::serviceRemoved, this, &mainWindow::removeService); + connect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(appStateChanged(Qt::ApplicationState))); + + publishEnabled = 1; + } void mainWindow::buildGUI() @@ -68,13 +71,13 @@ void mainWindow::buildGUI() button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); layout->addWidget(button); layout->setAlignment(button, Qt::AlignHCenter); - connect(button, SIGNAL(clicked()), this, SLOT(startPublish())); + connect(button, &QPushButton::clicked, this, &mainWindow::startPublishClicked); button = new QPushButton(tr(" Disable Publish ")); button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); layout->addWidget(button); layout->setAlignment(button, Qt::AlignHCenter); - connect(button, SIGNAL(clicked()), this, SLOT(stopPublish())); + connect(button, &QPushButton::clicked, this, &mainWindow::stopPublishClicked); table.verticalHeader()->hide(); table.horizontalHeader()->hide(); @@ -102,21 +105,39 @@ QString mainWindow::buildName(void) return name; } +void mainWindow::appStateChanged(Qt::ApplicationState state) +{ + if (state == Qt::ApplicationSuspended) { + zeroConf.stopServicePublish(); + zeroConf.stopBrowser(); + } + else if (state == Qt::ApplicationActive) { + if (publishEnabled && !zeroConf.publishExists()) + startPublish(); + if (!zeroConf.browserExists()) + zeroConf.startBrowser("_qtzeroconf_test._tcp"); + } +} + // ---------- Service Publish ---------- void mainWindow::startPublish() { - if (publishEnabled) - return; - publishEnabled = 1; - zeroConf.clearServiceTxtRecords(); zeroConf.addServiceTxtRecord("Qt", "the best!"); zeroConf.addServiceTxtRecord("ZeroConf is nice too"); zeroConf.startServicePublish(buildName().toUtf8(), "_qtzeroconf_test._tcp", "local", 11437); } -void mainWindow::stopPublish() +void mainWindow::startPublishClicked() +{ + if (publishEnabled) + return; + publishEnabled = 1; + startPublish(); +} + +void mainWindow::stopPublishClicked() { if (!publishEnabled) return; diff --git a/example/window.h b/example/window.h index f99bfdf..d7f61d6 100644 --- a/example/window.h +++ b/example/window.h @@ -40,16 +40,20 @@ public: private: void buildGUI(); + void startPublish(); QString buildName(void); QTableWidget table; QZeroConf zeroConf; bool publishEnabled; private slots: - void startPublish(); - void stopPublish(); + + void appStateChanged(Qt::ApplicationState state); + void startPublishClicked(); + void stopPublishClicked(); void addService(QZeroConfService item); void removeService(QZeroConfService item); + }; #endif /* WINDOW_H_ */ diff --git a/qzeroconf.h b/qzeroconf.h index 3ccb4c8..d64fa40 100644 --- a/qzeroconf.h +++ b/qzeroconf.h @@ -64,12 +64,14 @@ public: ~QZeroConf(); void startServicePublish(const char *name, const char *type, const char *domain, quint16 port); void stopServicePublish(void); + bool publishExists(void); inline void startBrowser(QString type) { startBrowser(type, QAbstractSocket::IPv4Protocol); } void startBrowser(QString type, QAbstractSocket::NetworkLayerProtocol protocol); void stopBrowser(void); + bool browserExists(void); void addServiceTxtRecord(QString nameOnly); void addServiceTxtRecord(QString name, QString value); void clearServiceTxtRecords(); diff --git a/qzeroconfservice.cpp b/qzeroconfservice.cpp index 3a8b39e..c17dae7 100644 --- a/qzeroconfservice.cpp +++ b/qzeroconfservice.cpp @@ -141,7 +141,7 @@ bool QZeroConfService::isValid() const bool QZeroConfService::operator==(const QZeroConfService &rhs) const { - return this->name() == rhs.name() && this->ip() == rhs.ip() && this->ipv6() == rhs.ipv6(); + return this->name() == rhs.name() && (this->ip() == rhs.ip() || this->ipv6() == rhs.ipv6()); }