Skip to content

Commit

Permalink
Refactor gateway scanner, use UPnP and /api/config results
Browse files Browse the repository at this point in the history
  • Loading branch information
manup committed Nov 20, 2017
1 parent 02c0c5f commit 91fe6b5
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 74 deletions.
4 changes: 2 additions & 2 deletions de_web_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ DeRestPluginPrivate::DeRestPluginPrivate(QObject *parent) :
webSocketServer = 0;

gwScanner = new GatewayScanner(this);
connect(gwScanner, SIGNAL(foundGateway(quint32,quint16,QString,QString)),
this, SLOT(foundGateway(quint32,quint16,QString,QString)));
connect(gwScanner, SIGNAL(foundGateway(QHostAddress,quint16,QString,QString)),
this, SLOT(foundGateway(QHostAddress,quint16,QString,QString)));
gwScanner->startScan();

QString dataPath = deCONZ::getStorageLocation(deCONZ::ApplicationsDataLocation);
Expand Down
2 changes: 1 addition & 1 deletion de_web_plugin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ public Q_SLOTS:
void ntpqFinished();

// gateways
void foundGateway(quint32 ip, quint16 port, const QString &uuid, const QString &name);
void foundGateway(const QHostAddress &host, quint16 port, const QString &uuid, const QString &name);

public:
void checkRfConnectState();
Expand Down
145 changes: 87 additions & 58 deletions gateway_scanner.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016 dresden elektronik ingenieurtechnik gmbh.
* Copyright (c) 2016-2017 dresden elektronik ingenieurtechnik gmbh.
* All rights reserved.
*
* The software in this package is published under the terms of the BSD
Expand All @@ -15,7 +15,8 @@
#include <QNetworkReply>
#include <vector>
#include "gateway_scanner.h"
#include "deconz/dbg_trace.h"
#include "deconz.h"
#include "json.h"

enum ScanState
{
Expand All @@ -39,6 +40,7 @@ class GatewayScannerPrivate
void startScanTimer(int msec, ScanEvent action);
void stopTimer();
void queryNextIp();
void processReply();

GatewayScanner *q;
ScanState state;
Expand Down Expand Up @@ -86,6 +88,18 @@ bool GatewayScanner::isRunning() const
return (d->state != StateInit);
}

void GatewayScanner::queryGateway(const QString &url)
{
Q_D(GatewayScanner);

if (!isRunning() && d->reply == 0)
{
d->reply = d->manager->get(QNetworkRequest(url));
QObject::connect(d->reply, SIGNAL(error(QNetworkReply::NetworkError)),
d->manager->parent(), SLOT(onError(QNetworkReply::NetworkError)));
}
}

void GatewayScanner::startScan()
{
Q_D(GatewayScanner);
Expand All @@ -105,12 +119,72 @@ void GatewayScanner::scanTimerFired()
void GatewayScanner::requestFinished(QNetworkReply *reply)
{
Q_D(GatewayScanner);

if (reply == d->reply)
{
d->processReply();
}

if (isRunning())
{
d->handleEvent(EventGotReply);
}
}

void GatewayScannerPrivate::processReply()
{
if (!reply)
{
return;
}

QNetworkReply *r = reply;
reply = 0;
r->deleteLater();

int code = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

if (code != 200) // not authorized or ok
{
return;
}

bool ok;
QVariant var = Json::parse(r->readAll(), ok);
if (!ok)
{
return;
}

QVariantMap map = var.toMap();
if (map.isEmpty())
{
return;
}

if (!map.contains(QLatin1String("bridgeid")) ||
!map.contains(QLatin1String("modelid")) ||
!map.contains(QLatin1String("name")))
{
return;
}

QString name = map["name"].toString();
//QString modelid = map["modelid"].toString();
QString bridgeid = map["bridgeid"].toString();

QUrl url = r->url();

QHostAddress host(url.host());
if (host.isNull() || name.isEmpty() || bridgeid.isEmpty())
{
return;
}

//DBG_Printf(DBG_INFO, "GW: %s %s, %s, %s\n", qPrintable(url.host()), qPrintable(name), qPrintable(modelid), qPrintable(bridgeid));
q->foundGateway(host, url.port(80), bridgeid, name);
}

void GatewayScanner::onError(QNetworkReply::NetworkError code)
{
Q_D(GatewayScanner);
Expand Down Expand Up @@ -184,9 +258,16 @@ void GatewayScannerPrivate::handleEvent(ScanEvent event)
{
if (state == StateInit)
{
initScanner();
state = StateIdle;
startScanTimer(10, ActionProcess);
if (event == ActionProcess)
{
initScanner();
state = StateIdle;
startScanTimer(10, ActionProcess);
}
else
{
Q_ASSERT(0);
}
}
else if (state == StateIdle)
{
Expand All @@ -211,58 +292,6 @@ void GatewayScannerPrivate::handleEvent(ScanEvent event)
}
else if (event == EventGotReply)
{
QNetworkReply *r = reply;
if (reply)
{
reply = 0;
int code = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

if (code == 200) // not authorized or ok
{
QNetworkRequest req = r->request();
DBG_Printf(DBG_INFO, "reply code %d from %s\n", code, qPrintable(req.url().toString()));

QString name;
bool isGateway = false;
char buf[256];
qint64 n = 0;
while ((n = r->readLine(buf, sizeof(buf))) > 0)
{
if (n < 10 || (size_t)n >= sizeof(buf))
continue;

buf[n] = '\0';

if (!isGateway)
{
if (strstr(buf, ">dresden elektronik<"))
{
isGateway = true;
}
}
else if (strstr(buf, "<gatewayName>"))
{
const char *start = strchr(buf, '>') + 1;
const char *end = strstr(start, "</gatewayName>");
if (!end || start == end)
continue;
buf[end - buf] = '\0';
name = start;
}
else if (strstr(buf, "<UDN>uuid:"))
{
const char *start = strchr(buf, ':') + 1;
const char *end = strstr(start, "</UDN>");
if (!end || start == end)
continue;
buf[end - buf] = '\0';
q->foundGateway(scanIp, scanPort, start, name);
break;
}
}
}
r->deleteLater();
}
host++;
startScanTimer(1, ActionProcess);
}
Expand Down Expand Up @@ -314,7 +343,7 @@ void GatewayScannerPrivate::queryNextIp()
}

QString url;
url.sprintf("http://%u.%u.%u.%u:%u/description.xml",
url.sprintf("http://%u.%u.%u.%u:%u/api/config",
((scanIp >> 24) & 0xff),
((scanIp >> 16) & 0xff),
((scanIp >> 8) & 0xff),
Expand Down
3 changes: 2 additions & 1 deletion gateway_scanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ class GatewayScanner : public QObject
explicit GatewayScanner(QObject *parent = 0);
~GatewayScanner();
bool isRunning() const;
void queryGateway(const QString &url);

Q_SIGNALS:
void foundGateway(quint32 ip, quint16 port, const QString &uuid, const QString &name);
void foundGateway(const QHostAddress &host, quint16 port, const QString &uuid, const QString &name);

public Q_SLOTS:
void startScan();
Expand Down
30 changes: 30 additions & 0 deletions rest_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <stdlib.h>
#include <time.h>
#include <QProcess>
#include "gateway.h"
#ifdef ARCH_ARM
#include <unistd.h>
#include <sys/reboot.h>
Expand Down Expand Up @@ -955,6 +956,35 @@ int DeRestPluginPrivate::getBasicConfig(const ApiRequest &req, ApiResponse &rsp)
}
}
basicConfigToMap(rsp.map);

// add more details if this was requested from discover page
// this should speedup multi-gateway discovery
if (!gateways.empty())
{
// restrict info TODO more limited "Origin"
QString referer = req.hdr.value(QLatin1String("Referer"));
if (referer.contains(QLatin1String("js/scanner-worker.js")))
{
QVariantList ls;
for (const Gateway *gw : gateways)
{
DBG_Assert(gw != 0);
if (gw)
{
QVariantMap g;
g["host"] = gw->address().toString();
g["port"] = gw->port();
ls.push_back(g);
}
}

if (!ls.empty())
{
rsp.map["gateways"] = ls;
}
}
}

rsp.httpStatus = HttpStatusOk;
rsp.etag = gwConfigEtag;
return REQ_READY_SEND;
Expand Down
9 changes: 5 additions & 4 deletions rest_gateways.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ void DeRestPluginPrivate::gatewayToMap(const ApiRequest &req, const Gateway *gw,
}
}

void DeRestPluginPrivate::foundGateway(quint32 ip, quint16 port, const QString &uuid, const QString &name)
void DeRestPluginPrivate::foundGateway(const QHostAddress &host, quint16 port, const QString &uuid, const QString &name)
{
if (uuid.isEmpty())
{
Expand All @@ -421,9 +421,9 @@ void DeRestPluginPrivate::foundGateway(quint32 ip, quint16 port, const QString &

if (gw && gw->uuid() == uuid)
{
if (gw->address().toIPv4Address() != ip || gw->port() != port)
if (gw->address().toIPv4Address() != host.toIPv4Address() || gw->port() != port)
{
gw->setAddress(QHostAddress(ip));
gw->setAddress(host);
gw->setPort(port);

}
Expand All @@ -446,13 +446,14 @@ void DeRestPluginPrivate::foundGateway(quint32 ip, quint16 port, const QString &
QString gwApikey = gwUuid.left(10);

Gateway *gw = new Gateway(this);
gw->setAddress(QHostAddress(ip));
gw->setAddress(host);
gw->setPort(port);
gw->setUuid(uuid);
gw->setName(name);
gw->setApiKey(gwApikey);
DBG_Printf(DBG_INFO, "found gateway %s:%u\n", qPrintable(gw->address().toString()), port);
gateways.push_back(gw);
updateEtag(gwConfigEtag);
}


Expand Down
Loading

0 comments on commit 91fe6b5

Please sign in to comment.