From 348f15ac48dc33fc756e63bf04d0b4a22fdb23a4 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Fri, 1 Jun 2018 01:55:44 +0200 Subject: [PATCH] switch to a different avahi lib which also works on android --- .gitignore | 2 + .gitmodules | 6 + QtZeroConf | 1 + README.md | 7 +- .../discovery/avahi/avahiserviceentry.cpp | 171 ------------- .../discovery/avahi/avahiserviceentry.h | 75 ------ libmea-core/discovery/avahi/qt-watch.cpp | 193 --------------- libmea-core/discovery/avahi/qt-watch.h | 35 --- libmea-core/discovery/avahi/qtavahiclient.cpp | 121 --------- libmea-core/discovery/avahi/qtavahiclient.h | 73 ------ .../discovery/avahi/qtavahiservice.cpp | 229 ------------------ libmea-core/discovery/avahi/qtavahiservice.h | 80 ------ .../discovery/avahi/qtavahiservice_p.cpp | 81 ------- .../discovery/avahi/qtavahiservice_p.h | 56 ----- .../discovery/avahi/qtavahiservicebrowser.cpp | 94 ------- .../discovery/avahi/qtavahiservicebrowser.h | 63 ----- .../avahi/qtavahiservicebrowser_p.cpp | 218 ----------------- .../discovery/avahi/qtavahiservicebrowser_p.h | 82 ------- libmea-core/discovery/zeroconfdiscovery.cpp | 52 ++-- libmea-core/discovery/zeroconfdiscovery.h | 13 +- libmea-core/jsonrpc/jsonrpcclient.cpp | 12 +- libmea-core/libmea-core.pro | 32 +-- libmea-core/tcpsocketinterface.cpp | 5 +- mea/ui/ConnectPage.qml | 11 +- 24 files changed, 84 insertions(+), 1628 deletions(-) create mode 100644 .gitmodules create mode 160000 QtZeroConf delete mode 100644 libmea-core/discovery/avahi/avahiserviceentry.cpp delete mode 100644 libmea-core/discovery/avahi/avahiserviceentry.h delete mode 100644 libmea-core/discovery/avahi/qt-watch.cpp delete mode 100644 libmea-core/discovery/avahi/qt-watch.h delete mode 100644 libmea-core/discovery/avahi/qtavahiclient.cpp delete mode 100644 libmea-core/discovery/avahi/qtavahiclient.h delete mode 100644 libmea-core/discovery/avahi/qtavahiservice.cpp delete mode 100644 libmea-core/discovery/avahi/qtavahiservice.h delete mode 100644 libmea-core/discovery/avahi/qtavahiservice_p.cpp delete mode 100644 libmea-core/discovery/avahi/qtavahiservice_p.h delete mode 100644 libmea-core/discovery/avahi/qtavahiservicebrowser.cpp delete mode 100644 libmea-core/discovery/avahi/qtavahiservicebrowser.h delete mode 100644 libmea-core/discovery/avahi/qtavahiservicebrowser_p.cpp delete mode 100644 libmea-core/discovery/avahi/qtavahiservicebrowser_p.h diff --git a/.gitignore b/.gitignore index fab7372d..e34d5e33 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,5 @@ Thumbs.db *.dll *.exe +# Android generated files +local.properties diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..81790a01 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "-f"] + path = -f + url = https://github.com/mzanetti/QtZeroConf.git +[submodule "QtZeroConf"] + path = QtZeroConf + url = https://github.com/jbagg/QtZeroConf.git diff --git a/QtZeroConf b/QtZeroConf new file mode 160000 index 00000000..31119114 --- /dev/null +++ b/QtZeroConf @@ -0,0 +1 @@ +Subproject commit 31119114cec29b890bc755bed0272a208b7130bf diff --git a/README.md b/README.md index c37b761b..d69dd5ed 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,11 @@ Required packages: It is recommended to install a complete Qt installation. Minimum required Version 5.7. No extra modules are required for a basic desktop build. +After cloning the repository, run + +$ git submodule init +$ git submodule update + To build a binary run $ mkdir builddir $ cd builddir @@ -16,8 +21,6 @@ $ make Or open mea.pro in QtCreator and click the "Play" button. Optional configuration flags to be passed to qmake: -- CONFIG+=withavahi - Enables avahi support. Requires libavahi-common and libavahi-client to be present on the system - CONFIG+=withtests Enables building the testrunner target diff --git a/libmea-core/discovery/avahi/avahiserviceentry.cpp b/libmea-core/discovery/avahi/avahiserviceentry.cpp deleted file mode 100644 index 9015faa8..00000000 --- a/libmea-core/discovery/avahi/avahiserviceentry.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "avahiserviceentry.h" - -/*! Constructs an empty invalid \l{AvahiServiceEntry}*/ -AvahiServiceEntry::AvahiServiceEntry() : - m_port(0), - m_protocol(QAbstractSocket::UnknownNetworkLayerProtocol) -{ - -} - - -/*! Constructs a new \l{AvahiServiceEntry} with the given \a name, \a serviceType, \a hostAddress, \a domain, \a hostName, \a port, \a protocol, \a txt and \a flags.*/ -AvahiServiceEntry::AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags) : - m_name(name), - m_serviceType(serviceType), - m_hostAddress(hostAddress), - m_domain(domain), - m_hostName(hostName), - m_port(port), - m_protocol(protocol), - m_txt(txt), - m_flags(flags) -{ - -} - -/*! Returns the name of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::name() const -{ - return m_name; -} - -/*! Returns the service type of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::serviceType() const -{ - return m_serviceType; -} - -/*! Returns the host address of this \l{AvahiServiceEntry}.*/ -QHostAddress AvahiServiceEntry::hostAddress() const -{ - return m_hostAddress; -} - -/*! Returns the domain of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::domain() const -{ - return m_domain; -} - -/*! Returns the host name of this \l{AvahiServiceEntry}.*/ -QString AvahiServiceEntry::hostName() const -{ - return m_hostName; -} - -/*! Returns the port of this \l{AvahiServiceEntry}.*/ -quint16 AvahiServiceEntry::port() const -{ - return m_port; -} - -/*! Returns the network protocol of this \l{AvahiServiceEntry}.*/ -QAbstractSocket::NetworkLayerProtocol AvahiServiceEntry::protocol() const -{ - return m_protocol; -} - -/*! Returns the avahi flags of this \l{AvahiServiceEntry}.*/ -AvahiLookupResultFlags AvahiServiceEntry::flags() const -{ - return m_flags; -} - -/*! Returns the txt string list of this \l{AvahiServiceEntry}.*/ -QStringList AvahiServiceEntry::txt() const -{ - return m_txt; -} - -/*! Returns true if this \l{AvahiServiceEntry} is valid.*/ -bool AvahiServiceEntry::isValid() const -{ - return !m_hostAddress.isNull() && !m_hostName.isEmpty() && m_port != 0 && m_protocol != QAbstractSocket::UnknownNetworkLayerProtocol; -} - -/*! Returns true if this \l{AvahiServiceEntry} is cached.*/ -bool AvahiServiceEntry::isChached() const -{ - return m_flags & AVAHI_LOOKUP_RESULT_CACHED; -} - -/*! Returns true if this \l{AvahiServiceEntry} was found in the wide area.*/ -bool AvahiServiceEntry::isWideArea() const -{ - return m_flags & AVAHI_LOOKUP_RESULT_WIDE_AREA; -} - -/*! Returns true if this \l{AvahiServiceEntry} is a multicast service.*/ -bool AvahiServiceEntry::isMulticast() const -{ - return m_flags & AVAHI_LOOKUP_RESULT_MULTICAST; -} - -/*! Returns true if this \l{AvahiServiceEntry} was found local.*/ -bool AvahiServiceEntry::isLocal() const -{ - return m_flags & AVAHI_LOOKUP_RESULT_LOCAL; -} - -/*! Returns true if this \l{AvahiServiceEntry} is our own service.*/ -bool AvahiServiceEntry::isOurOwn() const -{ - return m_flags & AVAHI_LOOKUP_RESULT_OUR_OWN; -} - -/*! Returns true if this \l{AvahiServiceEntry} is equal to \a other; otherwise returns false.*/ -bool AvahiServiceEntry::operator ==(const AvahiServiceEntry &other) const -{ - return other.name() == m_name && - other.serviceType() == m_serviceType && - other.hostAddress() == m_hostAddress && - other.domain() == m_domain && - other.hostName() == m_hostName && - other.port() == m_port && - other.protocol() == m_protocol && - other.flags() == m_flags && - other.txt() == m_txt; -} - -/*! Returns true if this \l{AvahiServiceEntry} is not equal to \a other; otherwise returns false.*/ -bool AvahiServiceEntry::operator !=(const AvahiServiceEntry &other) const -{ - return !operator==(other); -} - -/*! Writes the given \a entry to the specified \a dbg.*/ -QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry) -{ - dbg.nospace() << "AvahiServiceEntry("; - dbg << entry.name() << ")" << endl; - dbg << " location: " << entry.hostAddress().toString() << ":" << entry.port() << endl; - dbg << " hostname: " << entry.hostName() << endl; - dbg << " domain: " << entry.domain() << endl; - dbg << "service type: " << entry.serviceType() << endl; - dbg << " protocol: " << entry.protocol() << endl; - dbg << " txt: " << entry.txt() << endl; - return dbg; -} diff --git a/libmea-core/discovery/avahi/avahiserviceentry.h b/libmea-core/discovery/avahi/avahiserviceentry.h deleted file mode 100644 index 6321931c..00000000 --- a/libmea-core/discovery/avahi/avahiserviceentry.h +++ /dev/null @@ -1,75 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef AVAHISERVICEENTRY_H -#define AVAHISERVICEENTRY_H - -#include -#include -#include -#include -#include - -class AvahiServiceEntry -{ -public: - AvahiServiceEntry(); - AvahiServiceEntry(QString name, QString serviceType, QHostAddress hostAddress, QString domain, QString hostName, quint16 port, QAbstractSocket::NetworkLayerProtocol protocol, QStringList txt, AvahiLookupResultFlags flags); - - QString name() const; - QString serviceType() const; - QHostAddress hostAddress() const; - QString domain() const; - QString hostName() const; - quint16 port() const; - QAbstractSocket::NetworkLayerProtocol protocol() const; - AvahiLookupResultFlags flags() const; - QStringList txt() const; - - bool isValid() const; - - bool isChached() const; - bool isWideArea() const; - bool isMulticast() const; - bool isLocal() const; - bool isOurOwn() const; - - bool operator ==(const AvahiServiceEntry &other) const; - bool operator !=(const AvahiServiceEntry &other) const; - -private: - QString m_name; - QString m_serviceType; - QHostAddress m_hostAddress; - QString m_domain; - QString m_hostName; - quint16 m_port; - QAbstractSocket::NetworkLayerProtocol m_protocol; - QStringList m_txt; - AvahiLookupResultFlags m_flags; - -}; - -QDebug operator <<(QDebug dbg, const AvahiServiceEntry &entry); -Q_DECLARE_METATYPE(AvahiServiceEntry) - -#endif // AVAHISERVICEENTRY_H diff --git a/libmea-core/discovery/avahi/qt-watch.cpp b/libmea-core/discovery/avahi/qt-watch.cpp deleted file mode 100644 index 6bca5789..00000000 --- a/libmea-core/discovery/avahi/qt-watch.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/*** - This file is part of avahi. - - avahi is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - avahi is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with avahi; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. - - Modified: (C) 2016 Simon Stürz - -***/ - -#include -#include -#include - -#include -#include - -#include "qt-watch.h" - -class AvahiWatch : public QObject -{ - Q_OBJECT -public: - AvahiWatch(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void* userdata); - ~AvahiWatch() { } - AvahiWatchEvent getEvents() const { return m_incallback ? m_lastEvent : (AvahiWatchEvent)0; } - void setWatchedEvents(AvahiWatchEvent event); - -private slots: - void gotIn(); - void gotOut(); - -private: - QSocketNotifier* m_in; - QSocketNotifier* m_out; - AvahiWatchCallback m_callback; - AvahiWatchEvent m_lastEvent; - int m_fd; - void* m_userdata; - bool m_incallback; -}; - -class AvahiTimeout : public QObject -{ - Q_OBJECT - -public: - AvahiTimeout(const struct timeval* tv, AvahiTimeoutCallback callback, void* userdata); - ~AvahiTimeout() {} - void update(const struct timeval* tv); - -private slots: - void timeout(); - -private: - QTimer m_timer; - AvahiTimeoutCallback m_callback; - void* m_userdata; -}; - - - -AvahiWatch::AvahiWatch(int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void* userdata) : - m_in(0), - m_out(0), - m_callback(callback), - m_fd(fd), - m_userdata(userdata), - m_incallback(false) -{ - setWatchedEvents(event); -} - -void AvahiWatch::gotIn() -{ - m_lastEvent = AVAHI_WATCH_IN; - m_incallback = true; - m_callback(this, m_fd, m_lastEvent, m_userdata); - m_incallback = false; -} - -void AvahiWatch::gotOut() -{ - m_lastEvent = AVAHI_WATCH_OUT; - m_incallback = true; - m_callback(this, m_fd, m_lastEvent, m_userdata); - m_incallback = false; -} - -void AvahiWatch::setWatchedEvents(AvahiWatchEvent event) -{ - if (!(event & AVAHI_WATCH_IN)) { delete m_in; m_in = 0; } - if (!(event & AVAHI_WATCH_OUT)) { delete m_out; m_out = 0; } - if (event & AVAHI_WATCH_IN) { - m_in = new QSocketNotifier(m_fd,QSocketNotifier::Read, this); - connect(m_in, SIGNAL(activated(int)), SLOT(gotIn())); - } - if (event & AVAHI_WATCH_OUT) { - m_out = new QSocketNotifier(m_fd, QSocketNotifier::Write, this); - connect(m_out, SIGNAL(activated(int)), SLOT(gotOut())); - } -} - -AvahiTimeout::AvahiTimeout(const struct timeval* tv, AvahiTimeoutCallback callback, void *userdata) : - m_callback(callback), - m_userdata(userdata) -{ - connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout())); - m_timer.setSingleShot(true); - update(tv); -} - -void AvahiTimeout::update(const struct timeval *tv) -{ - m_timer.stop(); - if (tv) { - AvahiUsec u = avahi_age(tv)/1000; - m_timer.start( (u>0) ? 0 : -u); - } -} - -void AvahiTimeout::timeout() -{ - m_callback(this, m_userdata); -} - -static AvahiWatch* q_watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) -{ - Q_UNUSED(api) - return new AvahiWatch(fd, event, callback, userdata); -} - -static void q_watch_update(AvahiWatch *w, AvahiWatchEvent events) -{ - w->setWatchedEvents(events); -} - -static AvahiWatchEvent q_watch_get_events(AvahiWatch *w) -{ - return w->getEvents(); -} - -static void q_watch_free(AvahiWatch *w) -{ - delete w; -} - -static AvahiTimeout* q_timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) -{ - Q_UNUSED(api) - return new AvahiTimeout(tv, callback, userdata); -} - -static void q_timeout_update(AvahiTimeout *t, const struct timeval *tv) -{ - t->update(tv); -} - -static void q_timeout_free(AvahiTimeout *t) -{ - delete t; -} - -const AvahiPoll* avahi_qt_poll_get(void) -{ - static const AvahiPoll qt_poll = { - NULL, - q_watch_new, - q_watch_update, - q_watch_get_events, - q_watch_free, - q_timeout_new, - q_timeout_update, - q_timeout_free - }; - - return &qt_poll; -} - -#include "qt-watch.moc" - diff --git a/libmea-core/discovery/avahi/qt-watch.h b/libmea-core/discovery/avahi/qt-watch.h deleted file mode 100644 index ea5c1fc5..00000000 --- a/libmea-core/discovery/avahi/qt-watch.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef QAVAHI_H -#define QAVAHI_H - -/*** - This file is part of avahi. - - avahi is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - avahi is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with avahi; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. - - Modified: (C) 2016 Simon Stürz - -***/ - -/** \file qt-watch.h Qt main loop adapter */ - -#include - -AVAHI_C_DECL_BEGIN - -/** Setup abstract poll structure for integration with Qt main loop */ -const AvahiPoll* avahi_qt_poll_get(void); - -AVAHI_C_DECL_END - -#endif // QAVAHI_H diff --git a/libmea-core/discovery/avahi/qtavahiclient.cpp b/libmea-core/discovery/avahi/qtavahiclient.cpp deleted file mode 100644 index 52527b75..00000000 --- a/libmea-core/discovery/avahi/qtavahiclient.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qt-watch.h" -#include "qtavahiclient.h" - -#include - -QtAvahiClient::QtAvahiClient(QObject *parent) : - QObject(parent), - poll(avahi_qt_poll_get()), - client(0), - error(0), - m_state(QtAvahiClientStateNone) -{ - connect(this, &QtAvahiClient::clientStateChangedInternal, this, &QtAvahiClient::onClientStateChanged); -} - -QtAvahiClient::~QtAvahiClient() -{ - if (client) - avahi_client_free(client); - -} - -QtAvahiClient::QtAvahiClientState QtAvahiClient::state() const -{ - return m_state; -} - -void QtAvahiClient::start() -{ - if (client) - return; - - avahi_client_new(poll, (AvahiClientFlags) 0, QtAvahiClient::callback, this, &error); -} - -QString QtAvahiClient::errorString() const -{ - return QString(avahi_strerror(error)); -} - -void QtAvahiClient::callback(AvahiClient *client, AvahiClientState state, void *userdata) -{ - QtAvahiClient *serviceClient = static_cast(userdata); - if (!serviceClient) - return; - - serviceClient->client = client; - - switch (state) { - case AVAHI_CLIENT_S_RUNNING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateRunning); - break; - case AVAHI_CLIENT_FAILURE: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateFailure); - break; - case AVAHI_CLIENT_S_COLLISION: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateCollision); - break; - case AVAHI_CLIENT_S_REGISTERING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateRegistering); - break; - case AVAHI_CLIENT_CONNECTING: - emit serviceClient->clientStateChangedInternal(QtAvahiClientStateConnecting); - break; - } -} - -void QtAvahiClient::onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state) -{ - if (m_state == state) - return; - - m_state = state; - -// switch (m_state) { -// case QtAvahiClientStateNone: -// break; -// case QtAvahiClientStateRunning: -// qCDebug(dcAvahi()) << "Client running."; -// break; -// case QtAvahiClientStateFailure: -// qCWarning(dcAvahi()) << "Client failure:" << errorString(); -// break; -// case QtAvahiClientStateCollision: -// qCWarning(dcAvahi()) << "Client collision:" << errorString(); -// break; -// case QtAvahiClientStateRegistering: -// qCDebug(dcAvahi()) << "Client registering..."; -// break; -// case QtAvahiClientStateConnecting: -// qCDebug(dcAvahi()) << "Client connecting..."; -// break; -// default: -// break; -// } - - emit clientStateChanged(m_state); -} - diff --git a/libmea-core/discovery/avahi/qtavahiclient.h b/libmea-core/discovery/avahi/qtavahiclient.h deleted file mode 100644 index df6d6d27..00000000 --- a/libmea-core/discovery/avahi/qtavahiclient.h +++ /dev/null @@ -1,73 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHICLIENT_H -#define QTAVAHICLIENT_H - -#include -#include - -class QtAvahiClient : public QObject -{ - Q_OBJECT - Q_ENUMS(QtAvahiClientState) - -public: - enum QtAvahiClientState { - QtAvahiClientStateNone, - QtAvahiClientStateRunning, - QtAvahiClientStateFailure, - QtAvahiClientStateCollision, - QtAvahiClientStateRegistering, - QtAvahiClientStateConnecting - }; - - explicit QtAvahiClient(QObject *parent = 0); - ~QtAvahiClient(); - - QtAvahiClientState state() const; - -private: - friend class QtAvahiService; - friend class QtAvahiServiceBrowser; - friend class QtAvahiServiceBrowserPrivate; - - const AvahiPoll *poll; - AvahiClient *client; - int error; - QtAvahiClientState m_state; - - void start(); - QString errorString() const; - - static void callback(AvahiClient *client, AvahiClientState state, void *userdata); - -private slots: - void onClientStateChanged(const QtAvahiClientState &state); - -signals: - void clientStateChanged(const QtAvahiClientState &state); - void clientStateChangedInternal(const QtAvahiClientState &state); - -}; - -#endif // QTAVAHICLIENT_H diff --git a/libmea-core/discovery/avahi/qtavahiservice.cpp b/libmea-core/discovery/avahi/qtavahiservice.cpp deleted file mode 100644 index 10e19464..00000000 --- a/libmea-core/discovery/avahi/qtavahiservice.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -/*! \enum QtAvahiService::QtAvahiServiceState - - This enum type specifies the state of a \l{QtAvahiService}. - - \value QtAvahiServiceStateUncomitted - The group has not yet been commited, the user must still call avahi_entry_group_commit(). - \value QtAvahiServiceStateRegistering - The entries of the group are currently being registered. - \value QtAvahiServiceStateEstablished - The entries have successfully been established. - \value QtAvahiServiceStateCollision - A name collision for one of the entries in the group has been detected, the entries have been withdrawn. - \value QtAvahiServiceStateFailure - Some kind of failure happened, the entries have been withdrawn. - -*/ - -/*! \fn void QtAvahiService::serviceStateChanged(const QtAvahiServiceState &state); - This signal will be emitted when the \a state of this \l{QtAvahiService} has changed. -*/ - -#include "qtavahiservice.h" -#include "qtavahiservice_p.h" -#include - - -/*! Constructs a new \l{QtAvahiService} with the given \a parent. */ -QtAvahiService::QtAvahiService(QObject *parent) : - QObject(parent), - d_ptr(new QtAvahiServicePrivate), - m_state(QtAvahiServiceStateUncomitted) -{ - connect(this, &QtAvahiService::serviceStateChanged, this, &QtAvahiService::onStateChanged); - - d_ptr->client = new QtAvahiClient(this); - d_ptr->client->start(); -} - -/*! Destructs this \l{QtAvahiService}. */ -QtAvahiService::~QtAvahiService() -{ - if (d_ptr->group) - avahi_entry_group_free(d_ptr->group); - - delete d_ptr; -} - -/*! Returns the port of this \l{QtAvahiService}. */ -quint16 QtAvahiService::port() const -{ - return d_ptr->port; -} - -/*! Returns the name of this \l{QtAvahiService}. */ -QString QtAvahiService::name() const -{ - return d_ptr->name; -} - -/*! Returns the service type of this \l{QtAvahiService}. */ -QString QtAvahiService::serviceType() const -{ - return d_ptr->type; -} - -QHash QtAvahiService::txtRecords() const -{ - return d_ptr->txtRecords; -} - -QtAvahiService::QtAvahiServiceState QtAvahiService::state() const -{ - return m_state; -} - -/*! Register a new \l{QtAvahiService} with the given \a name and \a port. The service type can be specified with the \a serviceType string. The \a txtRecords records inform about additional information. Returns true if the service could be registered. */ -bool QtAvahiService::registerService(const QString &name, const quint16 &port, const QString &serviceType, const QHash &txtRecords) -{ - // Check if the client is running - if (!d_ptr->client->client || AVAHI_CLIENT_S_RUNNING != avahi_client_get_state(d_ptr->client->client)) { - qWarning() << "Could not register service" << name << port << serviceType << ". The client is not available."; - return false; - } - - d_ptr->name = name; - d_ptr->port = port; - d_ptr->type = serviceType; - d_ptr->txtRecords = txtRecords; - - // If the group is not set yet, create it - if (!d_ptr->group) - d_ptr->group = avahi_entry_group_new(d_ptr->client->client, QtAvahiServicePrivate::callback, this); - - // If the group is empty - if (avahi_entry_group_is_empty(d_ptr->group)) { - // Add the service - d_ptr->error = avahi_entry_group_add_service_strlst(d_ptr->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - (AvahiPublishFlags) 0, - d_ptr->name.toLatin1().data(), - d_ptr->type.toLatin1().data(), - 0, - 0, - (uint16_t)d_ptr->port, - QtAvahiServicePrivate::createTxtList(txtRecords)); - - // Verify if the group has to be comitted - if (d_ptr->error) { - - if (d_ptr->error == AVAHI_ERR_COLLISION) { - if (!handlCollision()) { - qWarning() << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - - - } else { - qWarning() << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - } - - // Commit the service - d_ptr->error = avahi_entry_group_commit(d_ptr->group); - if (d_ptr->error) { - qWarning() << this << "error:" << avahi_strerror(d_ptr->error); - return false; - } - } else { - qWarning() << "Service already registered. Please reset the service before reusing it."; - return false; - } - - return true; -} - -/*! Remove this service from the local network. This \l{QtAvahiService} can be reused to register a new avahi service. */ -void QtAvahiService::resetService() -{ - if (!d_ptr->group) - return; - - avahi_entry_group_reset(d_ptr->group); -} - -/*! Returns true if the service group was added and commited to the network without errors. */ -bool QtAvahiService::isValid() const -{ - return (d_ptr->group && !d_ptr->error); -} - -/*! Returns the error string of this \l{QtAvahiService}. */ -QString QtAvahiService::errorString() const -{ - if (!d_ptr->client->client) - return "Invalid client."; - - return avahi_strerror(avahi_client_errno(d_ptr->client->client)); -} - -bool QtAvahiService::handlCollision() -{ - QString alternativeServiceName = avahi_alternative_service_name(name().toStdString().data()); - qDebug() << "Service name colision. Picking alternative service name" << alternativeServiceName; - - resetService(); - return registerService(alternativeServiceName, port(), serviceType(), txtRecords()); -} - -void QtAvahiService::onStateChanged(const QtAvahiServiceState &state) -{ - if (m_state == state) - return; - - m_state = state; - - switch (m_state) { - case QtAvahiServiceStateUncomitted: - qDebug() << this << "state changed: uncomitted"; - break; - case QtAvahiServiceStateRegistering: - qDebug() << this << "state changed: registering..."; - break; - case QtAvahiServiceStateEstablished: - qDebug() << this << "state changed: established"; - break; - case QtAvahiServiceStateCollision: - qDebug() << this << "state changed: collision"; - handlCollision(); - break; - case QtAvahiServiceStateFailure: - qWarning() << this << "failure: " << errorString(); - break; - default: - break; - } - -} - -QDebug operator <<(QDebug dbg, QtAvahiService *service) -{ - dbg.nospace() << "AvahiService("; - dbg << service->name() << ", " << service->serviceType() << ", " << service->port() << ") "; - return dbg; -} diff --git a/libmea-core/discovery/avahi/qtavahiservice.h b/libmea-core/discovery/avahi/qtavahiservice.h deleted file mode 100644 index 051fbb5d..00000000 --- a/libmea-core/discovery/avahi/qtavahiservice.h +++ /dev/null @@ -1,80 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICE_H -#define QTAVAHISERVICE_H - -#include -#include -#include - -class QtAvahiServicePrivate; - -class QtAvahiService : public QObject -{ - Q_OBJECT - Q_ENUMS(QtAvahiServiceState) - -public: - enum QtAvahiServiceState { - QtAvahiServiceStateUncomitted = 0, - QtAvahiServiceStateRegistering = 1, - QtAvahiServiceStateEstablished = 2, - QtAvahiServiceStateCollision = 3, - QtAvahiServiceStateFailure = 4 - }; - - explicit QtAvahiService(QObject *parent = 0); - ~QtAvahiService(); - - quint16 port() const; - QString name() const; - QString serviceType() const; - QHash txtRecords() const; - QtAvahiServiceState state() const; - - bool registerService(const QString &name, const quint16 &port, const QString &serviceType = "_http._tcp", const QHash &txtRecords = QHash()); - void resetService(); - - bool isValid() const; - QString errorString() const; - -signals: - void serviceStateChanged(const QtAvahiServiceState &state); - -protected: - QtAvahiServicePrivate *d_ptr; - -private slots: - bool handlCollision(); - void onStateChanged(const QtAvahiServiceState &state); - -private: - QtAvahiServiceState m_state; - Q_DECLARE_PRIVATE(QtAvahiService) - -}; - -QDebug operator <<(QDebug dbg, QtAvahiService *service); - - -#endif // QTAVAHISERVICE_H diff --git a/libmea-core/discovery/avahi/qtavahiservice_p.cpp b/libmea-core/discovery/avahi/qtavahiservice_p.cpp deleted file mode 100644 index f83c2c4c..00000000 --- a/libmea-core/discovery/avahi/qtavahiservice_p.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qtavahiservice_p.h" - -#include -#include -#include - -QtAvahiServicePrivate::QtAvahiServicePrivate() : - client(0), - group(0), - error(0) -{ - -} - -void QtAvahiServicePrivate::callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata) -{ - Q_UNUSED(group); - - QtAvahiService *service = static_cast(userdata); - if (!service) - return; - - if (service->state() == (QtAvahiService::QtAvahiServiceState)state) - return; - - switch (state) { - case AVAHI_ENTRY_GROUP_UNCOMMITED: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateUncomitted); - break; - case AVAHI_ENTRY_GROUP_REGISTERING: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateRegistering); - break; - case AVAHI_ENTRY_GROUP_ESTABLISHED: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateEstablished); - break; - case AVAHI_ENTRY_GROUP_COLLISION: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateCollision); - break; - case AVAHI_ENTRY_GROUP_FAILURE: - emit service->serviceStateChanged(QtAvahiService::QtAvahiServiceStateFailure); - break; - } -} - -AvahiStringList *QtAvahiServicePrivate::createTxtList(const QHash &txt) -{ - AvahiStringList *list = NULL; - if (txt.isEmpty()) - return list; - - const QStringList keys = txt.keys(); - list = avahi_string_list_new((keys.first() + '=' + txt[keys.first()]).toLatin1().constData(), nullptr); - for (const QString &key : keys.mid(1)) { - list = avahi_string_list_add_pair(list, key.toLatin1().constData(), txt[key].toLatin1().constData()); - } - - return list; -} - diff --git a/libmea-core/discovery/avahi/qtavahiservice_p.h b/libmea-core/discovery/avahi/qtavahiservice_p.h deleted file mode 100644 index efd8b5bb..00000000 --- a/libmea-core/discovery/avahi/qtavahiservice_p.h +++ /dev/null @@ -1,56 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICEPRIVATE_P -#define QTAVAHISERVICEPRIVATE_P - -#include -#include - -#include "qtavahiservice.h" -#include "qtavahiclient.h" - -#include -#include -#include - -class QtAvahiServicePrivate -{ -public: - QtAvahiServicePrivate(); - - static void callback(AvahiEntryGroup *group, AvahiEntryGroupState state, void *userdata); - - QtAvahiClient *client; - AvahiEntryGroup *group; - QString name; - quint16 port; - QString type; - QHash txtRecords; - int error; - - static AvahiStringList *createTxtList(const QHash &txt); - -}; - -#endif // QTAVAHISERVICEPRIVATE_P - diff --git a/libmea-core/discovery/avahi/qtavahiservicebrowser.cpp b/libmea-core/discovery/avahi/qtavahiservicebrowser.cpp deleted file mode 100644 index 02bf6e47..00000000 --- a/libmea-core/discovery/avahi/qtavahiservicebrowser.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*! \fn void QtAvahiServiceBrowser::serviceEntryAdded(const AvahiServiceEntry &entry); - This signal will be emitted when a new \a entry was added to the current entry list. -*/ - -/*! \fn void QtAvahiServiceBrowser::serviceEntryRemoved(const AvahiServiceEntry &entry); - This signal will be emitted when a new \a entry was removed from the current entry list. -*/ - -#include "qtavahiservicebrowser.h" -#include "qtavahiservicebrowser_p.h" - -#include - -/*! Constructs a new \l{QtAvahiServiceBrowser} with the given \a parent. */ -QtAvahiServiceBrowser::QtAvahiServiceBrowser(QObject *parent) : - QObject(parent), - d_ptr(new QtAvahiServiceBrowserPrivate(new QtAvahiClient)) -{ - connect(d_ptr->client, &QtAvahiClient::clientStateChanged, this, &QtAvahiServiceBrowser::onClientStateChanged); -} - -/*! Destructs this \l{QtAvahiServiceBrowser}. */ -QtAvahiServiceBrowser::~QtAvahiServiceBrowser() -{ - // Delete each service browser - foreach (const QString &serviceType, d_ptr->serviceBrowserTable.keys()) { - AvahiServiceBrowser *browser = d_ptr->serviceBrowserTable.take(serviceType); - if (browser) { - avahi_service_browser_free(browser); - } - } - - // Delete the service type browser - if (d_ptr->serviceTypeBrowser) - avahi_service_type_browser_free(d_ptr->serviceTypeBrowser); - - delete d_ptr; -} - -/*! Enables this \l{QtAvahiServiceBrowser} and starts the service browsing. */ -void QtAvahiServiceBrowser::enable() -{ - d_ptr->client->start(); -} - -/*! Returns the current \l{AvahiServiceEntry} list of this \l{QtAvahiServiceBrowser}. */ -QList QtAvahiServiceBrowser::serviceEntries() const -{ - return m_serviceEntries; -} - -void QtAvahiServiceBrowser::onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state) -{ - if (state == QtAvahiClient::QtAvahiClientStateRunning) { - qDebug() << "Service browser client connected."; - // Return if we already have a service type browser - if (d_ptr->serviceTypeBrowser) - return; - - d_ptr->serviceTypeBrowser = avahi_service_type_browser_new(d_ptr->client->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, (AvahiLookupFlags) 0, QtAvahiServiceBrowserPrivate::callbackServiceTypeBrowser, this); - } else if (state == QtAvahiClient::QtAvahiClientStateFailure) { - qWarning() << "Service browser client failure:" << d_ptr->client->errorString(); - } -} - -void QtAvahiServiceBrowser::createServiceBrowser(const char *serviceType) -{ - // create a new service browser for the given serviceType - AvahiServiceBrowser *browser = avahi_service_browser_new(d_ptr->client->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, serviceType, NULL, (AvahiLookupFlags) 0, QtAvahiServiceBrowserPrivate::callbackServiceBrowser, this); - d_ptr->serviceBrowserTable.insert(serviceType, browser); -} - diff --git a/libmea-core/discovery/avahi/qtavahiservicebrowser.h b/libmea-core/discovery/avahi/qtavahiservicebrowser.h deleted file mode 100644 index a6695ede..00000000 --- a/libmea-core/discovery/avahi/qtavahiservicebrowser.h +++ /dev/null @@ -1,63 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICEBROWSER_H -#define QTAVAHISERVICEBROWSER_H - -#include -#include - -#include "qtavahiclient.h" -#include "avahiserviceentry.h" - -class QtAvahiServiceBrowserPrivate; - -class QtAvahiServiceBrowser : public QObject -{ - Q_OBJECT -public: - explicit QtAvahiServiceBrowser(QObject *parent = 0); - ~QtAvahiServiceBrowser(); - - void enable(); - - QList serviceEntries() const; - -signals: - void serviceEntryAdded(const AvahiServiceEntry &entry); - void serviceEntryRemoved(const AvahiServiceEntry &entry); - -private slots: - void onClientStateChanged(const QtAvahiClient::QtAvahiClientState &state); - -private: - QtAvahiServiceBrowserPrivate *d_ptr; - - QList m_serviceEntries; - QStringList m_serviceTypes; - - void createServiceBrowser(const char* serviceType); - - Q_DECLARE_PRIVATE(QtAvahiServiceBrowser) -}; - -#endif // QTAVAHISERVICEBROWSER_H diff --git a/libmea-core/discovery/avahi/qtavahiservicebrowser_p.cpp b/libmea-core/discovery/avahi/qtavahiservicebrowser_p.cpp deleted file mode 100644 index 265073e1..00000000 --- a/libmea-core/discovery/avahi/qtavahiservicebrowser_p.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "qtavahiservicebrowser_p.h" -#include "qtavahiservicebrowser.h" -#include "avahiserviceentry.h" - -#include -#include -#include - -QtAvahiServiceBrowserPrivate::QtAvahiServiceBrowserPrivate(QtAvahiClient *client) : - client(client), - serviceTypeBrowser(NULL) -{ - -} - -QtAvahiServiceBrowserPrivate::~QtAvahiServiceBrowserPrivate() -{ - foreach (AvahiServiceResolver *resolver, m_serviceResolvers) { - avahi_service_resolver_free(resolver); - } -} - -void QtAvahiServiceBrowserPrivate::callbackServiceTypeBrowser(AvahiServiceTypeBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(browser) - Q_UNUSED(interface) - Q_UNUSED(protocol) - Q_UNUSED(domain) - Q_UNUSED(flags) - - QtAvahiServiceBrowser *serviceBrowser = static_cast(userdata); - if (!serviceBrowser) - return; - - switch (event) { - case AVAHI_BROWSER_NEW: - if (!serviceBrowser->m_serviceTypes.contains(type)) { - serviceBrowser->m_serviceTypes.append(type); - qDebug() << "[+] Service browser" << type; - serviceBrowser->createServiceBrowser(type); - } - break; - case AVAHI_BROWSER_REMOVE: - // Note: the browser for this serviceType will be deleted once all - // services from this type are removed - break; - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - case AVAHI_BROWSER_ALL_FOR_NOW: - break; - case AVAHI_BROWSER_FAILURE: - qWarning() << "Service type browser error:" << QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client))); - break; - } -} - -void QtAvahiServiceBrowserPrivate::callbackServiceBrowser(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(browser); - Q_UNUSED(flags); - - QtAvahiServiceBrowser *serviceBrowser = static_cast(userdata); - if (!serviceBrowser) - return; - - switch (event) { - case AVAHI_BROWSER_NEW: { - // Start resolving new service - AvahiServiceResolver *resolver = avahi_service_resolver_new(serviceBrowser->d_ptr->client->client, - interface, - protocol, - name, - type, - domain, - AVAHI_PROTO_UNSPEC, - (AvahiLookupFlags) 0, - QtAvahiServiceBrowserPrivate::callbackServiceResolver, - serviceBrowser); - if (resolver) { - serviceBrowser->d_ptr->m_serviceResolvers.append(resolver); - } else { - qWarning() << "Failed to resolve service" << QString(name) << ":" << avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client)); - } - break; - } - case AVAHI_BROWSER_REMOVE: { - // Remove the service - foreach (const AvahiServiceEntry &entry, serviceBrowser->m_serviceEntries) { - // Check not only the name, but also the protocol - if (entry.name() == name && entry.protocol() == QtAvahiServiceBrowserPrivate::convertProtocol(protocol)) { - serviceBrowser->m_serviceEntries.removeAll(entry); - emit serviceBrowser->serviceEntryRemoved(entry); - } - } - - // Check if this was the last service for this serviceType - foreach (const AvahiServiceEntry &entry, serviceBrowser->m_serviceEntries) { - if (entry.serviceType() == type) - return; - } - - // This was the last service for this serviceType, lets delete the corresponding browser - AvahiServiceBrowser *browser = serviceBrowser->d_ptr->serviceBrowserTable.take(type); - if (browser) - avahi_service_browser_free(browser); - - serviceBrowser->m_serviceTypes.removeAll(type); - break; - } - case AVAHI_BROWSER_ALL_FOR_NOW: - break; - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - case AVAHI_BROWSER_FAILURE: - qWarning() << "Service browser error:" << QString(avahi_strerror(avahi_client_errno(serviceBrowser->d_ptr->client->client))); - break; - } - -} - -void QtAvahiServiceBrowserPrivate::callbackServiceResolver(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) -{ - Q_UNUSED(interface); - Q_UNUSED(type); - Q_UNUSED(txt); - - QPointer serviceBrowser = static_cast(userdata); - if (serviceBrowser.isNull()) - return; - - switch (event) { - case AVAHI_RESOLVER_FAILURE: - break; - case AVAHI_RESOLVER_FOUND: { - char a[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(a, sizeof(a), address); - - // convert protocol - QAbstractSocket::NetworkLayerProtocol networkProtocol = QtAvahiServiceBrowserPrivate::convertProtocol(protocol); - QStringList txtList = QtAvahiServiceBrowserPrivate::convertTxtList(txt); - - // create the new resolved service entry - AvahiServiceEntry entry = AvahiServiceEntry(name, - type, - QHostAddress(QString(a)), - QString(domain), - QString(host_name), - (quint16)port, - networkProtocol, - txtList, - flags); - - serviceBrowser->m_serviceEntries.append(entry); - emit serviceBrowser->serviceEntryAdded(entry); - } - } - serviceBrowser->d_ptr->m_serviceResolvers.removeAll(resolver); - avahi_service_resolver_free(resolver); - -} - -QStringList QtAvahiServiceBrowserPrivate::convertTxtList(AvahiStringList *txt) -{ - if (!txt) - return QStringList(); - - QStringList txtList; - txtList.append(QString(reinterpret_cast(txt->text))); - - while (txt->next) { - AvahiStringList *next = txt->next; - txtList.append(QString(reinterpret_cast(next->text))); - txt = next; - } - - return txtList; -} - -QAbstractSocket::NetworkLayerProtocol QtAvahiServiceBrowserPrivate::convertProtocol(const AvahiProtocol &protocol) -{ - QAbstractSocket::NetworkLayerProtocol networkProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - - switch (protocol) { - case AVAHI_PROTO_INET: - networkProtocol = QAbstractSocket::IPv4Protocol; - break; - case AVAHI_PROTO_INET6: - networkProtocol = QAbstractSocket::IPv6Protocol; - break; - case AVAHI_PROTO_UNSPEC: - networkProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } - return networkProtocol; -} - diff --git a/libmea-core/discovery/avahi/qtavahiservicebrowser_p.h b/libmea-core/discovery/avahi/qtavahiservicebrowser_p.h deleted file mode 100644 index a5cb6900..00000000 --- a/libmea-core/discovery/avahi/qtavahiservicebrowser_p.h +++ /dev/null @@ -1,82 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2016 Simon Stürz * - * * - * This file is part of mea. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef QTAVAHISERVICEBROWSERPRIVATE_H -#define QTAVAHISERVICEBROWSERPRIVATE_H - -#include -#include -#include - -#include "qtavahiclient.h" -#include "qtavahiservice.h" - -class QtAvahiServiceBrowserPrivate -{ -public: - QtAvahiServiceBrowserPrivate(QtAvahiClient *client); - ~QtAvahiServiceBrowserPrivate(); - - // Callback members - static void callbackServiceTypeBrowser(AvahiServiceTypeBrowser *browser, - AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiBrowserEvent event, - const char *type, - const char *domain, - AvahiLookupResultFlags flags, - void *userdata); - - static void callbackServiceBrowser(AvahiServiceBrowser *browser, - AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiBrowserEvent event, - const char *name, - const char *type, - const char *domain, - AvahiLookupResultFlags flags, - void *userdata); - - static void callbackServiceResolver(AvahiServiceResolver *resolver, AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiResolverEvent event, - const char *name, - const char *type, - const char *domain, - const char *host_name, - const AvahiAddress *address, - uint16_t port, - AvahiStringList *txt, - AvahiLookupResultFlags flags, - void *userdata); - - // Convert members - static QStringList convertTxtList(AvahiStringList *txt); - static QAbstractSocket::NetworkLayerProtocol convertProtocol(const AvahiProtocol &protocol); - - QtAvahiClient *client; - AvahiServiceTypeBrowser *serviceTypeBrowser; - QHash serviceBrowserTable; - QList m_serviceResolvers; -}; - -#endif // QTAVAHISERVICEBROWSERPRIVATE_H diff --git a/libmea-core/discovery/zeroconfdiscovery.cpp b/libmea-core/discovery/zeroconfdiscovery.cpp index b9b0eeee..3f33711c 100644 --- a/libmea-core/discovery/zeroconfdiscovery.cpp +++ b/libmea-core/discovery/zeroconfdiscovery.cpp @@ -7,17 +7,27 @@ ZeroconfDiscovery::ZeroconfDiscovery(DiscoveryModel *discoveryModel, QObject *pa QObject(parent), m_discoveryModel(discoveryModel) { -#ifdef WITH_AVAHI - m_serviceBrowser = new QtAvahiServiceBrowser(this); - connect(m_serviceBrowser, &QtAvahiServiceBrowser::serviceEntryAdded, this, &ZeroconfDiscovery::serviceEntryAdded); - m_serviceBrowser->enable(); +#ifdef WITH_ZEROCONF + m_zeroconfJsonRPC = new QZeroConf(this); + connect(m_zeroconfJsonRPC, &QZeroConf::serviceAdded, this, &ZeroconfDiscovery::serviceEntryAdded); + connect(m_zeroconfJsonRPC, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded); + m_zeroconfJsonRPC->startBrowser("_jsonrpc._tcp"); + qDebug() << "created service browser for _jsonrpc._tcp:" << m_zeroconfJsonRPC->browserExists(); + + m_zeroconfWebSocket = new QZeroConf(this); + connect(m_zeroconfWebSocket, &QZeroConf::serviceAdded, this, &ZeroconfDiscovery::serviceEntryAdded); + connect(m_zeroconfWebSocket, &QZeroConf::serviceUpdated, this, &ZeroconfDiscovery::serviceEntryAdded); + m_zeroconfWebSocket->startBrowser("_ws._tcp"); + qDebug() << "created service browser for _ws._tcp:" << m_zeroconfWebSocket->browserExists(); +#else + qDebug() << "Zeroconf support not compiled in. Zeroconf will not be available."; #endif } bool ZeroconfDiscovery::available() const { -#ifdef WITH_AVAHI - return true; +#ifdef WITH_ZEROCONF + return m_zeroconfJsonRPC->browserExists() || m_zeroconfWebSocket->browserExists(); #else return false; #endif @@ -25,22 +35,22 @@ bool ZeroconfDiscovery::available() const bool ZeroconfDiscovery::discovering() const { - return true; + return available(); } -#ifdef WITH_AVAHI -void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry) +#ifdef WITH_ZEROCONF +void ZeroconfDiscovery::serviceEntryAdded(const QZeroConfService &entry) { - if (!entry.name().startsWith("nymea") || entry.serviceType() != "_jsonrpc._tcp" || entry.hostAddress().protocol() == QAbstractSocket::IPv6Protocol) { + if (!entry.name().startsWith("nymea") || entry.ip().isNull()) { return; } - qDebug() << "avahi service entry added" << entry.name() << entry.hostAddress() << entry.port() << entry.txt() << entry.serviceType(); + qDebug() << "zeroconf service discovered" << entry << entry.txt() << entry.type(); QString uuid; bool sslEnabled = false; QString serverName; - foreach (const QString &txt, entry.txt()) { - QPair txtRecord = qMakePair(txt.split("=").first(), txt.split("=").at(1)); + foreach (const QByteArray &key, entry.txt().keys()) { + QPair txtRecord = qMakePair(key, entry.txt().value(key)); if (!sslEnabled && txtRecord.first == "sslEnabled") { sslEnabled = (txtRecord.second == "true"); } @@ -51,24 +61,30 @@ void ZeroconfDiscovery::serviceEntryAdded(const AvahiServiceEntry &entry) serverName = txtRecord.second; } } + qDebug() << "avahi service entry added" << serverName << uuid << sslEnabled; - DiscoveryDevice dev = m_discoveryModel->find(entry.hostAddress()); + DiscoveryDevice dev = m_discoveryModel->find(entry.ip()); if (dev.uuid() == uuid && dev.nymeaRpcUrl().startsWith("nymeas") && !sslEnabled) { // We already have this host and with a more secure configuration... skip this one... return; } + qDebug() << "Adding new found entry:" << entry.name() << entry.ip(); dev.setUuid(uuid); - dev.setHostAddress(entry.hostAddress()); + dev.setHostAddress(entry.ip()); dev.setPort(entry.port()); - dev.setFriendlyName(serverName + " on " + entry.hostName()); - QHostAddress address = entry.hostAddress(); + dev.setFriendlyName(serverName + " on " + entry.ip().toString()); + QHostAddress address = entry.ip(); QString addressString; if (address.protocol() == QAbstractSocket::IPv6Protocol) { addressString = "[" + address.toString() + "]"; } else { addressString = address.toString(); } - dev.setNymeaRpcUrl(QString("%1://%2:%3").arg(sslEnabled ? "nymeas" : "nymea").arg(addressString).arg(entry.port())); + if (entry.type() == "_ws._tcp") { + dev.setWebSocketUrl(QString("%1://%2:%3").arg(sslEnabled ? "wss" : "ws").arg(addressString).arg(entry.port())); + } else { + dev.setNymeaRpcUrl(QString("%1://%2:%3").arg(sslEnabled ? "nymeas" : "nymea").arg(addressString).arg(entry.port())); + } m_discoveryModel->addDevice(dev); // DiscoveryDevice *dev = new DiscoveryDevice(); diff --git a/libmea-core/discovery/zeroconfdiscovery.h b/libmea-core/discovery/zeroconfdiscovery.h index 7d79a3e5..8c4361ac 100644 --- a/libmea-core/discovery/zeroconfdiscovery.h +++ b/libmea-core/discovery/zeroconfdiscovery.h @@ -1,8 +1,8 @@ #ifndef ZEROCONFDISCOVERY_H #define ZEROCONFDISCOVERY_H -#ifdef WITH_AVAHI -#include "avahi/qtavahiservicebrowser.h" +#ifdef WITH_ZEROCONF +#include "qzeroconf.h" #endif #include "discoverymodel.h" @@ -22,14 +22,13 @@ public: private: DiscoveryModel *m_discoveryModel; -#ifdef WITH_AVAHI - QtAvahiServiceBrowser *m_serviceBrowser; +#ifdef WITH_ZEROCONF + QZeroConf *m_zeroconfJsonRPC = nullptr; + QZeroConf *m_zeroconfWebSocket = nullptr; private slots: - void serviceEntryAdded(const AvahiServiceEntry &entry); - + void serviceEntryAdded(const QZeroConfService &entry); #endif - }; #endif // ZEROCONFDISCOVERY_H diff --git a/libmea-core/jsonrpc/jsonrpcclient.cpp b/libmea-core/jsonrpc/jsonrpcclient.cpp index f1b1aba6..9c58b8b7 100644 --- a/libmea-core/jsonrpc/jsonrpcclient.cpp +++ b/libmea-core/jsonrpc/jsonrpcclient.cpp @@ -224,7 +224,7 @@ void JsonRpcClient::sendRequest(const QVariantMap &request) { QVariantMap newRequest = request; newRequest.insert("token", m_token); -// qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); + qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); m_connection->sendData(QJsonDocument::fromVariant(newRequest).toJson()); } @@ -237,6 +237,11 @@ void JsonRpcClient::onInterfaceConnectedChanged(bool connected) m_connected = false; emit connectedChanged(false); } + } else { + QVariantMap request; + request.insert("id", 0); + request.insert("method", "JSONRPC.Hello"); + sendRequest(request); } } @@ -254,7 +259,7 @@ void JsonRpcClient::dataReceived(const QByteArray &data) // qWarning() << "Could not parse json data from mea" << data << error.errorString(); return; } -// qDebug() << "received response" << m_receiveBuffer.left(splitIndex); + qDebug() << "received response" << m_receiveBuffer.left(splitIndex); m_receiveBuffer = m_receiveBuffer.right(m_receiveBuffer.length() - splitIndex - 1); if (!m_receiveBuffer.isEmpty()) { staticMetaObject.invokeMethod(this, "dataReceived", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray())); @@ -264,7 +269,8 @@ void JsonRpcClient::dataReceived(const QByteArray &data) // Check if this is the initial handshake - if (dataMap.value("id").toInt() == 0) { + if (dataMap.value("id").toInt() == 0 && dataMap.contains("params")) { + dataMap = dataMap.value("params").toMap(); m_initialSetupRequired = dataMap.value("initialSetupRequired").toBool(); m_authenticationRequired = dataMap.value("authenticationRequired").toBool(); m_pushButtonAuthAvailable = dataMap.value("pushButtonAuthAvailable").toBool(); diff --git a/libmea-core/libmea-core.pro b/libmea-core/libmea-core.pro index 470c4adc..2250ad89 100644 --- a/libmea-core/libmea-core.pro +++ b/libmea-core/libmea-core.pro @@ -3,11 +3,18 @@ TEMPLATE = lib CONFIG += staticlib include(../mea.pri) +!win32: { + # To enable this on Windows we'd need to install Bonjour + # https://support.apple.com/kb/DL999 + DEFINES += QZEROCONF_STATIC + DEFINES += WITH_ZEROCONF + include(../QtZeroConf/qtzeroconf.pri) +} QT -= gui QT += websockets bluetooth -INCLUDEPATH += $$top_srcdir/libnymea-common +INCLUDEPATH += $$top_srcdir/libnymea-common $$top_srcdir/QtZeroConf SOURCES += \ engine.cpp \ @@ -92,29 +99,6 @@ HEADERS += \ wifisetup/networkmanagercontroler.h \ libmea-core.h -withavahi { -DEFINES += WITH_AVAHI - -LIBS += -lavahi-client -lavahi-common - -HEADERS += discovery/avahi/avahiserviceentry.h \ - discovery/avahi/qt-watch.h \ - discovery/avahi/qtavahiclient.h \ - discovery/avahi/qtavahiservice_p.h \ - discovery/avahi/qtavahiservice.h \ - discovery/avahi/qtavahiservicebrowser_p.h \ - discovery/avahi/qtavahiservicebrowser.h \ - -SOURCES += discovery/avahi/avahiserviceentry.cpp \ - discovery/avahi/qt-watch.cpp \ - discovery/avahi/qtavahiclient.cpp \ - discovery/avahi/qtavahiservice_p.cpp \ - discovery/avahi/qtavahiservice.cpp \ - discovery/avahi/qtavahiservicebrowser_p.cpp \ - discovery/avahi/qtavahiservicebrowser.cpp \ - -} - unix { target.path = /usr/lib INSTALLS += target diff --git a/libmea-core/tcpsocketinterface.cpp b/libmea-core/tcpsocketinterface.cpp index f54f6d93..173e0cd4 100644 --- a/libmea-core/tcpsocketinterface.cpp +++ b/libmea-core/tcpsocketinterface.cpp @@ -23,7 +23,10 @@ QStringList TcpSocketInterface::supportedSchemes() const void TcpSocketInterface::sendData(const QByteArray &data) { - m_socket.write(data); + quint64 ret = m_socket.write(data); + if (ret != data.length()) { + qWarning() << "Error writing data to socket."; + } } void TcpSocketInterface::ignoreSslErrors(const QList &errors) diff --git a/mea/ui/ConnectPage.qml b/mea/ui/ConnectPage.qml index 3367aaff..82296899 100644 --- a/mea/ui/ConnectPage.qml +++ b/mea/ui/ConnectPage.qml @@ -135,8 +135,15 @@ Page { } } onClicked: { - print("Should connect to", model.nymeaRpcUrl) - Engine.connection.connect(model.nymeaRpcUrl) + var url; + if (model.nymeaRpcUrl) { + url = model.nymeaRpcUrl; + } else { + url = model.webSocketUrl; + } + print("Should connect to", url) + Engine.connection.connect(url) + pageStack.push(connectingPage) } }