From 9523039473535c92343f3ac3d59c39b4ade7b785 Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Mon, 17 Jun 2013 12:23:08 +0200 Subject: [PATCH] Avahi discovering --- CMakeLists.txt | 2 + letsgo.sh | 2 +- src/CMakeLists.txt | 21 +++- src/avahidevicelocator.cpp | 112 ++++++++++++++++++ ...urdevicelocator.h => avahidevicelocator.h} | 35 ++++-- src/bonjourdevicelocator.cpp | 52 -------- src/daemon.cpp | 93 ++++++++++----- src/daemon.h | 22 ++++ src/device.h | 16 ++- src/devicelocator.h | 8 +- src/fakedevicelocator.cpp | 34 +++--- src/fakedevicelocator.h | 14 ++- src/networkpackage.cpp | 24 +++- src/networkpackage.h | 8 ++ src/udpdevicelink.cpp | 17 +-- src/udpdevicelink.h | 10 +- test/CMakeLists.txt | 16 +++ 17 files changed, 348 insertions(+), 138 deletions(-) create mode 100644 src/avahidevicelocator.cpp rename src/{bonjourdevicelocator.h => avahidevicelocator.h} (59%) delete mode 100644 src/bonjourdevicelocator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a2bf84983..3c903653c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,5 @@ include(KDE4Defaults) include_directories(${KDE4_INCLUDES}) add_subdirectory(src) + +add_subdirectory(test) diff --git a/letsgo.sh b/letsgo.sh index 8ea1cf4aa..864fc407a 100755 --- a/letsgo.sh +++ b/letsgo.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash #Source bashrc to define kdebuild #http://techbase.kde.org/Getting_Started/Build/Environment diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6498c92b1..593f34ac9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,17 +1,26 @@ -set(kded_androidshine_SRCS fakedevicelocator.cpp echodevicelink.cpp udpdevicelink.cpp bonjourdevicelocator.cpp pausemusicpackagereceiver.cpp notificationpackagereceiver.cpp networkpackage.cpp - daemon.cpp devicelink.cpp devicelocator.cpp packagereceiver.cpp +set(kded_androidshine_SRCS + fakedevicelocator.cpp + echodevicelink.cpp + udpdevicelink.cpp + avahidevicelocator.cpp + pausemusicpackagereceiver.cpp + notificationpackagereceiver.cpp + networkpackage.cpp + daemon.cpp + devicelink.cpp + devicelocator.cpp + packagereceiver.cpp ) -kde4_add_plugin(kded_androidshine - ${kded_androidshine_SRCS} -) +kde4_add_plugin(kded_androidshine ${kded_androidshine_SRCS}) target_link_libraries(kded_androidshine ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} + kdnssd ${QT_QTNETWORK_LIBRARY} ) install(TARGETS kded_androidshine DESTINATION ${PLUGIN_INSTALL_DIR}) install(FILES androidshine.desktop DESTINATION ${SERVICES_INSTALL_DIR}/kded) -install(FILES androidshine.notifyrc DESTINATION ${DATA_INSTALL_DIR}/androidshine) \ No newline at end of file +install(FILES androidshine.notifyrc DESTINATION ${DATA_INSTALL_DIR}/androidshine) diff --git a/src/avahidevicelocator.cpp b/src/avahidevicelocator.cpp new file mode 100644 index 000000000..a59bbdb7f --- /dev/null +++ b/src/avahidevicelocator.cpp @@ -0,0 +1,112 @@ +/** + * Copyright 2013 Albert Vaca + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "avahidevicelocator.h" + +#include "udpdevicelink.h" + + +AvahiDeviceLocator::AvahiDeviceLocator() +{ + //http://api.kde.org/4.x-api/kdelibs-apidocs/dnssd/html/index.html + browser = new DNSSD::ServiceBrowser("_device._tcp"); + connect(browser, SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this,SLOT(deviceDetected(DNSSD::RemoteService::Ptr))); + connect(browser, SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr)),this,SLOT(deviceLost(DNSSD::RemoteService::Ptr))); + browser->startBrowse(); +} + +bool AvahiDeviceLocator::canLink(QString id) { + return visibleDevices.contains(id); +} + +DeviceLink* AvahiDeviceLocator::link(QString id) { + + if (!visibleDevices.contains(id)) return NULL; + + Device* d = visibleDevices[id]; + const DNSSD::RemoteService::Ptr& rs = deviceRoutes[d]; + + DeviceLink* dl = new UdpDeviceLink(QHostAddress(rs->hostName()),rs->port()); + linkedDevices.append(dl); //Store the ref to be able to delete the memory later + + return dl; +} + +bool AvahiDeviceLocator::pair(Device* d) +{ + //TODO: ? + d->pair(); + return true; +} + +void AvahiDeviceLocator::deviceDetected(DNSSD::RemoteService::Ptr s) +{ + qDebug() << "DETECTED"; + + Device* d = getDeviceInfo(s); + + if (!visibleDevices.contains(d->id())) { + visibleDevices[d->id()] = d; + deviceRoutes[d] = s; + } else { + qDebug() << "Warning: duplicate device id " + d->id(); + } +} + +void AvahiDeviceLocator::deviceLost(DNSSD::RemoteService::Ptr s) +{ + qDebug() << "LOST"; + + Device* found = NULL; + + for(QMap< Device*, DNSSD::RemoteService::Ptr >::iterator it = deviceRoutes.begin(), itEnd = deviceRoutes.end(); it != itEnd; it++) { + if (s == it.value()) { + found = it.key(); + } + } + + if (found != NULL) { + visibleDevices.remove(found->id()); + deviceRoutes.remove(found); + delete found; //created at getDeviceInfo called from deviceDetected + } else { + //TODO: Add a TAG to the debug messages + qDebug() << "Warning: lost unknown device?"; + } +} + +Device* AvahiDeviceLocator::getDeviceInfo(DNSSD::RemoteService::Ptr s) +{ + //TODO: I have no idea on how to get this info using only DNSSD, wihtout connecting to the device + Device* d = new Device("1234567890", "Unnamed"); //deleted at deviceLost + return d; +} + + + + + + + + + + + + diff --git a/src/bonjourdevicelocator.h b/src/avahidevicelocator.h similarity index 59% rename from src/bonjourdevicelocator.h rename to src/avahidevicelocator.h index dfc1a44ea..e95432c07 100644 --- a/src/bonjourdevicelocator.h +++ b/src/avahidevicelocator.h @@ -18,27 +18,44 @@ * along with this program. If not, see . */ -#ifndef BONJOURDEVICELOCATOR_H -#define BONJOURDEVICELOCATOR_H +#ifndef AVAHIDEVICELOCATOR_H +#define AVAHIDEVICELOCATOR_H #include +#include + +#include #include "devicelocator.h" -class BonjourDeviceLocator +class AvahiDeviceLocator : public DeviceLocator { Q_OBJECT public: - BonjourDeviceLocator(); - + AvahiDeviceLocator(); + QString getName() { return "Avahi"; } Priority getPriority() { return PRIORITY_HIGH; } - bool canLink(Device* d) { return true; } - DeviceLink* link(Device* d); + bool canLink(QString id); + DeviceLink* link(QString id); bool pair(Device* d); - QVector discover(); + QList discover() { return visibleDevices.values(); } + +private slots: + void deviceDetected(DNSSD::RemoteService::Ptr s); + void deviceLost(DNSSD::RemoteService::Ptr s); + +private: + DNSSD::ServiceBrowser* browser; + + Device* getDeviceInfo(DNSSD::RemoteService::Ptr s); + + QMap visibleDevices; + QMap deviceRoutes; + + QList linkedDevices; }; -#endif // BONJOURDEVICELOCATOR_H +#endif // AVAHIDEVICELOCATOR_H diff --git a/src/bonjourdevicelocator.cpp b/src/bonjourdevicelocator.cpp deleted file mode 100644 index 64d371dd2..000000000 --- a/src/bonjourdevicelocator.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2013 Albert Vaca - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "bonjourdevicelocator.h" - -#include "udpdevicelink.h" - -BonjourDeviceLocator::BonjourDeviceLocator() -{ - -/* - //http://api.kde.org/4.x-api/kdelibs-apidocs/dnssd/html/index.html - DNSSD::ServiceBrowser* browser = new DNSSD::ServiceBrowser("_http._tcp"); - connect(browser, SIGNAL(serviceAdded(RemoteService::Ptr)), - this, SLOT(addService(RemoteService::Ptr))); - connect(browser, SIGNAL(serviceRemoved(RemoteService::Ptr)), - this, SLOT(delService(RemoteService::Ptr))); - browser->startBrowse(); - In above example addService() will -*/ -} - -DeviceLink* BonjourDeviceLocator::link(Device* d) { - DeviceLink* dl = new UdpDeviceLink("192.168.1.48"); - return dl; -} - -bool BonjourDeviceLocator::pair(Device* d) { - return true; -} - -QVector BonjourDeviceLocator::discover() { - QVector devices; - return devices; -} diff --git a/src/daemon.cpp b/src/daemon.cpp index 2ccd97178..cbe18c2f0 100644 --- a/src/daemon.cpp +++ b/src/daemon.cpp @@ -22,7 +22,7 @@ #include "networkpackage.h" #include "notificationpackagereceiver.h" #include "pausemusicpackagereceiver.h" -#include "bonjourdevicelocator.h" +#include "avahidevicelocator.h" #include "fakedevicelocator.h" #include @@ -30,12 +30,40 @@ #include +#include +#include #include -K_PLUGIN_FACTORY(AndroidShineFactory, - registerPlugin();) +K_PLUGIN_FACTORY(AndroidShineFactory, registerPlugin();) K_EXPORT_PLUGIN(AndroidShineFactory("androidshine", "androidshine")) +DeviceLink* Daemon::linkTo(QString id) { + + DeviceLink* link = NULL; + + Q_FOREACH (DeviceLocator* locator, deviceLocators) { + if (locator->canLink(id)) { + link = locator->link(id); + if (link != NULL) break; + } + } + + if (link != NULL) { + + linkedDevices.append(link); + + Q_FOREACH (PackageReceiver* pr, packageReceivers) { + QObject::connect(link,SIGNAL(receivedPackage(const NetworkPackage&)), + pr,SLOT(receivePackage(const NetworkPackage&))); + } + + } else { + qDebug() << "Could not link device id " + id; + } + + return link; + +} Daemon::Daemon(QObject *parent, const QList&) : KDEDModule(parent) @@ -43,45 +71,55 @@ Daemon::Daemon(QObject *parent, const QList&) qDebug() << "GO GO GO!"; - //TODO: Do not hardcode the load of the package receivers packageReceivers.push_back(new NotificationPackageReceiver()); packageReceivers.push_back(new PauseMusicPackageReceiver()); //TODO: Do not hardcode the load of the device locators - deviceLocators.insert(new BonjourDeviceLocator()); + deviceLocators.insert(new AvahiDeviceLocator()); deviceLocators.insert(new FakeDeviceLocator()); //TODO: Read paired devices from config pairedDevices.push_back(new Device("MyAndroid","MyAndroid")); - - //Try to link to all paired devices - foreach (Device* device, pairedDevices) { - - DeviceLink* link = NULL; - - foreach (DeviceLocator* locator, deviceLocators) { - - if (locator->canLink(device)) { - link = locator->link(device); - if (link != NULL) break; - } - - } - - if (link != NULL) linkedDevices.append(link); - else qDebug() << "Could not link " + device->name(); - + //At boot time, try to link to all paired devices + Q_FOREACH (Device* device, pairedDevices) { + linkTo(device->id()); } - foreach (DeviceLink* ld, linkedDevices) { - foreach (PackageReceiver* pr, packageReceivers) { - QObject::connect(ld,SIGNAL(receivedPackage(const NetworkPackage&)), - pr,SLOT(receivePackage(const NetworkPackage&))); +} + + +QString Daemon::listVisibleDevices() +{ + + std::stringstream ret; + + ret << std::setw(20) << "ID"; + ret << std::setw(20) << "Name"; + ret << std::setw(20) << "Source"; + ret << std::endl; + + QList visibleDevices; + + foreach (DeviceLocator* dl, deviceLocators) { + foreach (Device* d, dl->discover()) { + ret << std::setw(20) << d->id().toStdString(); + ret << std::setw(20) << d->name().toStdString(); + ret << std::setw(20) << dl->getName().toStdString(); + ret << std::endl; } } + return QString::fromStdString(ret.str()); + +} + +bool Daemon::linkDevice(QString id) +{ + + return linkTo(id); + } Daemon::~Daemon() @@ -89,3 +127,4 @@ Daemon::~Daemon() qDebug() << "SAYONARA BABY"; } + diff --git a/src/daemon.h b/src/daemon.h index e83a39c99..0c89e4969 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -52,8 +52,30 @@ public: Daemon(QObject *parent, const QList&); ~Daemon(); +//DBUS interface + +public Q_SLOTS: + + Q_SCRIPTABLE QString listVisibleDevices(); + + Q_SCRIPTABLE bool linkDevice(QString id); + +/* + Q_SCRIPTABLE bool pairDevice(long id); + + Q_SCRIPTABLE QString listPairedDevices(long id); + + Q_SCRIPTABLE bool linkAllPairedDevices(); + + Q_SCRIPTABLE QString listLinkedDevices(long id); + +*/ + private: + //Get a DeviceLink through the best DeviceLocator available + DeviceLink* linkTo(QString d); + //All known devices (read from/stored to settings) QVector pairedDevices; diff --git a/src/device.h b/src/device.h index 4f812b887..d68c0c771 100644 --- a/src/device.h +++ b/src/device.h @@ -26,15 +26,21 @@ class Device { public: - Device(QString id, QString name) { + Device(const QString& id, const QString& name) + { mDeviceId = id; mDeviceName = name; } - QString id() { return mDeviceId; } - QString name() { return mDeviceName; } - bool paired() { return mPaired; } - void pair() { mPaired = true; } + QString id() const{ return mDeviceId; } + QString name() const { return mDeviceName; } + bool paired() const { return mPaired; } + + void pair() { + mPaired = true; + //TODO: Actually do something + + } private: bool mPaired; diff --git a/src/devicelocator.h b/src/devicelocator.h index dc7a81671..9c5f38add 100644 --- a/src/devicelocator.h +++ b/src/devicelocator.h @@ -36,6 +36,8 @@ public: DeviceLocator(); virtual ~DeviceLocator() { } + virtual QString getName() = 0; + enum Priority { PRIORITY_LOW = 0, //ie: 3g PRIORITY_MEDIUM = 50, //ie: internet @@ -43,10 +45,10 @@ public: }; virtual Priority getPriority() = 0; - virtual bool canLink(Device* d) = 0; - virtual DeviceLink* link(Device* d) = 0; + virtual bool canLink(QString id) = 0; + virtual DeviceLink* link(QString id) = 0; virtual bool pair(Device* d) = 0; - virtual QVector discover() = 0; + virtual QList discover() = 0; }; diff --git a/src/fakedevicelocator.cpp b/src/fakedevicelocator.cpp index 91501f5e6..460ca403b 100644 --- a/src/fakedevicelocator.cpp +++ b/src/fakedevicelocator.cpp @@ -21,29 +21,29 @@ #include "fakedevicelocator.h" #include "echodevicelink.h" -bool FakeDeviceLocator::canLink(Device* d) { - return d->name() == "fake"; +FakeDeviceLocator::FakeDeviceLocator() +{ + fakeDevice = new Device("fake","Fake device"); + echoDeviceLink = new EchoDeviceLink(); } -DeviceLink* FakeDeviceLocator::link(Device* d) { - if (d->name() == "fake") { - return new EchoDeviceLink(); - } else { - return NULL; - } +bool FakeDeviceLocator::canLink(QString id) { + return id == "fake"; +} + +DeviceLink* FakeDeviceLocator::link(QString id) { + if (!canLink(id)) return NULL; + return echoDeviceLink; } bool FakeDeviceLocator::pair(Device* d) { - if (d->name() != "fake") { - return false; - } else { - d->pair(); - return true; - } + if (d != fakeDevice) return false; + d->pair(); + return true; } -QVector FakeDeviceLocator::discover() { - QVector devices; - devices.append(new Device("fake","Fake device")); +QList FakeDeviceLocator::discover() { + QList devices; + devices.append(fakeDevice); return devices; } diff --git a/src/fakedevicelocator.h b/src/fakedevicelocator.h index 4210bc689..6ac865e73 100644 --- a/src/fakedevicelocator.h +++ b/src/fakedevicelocator.h @@ -26,12 +26,20 @@ class FakeDeviceLocator : public DeviceLocator { public: + FakeDeviceLocator(); + QString getName() { return "FakeLocator"; } + Priority getPriority() { return PRIORITY_LOW; } - bool canLink(Device* d); - DeviceLink* link(Device* d); + bool canLink(QString id); + DeviceLink* link(QString id); bool pair(Device* d); - QVector discover(); + QList discover(); + +private: + Device* fakeDevice; + DeviceLink* echoDeviceLink; + }; #endif // FAKEDEVICELOCATOR_H diff --git a/src/networkpackage.cpp b/src/networkpackage.cpp index 634819647..81bf46efb 100644 --- a/src/networkpackage.cpp +++ b/src/networkpackage.cpp @@ -28,17 +28,17 @@ NetworkPackage NetworkPackage::fromString(QByteArray s) { - - NetworkPackage pp; - //FIXME: How can I do this using Qt? std::string stds(std::string(s.data())); std::cout << stds << std::endl; std::stringstream ss(stds); - ss >> pp.mId; - std::cout << pp.mId << std::endl; + long id; + ss >> id; + qDebug() << "Receiving package with id: " << id; + + NetworkPackage pp(id); ss >> pp.mDeviceId; qDebug() << pp.mDeviceId; @@ -64,3 +64,17 @@ NetworkPackage NetworkPackage::fromString(QByteArray s) } +QByteArray NetworkPackage::toString() const +{ + + QByteArray s; + + //TODO + s += "HOLA"; + + return s; + +} + + + diff --git a/src/networkpackage.h b/src/networkpackage.h index a8bd15214..2cc692e7d 100644 --- a/src/networkpackage.h +++ b/src/networkpackage.h @@ -29,13 +29,21 @@ class NetworkPackage public: + NetworkPackage(long id) { + mId = id; + //TODO + } + static NetworkPackage fromString(QByteArray); + QByteArray toString() const; QString type() const { return mType; } QString body() const { return mBody; } long id() const { return mId; } bool isCancel() const { return mIsCancel; } + + private: long mId; diff --git a/src/udpdevicelink.cpp b/src/udpdevicelink.cpp index 76dda0829..5bdc67242 100644 --- a/src/udpdevicelink.cpp +++ b/src/udpdevicelink.cpp @@ -21,25 +21,28 @@ #include "udpdevicelink.h" -UdpDeviceLink::UdpDeviceLink(QString ip) +UdpDeviceLink::UdpDeviceLink(QHostAddress ip, quint16 port) { - m_udpSocket = new QUdpSocket(); - m_udpSocket->bind(10600); - connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications())); + mIp = ip; + mPort = port; + + mUdpSocket = new QUdpSocket(); + mUdpSocket->bind(port); + connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications())); } void UdpDeviceLink::readPendingNotifications() { - while (m_udpSocket->hasPendingDatagrams()) { + while (mUdpSocket->hasPendingDatagrams()) { QByteArray datagram; - datagram.resize(m_udpSocket->pendingDatagramSize()); + datagram.resize(mUdpSocket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; - m_udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); + mUdpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); //log.write(datagram); qDebug() << datagram; diff --git a/src/udpdevicelink.h b/src/udpdevicelink.h index f41f76865..0e6da8617 100644 --- a/src/udpdevicelink.h +++ b/src/udpdevicelink.h @@ -33,10 +33,11 @@ class UdpDeviceLink Q_OBJECT public: - UdpDeviceLink(QString ip); + UdpDeviceLink(QHostAddress ip, quint16 port); void sendPackage(const NetworkPackage& np) { - //TODO: Not implemented + mUdpSocket->writeDatagram(np.toString(), mIp, mPort); + } @@ -45,7 +46,10 @@ private Q_SLOTS: void readPendingNotifications(); private: - QUdpSocket* m_udpSocket; + QUdpSocket* mUdpSocket; + + QHostAddress mIp; + quint16 mPort; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e69de29bb..2cf7e9d28 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -0,0 +1,16 @@ +set(kded_androidshine_tests_SRCS + backendtests.cpp +) + +kde4_add_unit_test(kded_androidshine_tests ${kded_androidshine_tests_SRCS}) + +target_link_libraries(kded_androidshine_tests + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + kdnssd + ${QT_QTNETWORK_LIBRARY} +) + +add_test(kded_androidshine_tests ${CMAKE_CURRENT_BINARY_DIR}/kded_androidshine_tests) + +