diff --git a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.cpp b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.cpp index b7a25e17..07d1841b 100644 --- a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.cpp +++ b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.cpp @@ -55,11 +55,41 @@ #include #include +#include DevicePluginWifiDetector::DevicePluginWifiDetector() { } +DeviceManager::DeviceSetupStatus DevicePluginWifiDetector::setupDevice(Device *device) +{ + qCDebug(dcWifiDetector) << "Setup" << device->params(); + return DeviceManager::DeviceSetupStatusSuccess; +} + +DeviceManager::DeviceError DevicePluginWifiDetector::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +{ + Q_UNUSED(params) + + m_deviceDescriptors.clear(); + + if (deviceClassId != wifiDeviceClassId) + return DeviceManager::DeviceErrorDeviceClassNotFound; + + foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) { + // not localhost and IPv4 + if (!address.isLoopback() && address.protocol() == QAbstractSocket::IPv4Protocol) { + QProcess *process = new QProcess(this); + qCDebug(dcWifiDetector) << "Discover interface" << address.toString(); + connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(discoveryProcessFinished(int,QProcess::ExitStatus))); + process->start(QStringLiteral("nmap"), QStringList() << "-sP" << QString("%1/24").arg(address.toString())); + m_discoveryProcesses.append(process); + } + } + + return DeviceManager::DeviceErrorAsync; +} + DeviceManager::HardwareResources DevicePluginWifiDetector::requiredHardware() const { return DeviceManager::HardwareResourceTimer; @@ -67,46 +97,90 @@ DeviceManager::HardwareResources DevicePluginWifiDetector::requiredHardware() co void DevicePluginWifiDetector::guhTimer() { - - - QProcess *p = new QProcess(this); - connect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus))); - p->start(QStringLiteral("sudo"), QStringList() << "nmap" << "-sP" << "10.10.10.0/24"); + foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) { + // not localhost and IPv4 + if (!address.isLoopback() && address.protocol() == QAbstractSocket::IPv4Protocol) { + QProcess *process = new QProcess(this); + connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus))); + process->start(QStringLiteral("nmap"), QStringList() << "-sP" << QString("%1/24").arg(address.toString())); + } + } } void DevicePluginWifiDetector::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { - QProcess *p = static_cast(sender()); + QProcess *process = static_cast(sender()); if (exitCode != 0 || exitStatus != QProcess::NormalExit) { - qCWarning(dcWifiDetector) << "error performing network scan:" << p->readAllStandardError(); + qCWarning(dcWifiDetector) << "Network scan error:" << process->readAllStandardError(); + process->deleteLater(); return; } - QList watchedDevices = deviceManager()->findConfiguredDevices(supportedDevices().first().id()); - if (watchedDevices.isEmpty()) { - p->deleteLater(); + // return if there is no longer any device + if (myDevices().isEmpty()) { + process->deleteLater(); return; } QStringList foundDevices; - while(p->canReadLine()) { - QString result = QString::fromLatin1(p->readLine()); + while(process->canReadLine()) { + QString result = QString::fromLatin1(process->readLine()); if (result.startsWith("MAC Address:")) { QStringList lineParts = result.split(' '); if (lineParts.count() > 3) { - QString addr = lineParts.at(2); - foundDevices << addr.toLower(); + //qCDebug(dcWifiDetector) << result.remove("/n"); + foundDevices << lineParts.at(2).toLower(); } } } - foreach (Device *device, watchedDevices) { - bool wasInRange = device->stateValue(inRangeStateTypeId).toBool(); - bool wasFound = foundDevices.contains(device->paramValue("mac").toString().toLower()); - if (wasInRange != wasFound) { + // check states + foreach (Device *device, myDevices()) { + bool wasFound = foundDevices.contains(device->paramValue("mac address").toString().toLower()); + if (device->stateValue(inRangeStateTypeId).toBool() != wasFound) { device->setStateValue(inRangeStateTypeId, wasFound); } } - p->deleteLater(); + process->deleteLater(); +} + +void DevicePluginWifiDetector::discoveryProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + QProcess *process = static_cast(sender()); + + qCDebug(dcWifiDetector) << "Discovery finished"; + + if (m_discoveryProcesses.contains(process)) { + m_discoveryProcesses.removeAll(process); + } else { + return; + } + + if (exitCode != 0 || exitStatus != QProcess::NormalExit) { + qCWarning(dcWifiDetector) << "Network scan error:" << process->readAllStandardError(); + process->deleteLater(); + return; + } + + while(process->canReadLine()) { + QString result = QString::fromLatin1(process->readLine()); + if (result.startsWith("MAC Address:")) { + QStringList lineParts = result.split(' '); + if (lineParts.count() > 4) { + qCDebug(dcWifiDetector) << "-----------------------------------"; + QString macAddress = lineParts.at(2).toLower(); + int index = result.indexOf(lineParts.at(2)); + QString name = result.right(result.length() - index - macAddress.length() - 1); + qCDebug(dcWifiDetector) << "Address :" << macAddress; + qCDebug(dcWifiDetector) << "Interface:" << name.remove(QRegExp("\\(|\\)")); + m_deviceDescriptors.append(DeviceDescriptor(wifiDeviceClassId, macAddress, name.remove(QRegExp("\\(|\\)")))); + } + } + } + + if (m_discoveryProcesses.isEmpty()) { + emit devicesDiscovered(wifiDeviceClassId, m_deviceDescriptors); + } + } diff --git a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.h b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.h index 7b8a92a6..cba7d29f 100644 --- a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.h +++ b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.h @@ -36,12 +36,19 @@ class DevicePluginWifiDetector : public DevicePlugin public: explicit DevicePluginWifiDetector(); + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; DeviceManager::HardwareResources requiredHardware() const override; void guhTimer() override; +private: + QList m_discoveryProcesses; + QList m_deviceDescriptors; + private slots: void processFinished(int exitCode, QProcess::ExitStatus exitStatus); + void discoveryProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); }; #endif // DEVICEPLUGINWIFIDETECTOR_H diff --git a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.json b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.json index ddab16e3..17a2a279 100644 --- a/plugins/deviceplugins/wifidetector/devicepluginwifidetector.json +++ b/plugins/deviceplugins/wifidetector/devicepluginwifidetector.json @@ -11,11 +11,12 @@ { "deviceClassId": "bd216356-f1ec-4324-9785-6982d2174e17", "name": "WiFi Device", + "idName": "wifi", "basicTags": [ - "Service", + "Device", "Sensor" ], - "createMethods": ["user"], + "createMethods": ["user", "discovery"], "paramTypes": [ { "name": "name", @@ -23,7 +24,7 @@ "inputType": "TextLine" }, { - "name": "mac", + "name": "mac address", "type": "QString", "inputType": "MacAddress" } diff --git a/server/rest/deviceclassesresource.cpp b/server/rest/deviceclassesresource.cpp index 20350239..fed25d1c 100644 --- a/server/rest/deviceclassesresource.cpp +++ b/server/rest/deviceclassesresource.cpp @@ -286,6 +286,11 @@ void DeviceClassesResource::devicesDiscovered(const DeviceClassId &deviceClassId qCDebug(dcRest) << "Discovery finished. Found" << deviceDescriptors.count() << "devices."; + if (m_discoverRequests.value(deviceClassId).isNull()) { + qCWarning(dcRest) << "Async reply for discovery does not exist any more (timeout)."; + return; + } + HttpReply *reply = m_discoverRequests.take(deviceClassId); reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceDescriptors(deviceDescriptors)).toJson()); diff --git a/server/rest/deviceclassesresource.h b/server/rest/deviceclassesresource.h index 11397156..4bf2398f 100644 --- a/server/rest/deviceclassesresource.h +++ b/server/rest/deviceclassesresource.h @@ -44,7 +44,7 @@ public: HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override; private: - mutable QHash m_discoverRequests; + mutable QHash> m_discoverRequests; DeviceClass m_deviceClass; diff --git a/server/rest/devicesresource.cpp b/server/rest/devicesresource.cpp index eec37a66..d104370c 100644 --- a/server/rest/devicesresource.cpp +++ b/server/rest/devicesresource.cpp @@ -499,6 +499,11 @@ void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::De QVariantMap response; response.insert("error", JsonTypes::deviceErrorToString(status)); + if (m_asyncActionExecutions.value(actionId).isNull()) { + qCWarning(dcRest) << "Async reply for execute action does not exist any more (timeout)."; + return; + } + HttpReply *reply = m_asyncActionExecutions.take(actionId); reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { @@ -524,6 +529,11 @@ void DevicesResource::deviceSetupFinished(Device *device, DeviceManager::DeviceE QVariantMap response; response.insert("error", JsonTypes::deviceErrorToString(status)); + if (m_asyncDeviceAdditions.value(device->id()).isNull()) { + qCWarning(dcRest) << "Async reply for device setup does not exist any more (timeout)."; + return; + } + HttpReply *reply = m_asyncDeviceAdditions.take(device->id()); reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { @@ -550,6 +560,11 @@ void DevicesResource::deviceEditFinished(Device *device, DeviceManager::DeviceEr QVariantMap response; response.insert("error", JsonTypes::deviceErrorToString(status)); + if (m_asyncEditDevice.value(device).isNull()) { + qCWarning(dcRest) << "Async reply for device edit does not exist any more (timeout)."; + return; + } + HttpReply *reply = m_asyncEditDevice.take(device); reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { @@ -573,6 +588,11 @@ void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransac QVariantMap response; response.insert("error", JsonTypes::deviceErrorToString(status)); + if (m_asyncPairingRequests.value(pairingTransactionId).isNull()) { + qCWarning(dcRest) << "Async reply for device pairing does not exist any more."; + return; + } + HttpReply *reply = m_asyncPairingRequests.take(pairingTransactionId); if (status != DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Pairing device finished with error."; @@ -582,6 +602,7 @@ void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransac reply->finished(); return; } + qCDebug(dcRest) << "Pairing device finished successfully"; // Add device to async device addtions diff --git a/server/rest/devicesresource.h b/server/rest/devicesresource.h index b50985cd..b22a2b2f 100644 --- a/server/rest/devicesresource.h +++ b/server/rest/devicesresource.h @@ -43,10 +43,10 @@ public: HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override; private: - mutable QHash m_asyncActionExecutions; - mutable QHash m_asyncDeviceAdditions; - mutable QHash m_asyncEditDevice; - mutable QHash m_asyncPairingRequests; + mutable QHash > m_asyncActionExecutions; + mutable QHash > m_asyncDeviceAdditions; + mutable QHash > m_asyncEditDevice; + mutable QHash > m_asyncPairingRequests; Device *m_device; diff --git a/server/rest/restserver.cpp b/server/rest/restserver.cpp index f3c99842..3c708c98 100644 --- a/server/rest/restserver.cpp +++ b/server/rest/restserver.cpp @@ -138,6 +138,13 @@ void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &re void RestServer::asyncReplyFinished() { HttpReply *reply = qobject_cast(sender()); + + if (!m_asyncReplies.values().contains(reply)) { + qCWarning(dcWebServer) << "Reply for async request does no longer exist"; + reply->deleteLater(); + return; + } + QUuid clientId = m_asyncReplies.key(reply); m_asyncReplies.remove(clientId);