Reversed Avahi discovery (now the computer announces the service)

This commit is contained in:
Albert Vaca 2013-06-18 20:04:53 +02:00
parent ff9e8be5ad
commit 5d0510c836
12 changed files with 207 additions and 252 deletions

View file

@ -1,14 +1,14 @@
set(kded_androidshine_SRCS set(kded_androidshine_SRCS
fakedevicelocator.cpp fakeannouncer.cpp
echodevicelink.cpp echodevicelink.cpp
udpdevicelink.cpp udpdevicelink.cpp
avahidevicelocator.cpp avahiannouncer.cpp
pausemusicpackagereceiver.cpp pausemusicpackagereceiver.cpp
notificationpackagereceiver.cpp notificationpackagereceiver.cpp
networkpackage.cpp networkpackage.cpp
daemon.cpp daemon.cpp
devicelink.cpp devicelink.cpp
devicelocator.cpp announcer.cpp
packagereceiver.cpp packagereceiver.cpp
) )

View file

@ -18,8 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "devicelocator.h" #include "announcer.h"
DeviceLocator::DeviceLocator() { Announcer::Announcer() {
//gcc complains if we don't add something to compile on a class with virtual functions //gcc complains if we don't add something to compile on a class with virtual functions
} }

View file

@ -18,8 +18,8 @@
* 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 DEVICELOCATOR_H #ifndef ANNOUNCER_H
#define DEVICELOCATOR_H #define ANNOUNCER_H
#include <qvector.h> #include <qvector.h>
#include <QObject> #include <QObject>
@ -27,16 +27,14 @@
#include "devicelink.h" #include "devicelink.h"
#include "device.h" #include "device.h"
class DeviceLocator class Announcer
: public QObject : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DeviceLocator(); Announcer();
virtual ~DeviceLocator() { } virtual ~Announcer() { }
virtual QString getName() = 0;
enum Priority { enum Priority {
PRIORITY_LOW = 0, //ie: 3g PRIORITY_LOW = 0, //ie: 3g
@ -44,18 +42,16 @@ public:
PRIORITY_HIGH = 100 //ie: lan PRIORITY_HIGH = 100 //ie: lan
}; };
virtual QString getName() = 0;
virtual Priority getPriority() = 0; virtual Priority getPriority() = 0;
virtual bool canLink(QString id) = 0;
virtual DeviceLink* link(QString id) = 0; virtual void setDiscoverable(bool b) = 0;
virtual bool pair(Device* d) = 0;
virtual QList<Device*> discover() = 0; signals:
void deviceConnection(DeviceLink *);
signals: signals:
//TODO: Emit this to be able to see if it is a known device
//void deviceDiscovered(Device* d);
//void deviceLost(QString id);
}; };
#endif // DEVICELOCATOR_H #endif

79
src/avahiannouncer.cpp Normal file
View file

@ -0,0 +1,79 @@
/**
* 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 "avahiannouncer.h"
#include "udpdevicelink.h"
AvahiAnnouncer::AvahiAnnouncer()
{
QString serviceType = "_kdeconnect._udp";
quint16 port = 10601;
//http://api.kde.org/4.x-api/kdelibs-apidocs/dnssd/html/index.html
service = new DNSSD::PublicService("KDE Host", serviceType, port);
mUdpSocket = new QUdpSocket();
mUdpSocket->bind(port);
connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications()));
qDebug() << "listening to udp messages";
}
void AvahiAnnouncer::readPendingNotifications()
{
qDebug() << "readPendingNotifications";
while (mUdpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(mUdpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
mUdpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
//log.write(datagram);
qDebug() << ("AvahiAnnouncer incomming udp datagram: " + datagram);
QString id, name;
Device* device = new Device(id, name);
DeviceLink* dl = new UdpDeviceLink(device, sender, 10600);
links.append(dl);
emit deviceConnection(dl);
}
}
AvahiAnnouncer::~AvahiAnnouncer()
{
delete service;
}
void AvahiAnnouncer::setDiscoverable(bool b)
{
if (b) service->publishAsync();
}

View file

@ -18,44 +18,45 @@
* 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 AVAHIDEVICELOCATOR_H #ifndef AVAHIANNOUNCER_H
#define AVAHIDEVICELOCATOR_H #define AVAHIANNOUNCER_H
#include <QObject> #include <QObject>
#include <KDE/DNSSD/ServiceBrowser>
#include <KDE/DNSSD/RemoteService> #include <QUdpSocket>
#include "devicelocator.h" #include <KDE/DNSSD/PublicService>
class AvahiDeviceLocator #include "announcer.h"
: public DeviceLocator
class AvahiAnnouncer
: public Announcer
{ {
Q_OBJECT Q_OBJECT
public: public:
AvahiDeviceLocator(); AvahiAnnouncer();
~AvahiAnnouncer();
QString getName() { return "Avahi"; } QString getName() { return "Avahi"; }
Priority getPriority() { return PRIORITY_HIGH; } Priority getPriority() { return PRIORITY_HIGH; }
bool canLink(QString id);
DeviceLink* link(QString id);
bool pair(Device* d);
QList<Device*> discover() { return visibleDevices.values(); }
private slots: void setDiscoverable(bool b);
void deviceDetected(DNSSD::RemoteService::Ptr s);
void deviceLost(DNSSD::RemoteService::Ptr s);
private Q_SLOTS:
void readPendingNotifications();
private: private:
DNSSD::ServiceBrowser* browser; DNSSD::PublicService* service;
QUdpSocket* mUdpSocket;
Device* getDeviceInfo(DNSSD::RemoteService::Ptr s); QVector<DeviceLink*> links;
QMap<QString, Device*> visibleDevices; QHostAddress mIp;
QMap<Device*, DNSSD::RemoteService::Ptr> deviceRoutes; quint16 mPort;
QList<DeviceLink*> linkedDevices;
}; };
#endif // AVAHIDEVICELOCATOR_H #endif

View file

@ -1,118 +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 "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(d, QHostAddress(rs->hostName()),rs->port());
qDebug() << "Sending pair request to device " + id;
NetworkPackage np(12345);
//TODO: Package contents
dl->sendPackage(np);
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

@ -22,8 +22,8 @@
#include "networkpackage.h" #include "networkpackage.h"
#include "notificationpackagereceiver.h" #include "notificationpackagereceiver.h"
#include "pausemusicpackagereceiver.h" #include "pausemusicpackagereceiver.h"
#include "avahidevicelocator.h" #include "avahiannouncer.h"
#include "fakedevicelocator.h" #include "fakeannouncer.h"
#include <QtNetwork/QUdpSocket> #include <QtNetwork/QUdpSocket>
#include <QFile> #include <QFile>
@ -37,32 +37,15 @@
K_PLUGIN_FACTORY(AndroidShineFactory, registerPlugin<Daemon>();) K_PLUGIN_FACTORY(AndroidShineFactory, registerPlugin<Daemon>();)
K_EXPORT_PLUGIN(AndroidShineFactory("androidshine", "androidshine")) K_EXPORT_PLUGIN(AndroidShineFactory("androidshine", "androidshine"))
DeviceLink* Daemon::linkTo(QString id) { void Daemon::linkTo(DeviceLink* dl) {
DeviceLink* link = NULL; linkedDevices.append(dl);
Q_FOREACH (DeviceLocator* locator, deviceLocators) { Q_FOREACH (PackageReceiver* pr, packageReceivers) {
if (locator->canLink(id)) { QObject::connect(dl,SIGNAL(receivedPackage(const NetworkPackage&)),
link = locator->link(id); pr,SLOT(receivePackage(const NetworkPackage&)));
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>&)
@ -76,22 +59,21 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
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 AvahiDeviceLocator()); announcers.insert(new AvahiAnnouncer());
deviceLocators.insert(new FakeDeviceLocator()); announcers.insert(new FakeAnnouncer());
//Listen to incomming connections
Q_FOREACH (Announcer* a, announcers) {
QObject::connect(a,SIGNAL(deviceConnection(DeviceLink*)),
this,SLOT(deviceConnection(DeviceLink*)));
a->setDiscoverable(true);
}
//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
//FIXME: This should be done for every new visible device, not only at boot
//TODO: Add a way to notify discovered/lost devices
Q_FOREACH (Device* device, pairedDevices) {
linkTo(device->id());
}
} }
QString Daemon::listVisibleDevices() QString Daemon::listVisibleDevices()
{ {
@ -99,29 +81,22 @@ QString Daemon::listVisibleDevices()
ret << std::setw(20) << "ID"; ret << std::setw(20) << "ID";
ret << std::setw(20) << "Name"; ret << std::setw(20) << "Name";
ret << std::setw(20) << "Source";
ret << std::endl; ret << std::endl;
QList<Device*> visibleDevices; Q_FOREACH (Device* d, visibleDevices) {
ret << std::setw(20) << d->id().toStdString();
Q_FOREACH (DeviceLocator* dl, deviceLocators) { ret << std::setw(20) << d->name().toStdString();
Q_FOREACH (Device* d, dl->discover()) { ret << std::endl;
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()); return QString::fromStdString(ret.str());
} }
bool Daemon::linkDevice(QString id) bool Daemon::pairDevice(QString id)
{ {
//TODO
return linkTo(id); return true;
} }
QString Daemon::listLinkedDevices() QString Daemon::listLinkedDevices()
@ -133,9 +108,36 @@ QString Daemon::listLinkedDevices()
} }
return ret; return ret;
} }
void Daemon::deviceConnection(DeviceLink* dl)
{
QString id = dl->device()->id();
bool paired = false;
Q_FOREACH (Device* d, pairedDevices) {
if (id == d->id()) {
paired = true;
break;
}
}
visibleDevices.append(dl->device());
if (paired) {
qDebug() << "Known device connected" + dl->device()->name();
linkTo(dl);
}
else {
qDebug() << "Unknown device connected" + dl->device()->name();
//TODO: Not connect immediately
linkTo(dl);
}
}
Daemon::~Daemon() Daemon::~Daemon()
{ {
qDebug() << "SAYONARA BABY"; qDebug() << "SAYONARA BABY";

View file

@ -39,7 +39,7 @@
#include "device.h" #include "device.h"
#include "packagereceiver.h" #include "packagereceiver.h"
#include "devicelink.h" #include "devicelink.h"
#include "devicelocator.h" #include "announcer.h"
class QUdpSocket; class QUdpSocket;
@ -54,15 +54,16 @@ public:
//DBUS interface //DBUS interface
private Q_SLOTS:
void deviceConnection(DeviceLink* dl);
public Q_SLOTS: public Q_SLOTS:
Q_SCRIPTABLE QString listVisibleDevices(); Q_SCRIPTABLE QString listVisibleDevices();
Q_SCRIPTABLE bool linkDevice(QString id);
/*
Q_SCRIPTABLE bool pairDevice(QString id); Q_SCRIPTABLE bool pairDevice(QString id);
/*
Q_SCRIPTABLE QString listPairedDevices(QString id); Q_SCRIPTABLE QString listPairedDevices(QString id);
Q_SCRIPTABLE bool linkAllPairedDevices(); Q_SCRIPTABLE bool linkAllPairedDevices();
@ -73,17 +74,23 @@ public Q_SLOTS:
private: private:
//Get a DeviceLink through the best DeviceLocator available void linkTo(DeviceLink* dl);
DeviceLink* linkTo(QString d);
//All known devices (read from/stored to settings) //Non paired visible devices
QList<Device*> visibleDevices;
//All paired devices (should be stored and read from disk)
QVector<Device*> pairedDevices; QVector<Device*> pairedDevices;
//Currently connected devices //Currently connected devices
QVector<DeviceLink*> linkedDevices; QVector<DeviceLink*> linkedDevices;
//Different ways to find new devices and connect to them, ordered by priority
QSet<DeviceLocator*> deviceLocators;
//Different ways to find devices and connect to them, ordered by priority
QSet<Announcer*> announcers;
//Everybody who wants to be notified about a new package //Everybody who wants to be notified about a new package
QVector<PackageReceiver*> packageReceivers; QVector<PackageReceiver*> packageReceivers;

View file

@ -18,32 +18,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "fakedevicelocator.h" #include "fakeannouncer.h"
#include "echodevicelink.h" #include "echodevicelink.h"
FakeDeviceLocator::FakeDeviceLocator() FakeAnnouncer::FakeAnnouncer()
{ {
fakeDevice = new Device("fake","Fake device"); fakeDevice = new Device("fake","Fake device");
echoDeviceLink = new EchoDeviceLink(fakeDevice); echoDeviceLink = new EchoDeviceLink(fakeDevice);
} }
bool FakeDeviceLocator::canLink(QString id) { FakeAnnouncer::~FakeAnnouncer()
return id == "fake"; {
//delete echoDeviceLink;
//delete fakeDevice;
} }
DeviceLink* FakeDeviceLocator::link(QString id) { void FakeAnnouncer::setDiscoverable(bool b)
if (!canLink(id)) return NULL; {
return echoDeviceLink; if (b) emit deviceConnection(echoDeviceLink);
} }
bool FakeDeviceLocator::pair(Device* d) {
if (d != fakeDevice) return false;
d->pair();
return true;
}
QList<Device*> FakeDeviceLocator::discover() {
QList<Device*> devices;
devices.append(fakeDevice);
return devices;
}

View file

@ -18,23 +18,22 @@
* 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 FAKEDEVICELOCATOR_H #ifndef FAKEANNOUNCER_H
#define FAKEDEVICELOCATOR_H #define FAKEANNOUNCER_H
#include "devicelocator.h"
class FakeDeviceLocator #include "announcer.h"
: public DeviceLocator
class FakeAnnouncer
: public Announcer
{ {
public: public:
FakeDeviceLocator(); FakeAnnouncer();
~FakeAnnouncer();
QString getName() { return "FakeLocator"; }
QString getName() { return "FakeAnnouncer"; }
Priority getPriority() { return PRIORITY_LOW; } Priority getPriority() { return PRIORITY_LOW; }
bool canLink(QString id);
DeviceLink* link(QString id); void setDiscoverable(bool b);
bool pair(Device* d);
QList<Device*> discover();
private: private:
Device* fakeDevice; Device* fakeDevice;
@ -42,4 +41,4 @@ private:
}; };
#endif // FAKEDEVICELOCATOR_H #endif

View file

@ -51,6 +51,7 @@ void UdpDeviceLink::readPendingNotifications()
NetworkPackage np = NetworkPackage::fromString(datagram); NetworkPackage np = NetworkPackage::fromString(datagram);
emit receivedPackage(np); emit receivedPackage(np);
} }
} }

View file

@ -37,10 +37,7 @@ public:
void sendPackage(const NetworkPackage& np) { void sendPackage(const NetworkPackage& np) {
mUdpSocket->writeDatagram(np.toString(), mIp, mPort); mUdpSocket->writeDatagram(np.toString(), mIp, mPort);
} }
private Q_SLOTS: private Q_SLOTS:
void readPendingNotifications(); void readPendingNotifications();