diff --git a/libguh/network/upnpdiscovery/upnpdiscovery.cpp b/libguh/network/upnpdiscovery/upnpdiscovery.cpp index 6243cd62..79841cad 100644 --- a/libguh/network/upnpdiscovery/upnpdiscovery.cpp +++ b/libguh/network/upnpdiscovery/upnpdiscovery.cpp @@ -120,7 +120,7 @@ void UpnpDiscovery::requestDeviceInformation(const QNetworkRequest &networkReque m_informationRequestList.insert(replay, upnpDeviceDescriptor); } -void UpnpDiscovery::respondToSearchRequest() +void UpnpDiscovery::respondToSearchRequest(QHostAddress host, int port) { GuhSettings settings(GuhSettings::SettingsRoleDevices); settings.beginGroup("guhd"); @@ -133,34 +133,38 @@ void UpnpDiscovery::respondToSearchRequest() GuhSettings globalSettings(GuhSettings::SettingsRoleGlobal); globalSettings.beginGroup("WebServer"); - int port = settings.value("port", 3333).toInt(); + int serverPort = settings.value("port", 3333).toInt(); bool useSsl = settings.value("https", false).toBool(); globalSettings.endGroup(); foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { - // listen only on IPv4 foreach (QNetworkAddressEntry entry, interface.addressEntries()) { + // check IPv4 if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) { - QString locationString; - if (useSsl) { - locationString = "https://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml"; - } else { - locationString = "http://" + entry.ip().toString() + ":" + QString::number(port) + "/server.xml"; + // check subnet + if (host.isInSubnet(QHostAddress::parseSubnet(entry.ip().toString() + "/24"))) { + QString locationString; + if (useSsl) { + locationString = "https://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml"; + } else { + locationString = "http://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml"; + } + + // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf + QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n" + "Cache-Control: max-age=1900\r\n" + "DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n" + "EXT:\r\n" + "CONTENT-LENGTH:0\r\n" + "Location: " + locationString.toUtf8() + "\r\n" + "Server: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n" + "ST:upnp:rootdevice\r\n" + "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "\r\n"); + + //qCDebug(dcHardware) << QString("Sending response to %1:%2\n").arg(host.toString()).arg(port); + writeDatagram(rootdeviceResponseMessage, host, port); } - - // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf - QByteArray rootdeviceResponseMessage = QByteArray("HTTP/1.1 200 OK\r\n" - "CACHE-CONTROL: max-age=1900\r\n" - "DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n" - "EXT:\r\n" - "CONTENT-LENGTH:0\r\n" - "LOCATION: " + locationString.toUtf8() + "\r\n" - "SERVER: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n" - "ST:upnp:rootdevice\r\n" - "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" - "\r\n"); - - sendToMulticast(rootdeviceResponseMessage); } } } @@ -169,7 +173,7 @@ void UpnpDiscovery::respondToSearchRequest() /*! This method will be called to send the SSDP message \a data to the UPnP multicast.*/ void UpnpDiscovery::sendToMulticast(const QByteArray &data) { - qCDebug(dcHardware) << "sending to multicast\n" << data; + //qCDebug(dcHardware) << "sending to multicast\n" << data; writeDatagram(data, m_host, m_port); } @@ -181,19 +185,20 @@ void UpnpDiscovery::error(QAbstractSocket::SocketError error) void UpnpDiscovery::readData() { QByteArray data; + quint16 port; QHostAddress hostAddress; QUrl location; // read the answere from the multicast while (hasPendingDatagrams()) { data.resize(pendingDatagramSize()); - readDatagram(data.data(), data.size(), &hostAddress); + readDatagram(data.data(), data.size(), &hostAddress, &port); } if (data.contains("M-SEARCH")) { qCDebug(dcHardware) << "--------------------------------------"; - qCDebug(dcHardware) << "UPnP data:" << hostAddress.toString() << "\n" << data; - respondToSearchRequest(); + qCDebug(dcHardware) << QString("UPnP data: %1:%2 \n").arg(hostAddress.toString()).arg(QString::number(port)) << data; + respondToSearchRequest(hostAddress, port); return; } @@ -333,16 +338,13 @@ void UpnpDiscovery::notificationTimeout() // http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf QByteArray rootdeviceResponseMessage = QByteArray("NOTIFY * HTTP/1.1\r\n" - "CACHE-CONTROL: max-age=1900\r\n" "HOST:239.255.255.250:1900\r\n" + "Cache-Control: max-age=1900\r\n" + "Location: " + locationString.toUtf8() + "\r\n" "NT:urn:schemas-upnp-org:device:Basic:1\r\n" - "NTS:ssdp:alive\r\n" - "DATE: " + QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT\r\n" - "EXT:\r\n" - "CONTENT-LENGTH:0\r\n" - "LOCATION: " + locationString.toUtf8() + "\r\n" - "SERVER: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n" "USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n" + "NTS: ssdp:alive\r\n" + "SERVER: guh/" + QByteArray(GUH_VERSION_STRING) + " UPnP/1.1 \r\n" "\r\n"); sendToMulticast(rootdeviceResponseMessage); diff --git a/libguh/network/upnpdiscovery/upnpdiscovery.h b/libguh/network/upnpdiscovery/upnpdiscovery.h index f70d8129..c95018f9 100644 --- a/libguh/network/upnpdiscovery/upnpdiscovery.h +++ b/libguh/network/upnpdiscovery/upnpdiscovery.h @@ -58,7 +58,7 @@ private: QHash m_informationRequestList; void requestDeviceInformation(const QNetworkRequest &networkRequest, const UpnpDeviceDescriptor &upnpDeviceDescriptor); - void respondToSearchRequest(); + void respondToSearchRequest(QHostAddress host, int port); protected: diff --git a/server/webserver.cpp b/server/webserver.cpp index 426a00a4..4268dc92 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -216,135 +216,6 @@ QString WebServer::fileName(const QString &query) return m_webinterfaceDir.path() + fileName; } -QByteArray WebServer::createServerXmlDocument(QHostAddress address) -{ - GuhSettings settings(GuhSettings::SettingsRoleDevices); - settings.beginGroup("guhd"); - QByteArray uuid = settings.value("uuid", QVariant()).toByteArray(); - if (uuid.isEmpty()) { - uuid = QUuid::createUuid().toByteArray().replace("{", "").replace("}",""); - settings.setValue("uuid", uuid); - } - settings.endGroup(); - - - QByteArray data; - QXmlStreamWriter writer(&data); - writer.setAutoFormatting(true); - writer.writeStartDocument("1.0"); - writer.writeStartElement("root"); - writer.writeAttribute("xmlns", "urn:schemas-upnp-org:device-1-0"); - - writer.writeStartElement("specVersion"); - writer.writeTextElement("major", "1"); - writer.writeTextElement("minor", "1"); - writer.writeEndElement(); // specVersion - -// if (m_useSsl) { -// writer.writeTextElement("URLBase", "https://" + address.toString() + ":" + QString::number(m_port)); -// } else { -// writer.writeTextElement("URLBase", "http://" + address.toString() + ":" + QString::number(m_port)); -// } - writer.writeStartElement("device"); - writer.writeTextElement("deviceType", "urn:schemas-upnp-org:device:Basic:1"); - writer.writeTextElement("friendlyName", "guhd"); - writer.writeTextElement("manufacturer", "ARGE guh"); - writer.writeTextElement("manufacturerURL", "http://guh.guru"); - writer.writeTextElement("modelDescription", "Home automation server"); - writer.writeTextElement("modelName", "guhd"); - writer.writeTextElement("modelNumber", GUH_VERSION_STRING); - writer.writeTextElement("modelURL", "http://guh.io"); // (optional) - writer.writeTextElement("UDN", "uuid:" + uuid); - if (m_useSsl) { - writer.writeTextElement("presentationURL", "https://" + address.toString() + ":" + QString::number(m_port)); - } else { - writer.writeTextElement("presentationURL", "http://" + address.toString() + ":" + QString::number(m_port)); - } - - //writer.writeTextElement("presentationURL", "/"); - - writer.writeStartElement("iconList"); - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "8"); - writer.writeTextElement("height", "8"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-8x8.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "16"); - writer.writeTextElement("height", "16"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-16x16.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "22"); - writer.writeTextElement("height", "22"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-22x22.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "32"); - writer.writeTextElement("height", "32"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-32x32.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "48"); - writer.writeTextElement("height", "48"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-48x48.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "64"); - writer.writeTextElement("height", "64"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-64x64.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "128"); - writer.writeTextElement("height", "128"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-128x128.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "256"); - writer.writeTextElement("height", "256"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-256x256.png"); - writer.writeEndElement(); // icon - - writer.writeStartElement("icon"); - writer.writeTextElement("mimetype", "image/png"); - writer.writeTextElement("width", "512"); - writer.writeTextElement("height", "512"); - writer.writeTextElement("depth", "24"); - writer.writeTextElement("url", "/icons/guh-logo-512x512.png"); - writer.writeEndElement(); // icon - - writer.writeEndElement(); // iconList - - writer.writeEndElement(); // device - writer.writeEndElement(); // root - writer.writeEndDocument(); - return data; -} - HttpReply *WebServer::processIconRequest(const QString &fileName) { if (!fileName.endsWith(".png")) @@ -479,8 +350,8 @@ void WebServer::readClient() } // check HTTP version - if (request.httpVersion() != "HTTP/1.1") { - qCWarning(dcWebServer) << "HTTP version is not supported."; + if (request.httpVersion() != "HTTP/1.1" && request.httpVersion() != "HTTP/1.0") { + qCWarning(dcWebServer) << "HTTP version is not supported." << request.httpVersion(); HttpReply *reply = RestResource::createErrorReply(HttpReply::HttpVersionNotSupported); reply->setClientId(clientId); sendHttpReply(reply); @@ -676,6 +547,132 @@ bool WebServer::stopServer() return true; } + +QByteArray WebServer::createServerXmlDocument(QHostAddress address) +{ + GuhSettings settings(GuhSettings::SettingsRoleDevices); + settings.beginGroup("guhd"); + QByteArray uuid = settings.value("uuid", QVariant()).toByteArray(); + if (uuid.isEmpty()) { + uuid = QUuid::createUuid().toByteArray().replace("{", "").replace("}",""); + settings.setValue("uuid", uuid); + } + settings.endGroup(); + + + QByteArray data; + QXmlStreamWriter writer(&data); + writer.setAutoFormatting(true); + writer.writeStartDocument("1.0"); + writer.writeStartElement("root"); + writer.writeAttribute("xmlns", "urn:schemas-upnp-org:device-1-0"); + + writer.writeStartElement("specVersion"); + writer.writeTextElement("major", "1"); + writer.writeTextElement("minor", "1"); + writer.writeEndElement(); // specVersion + + if (m_useSsl) { + writer.writeTextElement("URLBase", "https://" + address.toString() + ":" + QString::number(m_port)); + } else { + writer.writeTextElement("URLBase", "http://" + address.toString() + ":" + QString::number(m_port)); + } + writer.writeTextElement("presentationURL", "/"); + + writer.writeStartElement("device"); + writer.writeTextElement("deviceType", "urn:schemas-upnp-org:device:Basic:1"); + writer.writeTextElement("friendlyName", "guhd"); + writer.writeTextElement("manufacturer", "guh"); + writer.writeTextElement("manufacturerURL", "http://guh.guru"); + writer.writeTextElement("modelDescription", "Home automation server"); + writer.writeTextElement("modelName", "guhd"); + writer.writeTextElement("modelNumber", GUH_VERSION_STRING); + writer.writeTextElement("modelURL", "http://guh.io"); // (optional) + writer.writeTextElement("UDN", "uuid:" + uuid); + + writer.writeStartElement("iconList"); + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "8"); + writer.writeTextElement("height", "8"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-8x8.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "16"); + writer.writeTextElement("height", "16"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-16x16.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "22"); + writer.writeTextElement("height", "22"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-22x22.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "32"); + writer.writeTextElement("height", "32"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-32x32.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "48"); + writer.writeTextElement("height", "48"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-48x48.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "64"); + writer.writeTextElement("height", "64"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-64x64.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "128"); + writer.writeTextElement("height", "128"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-128x128.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "256"); + writer.writeTextElement("height", "256"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-256x256.png"); + writer.writeEndElement(); // icon + + writer.writeStartElement("icon"); + writer.writeTextElement("mimetype", "image/png"); + writer.writeTextElement("width", "512"); + writer.writeTextElement("height", "512"); + writer.writeTextElement("depth", "24"); + writer.writeTextElement("url", "/icons/guh-logo-512x512.png"); + writer.writeEndElement(); // icon + + writer.writeEndElement(); // iconList + + writer.writeEndElement(); // device + writer.writeEndElement(); // root + writer.writeEndDocument(); + return data; +} + + WebServerClient::WebServerClient(const QHostAddress &address, QObject *parent): QObject(parent), m_address(address)