Avahi discovering

This commit is contained in:
Albert Vaca 2013-06-17 12:23:08 +02:00
parent a736beae77
commit 9523039473
17 changed files with 348 additions and 138 deletions

View file

@ -6,3 +6,5 @@ include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(test)

View file

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
#Source bashrc to define kdebuild #Source bashrc to define kdebuild
#http://techbase.kde.org/Getting_Started/Build/Environment #http://techbase.kde.org/Getting_Started/Build/Environment

View file

@ -1,14 +1,23 @@
set(kded_androidshine_SRCS fakedevicelocator.cpp echodevicelink.cpp udpdevicelink.cpp bonjourdevicelocator.cpp pausemusicpackagereceiver.cpp notificationpackagereceiver.cpp networkpackage.cpp set(kded_androidshine_SRCS
daemon.cpp devicelink.cpp devicelocator.cpp packagereceiver.cpp 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 kde4_add_plugin(kded_androidshine ${kded_androidshine_SRCS})
${kded_androidshine_SRCS}
)
target_link_libraries(kded_androidshine target_link_libraries(kded_androidshine
${KDE4_KDECORE_LIBS} ${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS} ${KDE4_KDEUI_LIBS}
kdnssd
${QT_QTNETWORK_LIBRARY} ${QT_QTNETWORK_LIBRARY}
) )

112
src/avahidevicelocator.cpp Normal file
View file

@ -0,0 +1,112 @@
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View file

@ -18,27 +18,44 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef BONJOURDEVICELOCATOR_H #ifndef AVAHIDEVICELOCATOR_H
#define BONJOURDEVICELOCATOR_H #define AVAHIDEVICELOCATOR_H
#include <QObject> #include <QObject>
#include <KDE/DNSSD/ServiceBrowser>
#include <KDE/DNSSD/RemoteService>
#include "devicelocator.h" #include "devicelocator.h"
class BonjourDeviceLocator class AvahiDeviceLocator
: public DeviceLocator : public DeviceLocator
{ {
Q_OBJECT Q_OBJECT
public: public:
BonjourDeviceLocator(); AvahiDeviceLocator();
QString getName() { return "Avahi"; }
Priority getPriority() { return PRIORITY_HIGH; } Priority getPriority() { return PRIORITY_HIGH; }
bool canLink(Device* d) { return true; } bool canLink(QString id);
DeviceLink* link(Device* d); DeviceLink* link(QString id);
bool pair(Device* d); bool pair(Device* d);
QVector<Device*> discover(); QList<Device*> 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<QString, Device*> visibleDevices;
QMap<Device*, DNSSD::RemoteService::Ptr> deviceRoutes;
QList<DeviceLink*> linkedDevices;
}; };
#endif // BONJOURDEVICELOCATOR_H #endif // AVAHIDEVICELOCATOR_H

View file

@ -1,52 +0,0 @@
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<Device*> BonjourDeviceLocator::discover() {
QVector<Device*> devices;
return devices;
}

View file

@ -22,7 +22,7 @@
#include "networkpackage.h" #include "networkpackage.h"
#include "notificationpackagereceiver.h" #include "notificationpackagereceiver.h"
#include "pausemusicpackagereceiver.h" #include "pausemusicpackagereceiver.h"
#include "bonjourdevicelocator.h" #include "avahidevicelocator.h"
#include "fakedevicelocator.h" #include "fakedevicelocator.h"
#include <QtNetwork/QUdpSocket> #include <QtNetwork/QUdpSocket>
@ -30,12 +30,40 @@
#include <KDE/KIcon> #include <KDE/KIcon>
#include <sstream>
#include <iomanip>
#include <iostream> #include <iostream>
K_PLUGIN_FACTORY(AndroidShineFactory, K_PLUGIN_FACTORY(AndroidShineFactory, registerPlugin<Daemon>();)
registerPlugin<Daemon>();)
K_EXPORT_PLUGIN(AndroidShineFactory("androidshine", "androidshine")) 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<QVariant>&) Daemon::Daemon(QObject *parent, const QList<QVariant>&)
: KDEDModule(parent) : KDEDModule(parent)
@ -43,44 +71,54 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
qDebug() << "GO GO GO!"; qDebug() << "GO GO GO!";
//TODO: Do not hardcode the load of the package receivers //TODO: Do not hardcode the load of the package receivers
packageReceivers.push_back(new NotificationPackageReceiver()); packageReceivers.push_back(new NotificationPackageReceiver());
packageReceivers.push_back(new PauseMusicPackageReceiver()); packageReceivers.push_back(new PauseMusicPackageReceiver());
//TODO: Do not hardcode the load of the device locators //TODO: Do not hardcode the load of the device locators
deviceLocators.insert(new BonjourDeviceLocator()); deviceLocators.insert(new AvahiDeviceLocator());
deviceLocators.insert(new FakeDeviceLocator()); deviceLocators.insert(new FakeDeviceLocator());
//TODO: Read paired devices from config //TODO: Read paired devices from config
pairedDevices.push_back(new Device("MyAndroid","MyAndroid")); pairedDevices.push_back(new Device("MyAndroid","MyAndroid"));
//At boot time, try to link to all paired devices
//Try to link to all paired devices Q_FOREACH (Device* device, pairedDevices) {
foreach (Device* device, pairedDevices) { linkTo(device->id());
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(); 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<Device*> 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());
} }
foreach (DeviceLink* ld, linkedDevices) { bool Daemon::linkDevice(QString id)
foreach (PackageReceiver* pr, packageReceivers) { {
QObject::connect(ld,SIGNAL(receivedPackage(const NetworkPackage&)),
pr,SLOT(receivePackage(const NetworkPackage&))); return linkTo(id);
}
}
} }
@ -89,3 +127,4 @@ Daemon::~Daemon()
qDebug() << "SAYONARA BABY"; qDebug() << "SAYONARA BABY";
} }

View file

@ -52,8 +52,30 @@ public:
Daemon(QObject *parent, const QList<QVariant>&); Daemon(QObject *parent, const QList<QVariant>&);
~Daemon(); ~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: private:
//Get a DeviceLink through the best DeviceLocator available
DeviceLink* linkTo(QString d);
//All known devices (read from/stored to settings) //All known devices (read from/stored to settings)
QVector<Device*> pairedDevices; QVector<Device*> pairedDevices;

View file

@ -26,15 +26,21 @@
class Device class Device
{ {
public: public:
Device(QString id, QString name) { Device(const QString& id, const QString& name)
{
mDeviceId = id; mDeviceId = id;
mDeviceName = name; mDeviceName = name;
} }
QString id() { return mDeviceId; } QString id() const{ return mDeviceId; }
QString name() { return mDeviceName; } QString name() const { return mDeviceName; }
bool paired() { return mPaired; } bool paired() const { return mPaired; }
void pair() { mPaired = true; }
void pair() {
mPaired = true;
//TODO: Actually do something
}
private: private:
bool mPaired; bool mPaired;

View file

@ -36,6 +36,8 @@ public:
DeviceLocator(); DeviceLocator();
virtual ~DeviceLocator() { } virtual ~DeviceLocator() { }
virtual QString getName() = 0;
enum Priority { enum Priority {
PRIORITY_LOW = 0, //ie: 3g PRIORITY_LOW = 0, //ie: 3g
PRIORITY_MEDIUM = 50, //ie: internet PRIORITY_MEDIUM = 50, //ie: internet
@ -43,10 +45,10 @@ public:
}; };
virtual Priority getPriority() = 0; virtual Priority getPriority() = 0;
virtual bool canLink(Device* d) = 0; virtual bool canLink(QString id) = 0;
virtual DeviceLink* link(Device* d) = 0; virtual DeviceLink* link(QString id) = 0;
virtual bool pair(Device* d) = 0; virtual bool pair(Device* d) = 0;
virtual QVector<Device*> discover() = 0; virtual QList<Device*> discover() = 0;
}; };

View file

@ -21,29 +21,29 @@
#include "fakedevicelocator.h" #include "fakedevicelocator.h"
#include "echodevicelink.h" #include "echodevicelink.h"
bool FakeDeviceLocator::canLink(Device* d) { FakeDeviceLocator::FakeDeviceLocator()
return d->name() == "fake"; {
fakeDevice = new Device("fake","Fake device");
echoDeviceLink = new EchoDeviceLink();
} }
DeviceLink* FakeDeviceLocator::link(Device* d) { bool FakeDeviceLocator::canLink(QString id) {
if (d->name() == "fake") { return id == "fake";
return new EchoDeviceLink();
} else {
return NULL;
} }
DeviceLink* FakeDeviceLocator::link(QString id) {
if (!canLink(id)) return NULL;
return echoDeviceLink;
} }
bool FakeDeviceLocator::pair(Device* d) { bool FakeDeviceLocator::pair(Device* d) {
if (d->name() != "fake") { if (d != fakeDevice) return false;
return false;
} else {
d->pair(); d->pair();
return true; return true;
} }
}
QVector<Device*> FakeDeviceLocator::discover() { QList<Device*> FakeDeviceLocator::discover() {
QVector<Device*> devices; QList<Device*> devices;
devices.append(new Device("fake","Fake device")); devices.append(fakeDevice);
return devices; return devices;
} }

View file

@ -26,12 +26,20 @@ class FakeDeviceLocator
: public DeviceLocator : public DeviceLocator
{ {
public: public:
FakeDeviceLocator();
QString getName() { return "FakeLocator"; }
Priority getPriority() { return PRIORITY_LOW; } Priority getPriority() { return PRIORITY_LOW; }
bool canLink(Device* d); bool canLink(QString id);
DeviceLink* link(Device* d); DeviceLink* link(QString id);
bool pair(Device* d); bool pair(Device* d);
QVector<Device*> discover(); QList<Device*> discover();
private:
Device* fakeDevice;
DeviceLink* echoDeviceLink;
}; };
#endif // FAKEDEVICELOCATOR_H #endif // FAKEDEVICELOCATOR_H

View file

@ -28,17 +28,17 @@
NetworkPackage NetworkPackage::fromString(QByteArray s) NetworkPackage NetworkPackage::fromString(QByteArray s)
{ {
NetworkPackage pp;
//FIXME: How can I do this using Qt? //FIXME: How can I do this using Qt?
std::string stds(std::string(s.data())); std::string stds(std::string(s.data()));
std::cout << stds << std::endl; std::cout << stds << std::endl;
std::stringstream ss(stds); std::stringstream ss(stds);
ss >> pp.mId; long id;
std::cout << pp.mId << std::endl; ss >> id;
qDebug() << "Receiving package with id: " << id;
NetworkPackage pp(id);
ss >> pp.mDeviceId; ss >> pp.mDeviceId;
qDebug() << 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;
}

View file

@ -29,13 +29,21 @@ class NetworkPackage
public: public:
NetworkPackage(long id) {
mId = id;
//TODO
}
static NetworkPackage fromString(QByteArray); static NetworkPackage fromString(QByteArray);
QByteArray toString() const;
QString type() const { return mType; } QString type() const { return mType; }
QString body() const { return mBody; } QString body() const { return mBody; }
long id() const { return mId; } long id() const { return mId; }
bool isCancel() const { return mIsCancel; } bool isCancel() const { return mIsCancel; }
private: private:
long mId; long mId;

View file

@ -21,25 +21,28 @@
#include "udpdevicelink.h" #include "udpdevicelink.h"
UdpDeviceLink::UdpDeviceLink(QString ip) UdpDeviceLink::UdpDeviceLink(QHostAddress ip, quint16 port)
{ {
m_udpSocket = new QUdpSocket(); mIp = ip;
m_udpSocket->bind(10600); mPort = port;
connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications()));
mUdpSocket = new QUdpSocket();
mUdpSocket->bind(port);
connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications()));
} }
void UdpDeviceLink::readPendingNotifications() void UdpDeviceLink::readPendingNotifications()
{ {
while (m_udpSocket->hasPendingDatagrams()) { while (mUdpSocket->hasPendingDatagrams()) {
QByteArray datagram; QByteArray datagram;
datagram.resize(m_udpSocket->pendingDatagramSize()); datagram.resize(mUdpSocket->pendingDatagramSize());
QHostAddress sender; QHostAddress sender;
quint16 senderPort; quint16 senderPort;
m_udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); mUdpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
//log.write(datagram); //log.write(datagram);
qDebug() << datagram; qDebug() << datagram;

View file

@ -33,10 +33,11 @@ class UdpDeviceLink
Q_OBJECT Q_OBJECT
public: public:
UdpDeviceLink(QString ip); UdpDeviceLink(QHostAddress ip, quint16 port);
void sendPackage(const NetworkPackage& np) { void sendPackage(const NetworkPackage& np) {
//TODO: Not implemented mUdpSocket->writeDatagram(np.toString(), mIp, mPort);
} }
@ -45,7 +46,10 @@ private Q_SLOTS:
void readPendingNotifications(); void readPendingNotifications();
private: private:
QUdpSocket* m_udpSocket; QUdpSocket* mUdpSocket;
QHostAddress mIp;
quint16 mPort;
}; };

View file

@ -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)