fix upnp server t0 be more standard compliant

This commit is contained in:
Michael Zanetti 2018-06-05 15:44:28 +02:00
parent f160a92f92
commit 80b444a62a
2 changed files with 60 additions and 62 deletions

View File

@ -128,27 +128,41 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int
// TODO: Once DeviceManager (and with that this can be moved into the server, use NymeaCore's configuration manager instead of parsing the config here...
NymeaSettings globalSettings(NymeaSettings::SettingsRoleGlobal);
globalSettings.beginGroup("nymead");
QByteArray uuid = globalSettings.value("uuid", QUuid()).toByteArray();
QByteArray uuid = globalSettings.value("uuid", QUuid()).toString().remove(QRegExp("[{}]")).toUtf8();
globalSettings.endGroup();
globalSettings.beginGroup("WebServer");
int serverPort = -1;
bool useSsl = false;
bool useSSL = false;
foreach (const QString &group, globalSettings.childGroups()) {
globalSettings.beginGroup(group);
QHostAddress serverInterface = QHostAddress(globalSettings.value("address").toString());
if (serverInterface == host || serverInterface == QHostAddress("0.0.0.0")) {
serverPort = globalSettings.value("port", -1).toInt();
useSsl = globalSettings.value("sslEnabled", true).toBool();
}
bool ssl = globalSettings.value("sslEnabled", true).toBool();
int port = globalSettings.value("port", -1).toInt();
globalSettings.endGroup();
// We prefer unencrypted WebServers in this case. Most UPnP clients will bail out on our certificate...
// However, if there is none without encryption, still use one with, so that at least our own clients find it.
if (serverPort == -1) { // Don't have a better option yet. Use this.
serverPort = port;
useSSL = ssl;
continue;
}
if (!ssl && useSSL) { // There is one without ssl. Use that.
serverPort = port;
useSSL = false;
break;
}
}
globalSettings.endGroup();
if (serverPort == -1) {
qCWarning(dcConnection) << "No matching WebServer configuration found. Discarding UPnP request!";
qCWarning(dcUpnp()) << "No matching WebServer configuration found. Discarding UPnP request! UPnP requires a plaintext webserver.";
return;
}
if (useSSL) {
qCWarning(dcUpnp()) << "Could not find a WebServer without SSL. Using one with SSL. This will not work with many clients.";
}
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
foreach (QNetworkAddressEntry entry, interface.addressEntries()) {
@ -157,7 +171,7 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int
// check subnet
if (host.isInSubnet(QHostAddress::parseSubnet(entry.ip().toString() + "/24"))) {
QString locationString;
if (useSsl) {
if (useSSL) {
locationString = "https://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml";
} else {
locationString = "http://" + entry.ip().toString() + ":" + QString::number(serverPort) + "/server.xml";
@ -168,11 +182,10 @@ void UpnpDiscoveryImplementation::respondToSearchRequest(QHostAddress host, int
"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: nymea/" + QByteArray(NYMEA_VERSION_STRING) + " UPnP/1.1 \r\n"
"ST:upnp:rootdevice\r\n"
"USN:uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n"
"ST: upnp:rootdevice\r\n"
"USN: uuid:" + uuid + "::urn:schemas-upnp-org:device:Basic:1\r\n"
"\r\n");
qCDebug(dcUpnp()) << QString("Sending response to %1:%2").arg(host.toString()).arg(port);

View File

@ -605,7 +605,7 @@ bool WebServer::stopServer()
QByteArray WebServer::createServerXmlDocument(QHostAddress address)
{
QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toByteArray();
QByteArray uuid = NymeaCore::instance()->configuration()->serverUuid().toString().remove(QRegExp("[{}]")).toUtf8();
QByteArray data;
QXmlStreamWriter writer(&data);
@ -619,57 +619,12 @@ QByteArray WebServer::createServerXmlDocument(QHostAddress address)
writer.writeTextElement("minor", "1");
writer.writeEndElement(); // specVersion
if (m_configuration.sslEnabled) {
writer.writeTextElement("URLBase", "https://" + address.toString() + ":" + QString::number(m_configuration.port));
} else {
writer.writeTextElement("URLBase", "http://" + address.toString() + ":" + QString::number(m_configuration.port));
}
ServerConfiguration websocketConfiguration;
bool webSocketServerFound = false;
foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->webSocketServerConfigurations()) {
if (config.address == QHostAddress("0.0.0.0") || config.address == address) {
if (!webSocketServerFound) {
websocketConfiguration = config;
webSocketServerFound = true;
} else if (!websocketConfiguration.sslEnabled && config.sslEnabled) {
// If the previous one is plaintext but we also have a secure one, upgrade to that.
websocketConfiguration = config;
}
}
}
if (webSocketServerFound) {
if (websocketConfiguration.sslEnabled) {
writer.writeTextElement("websocketURL", "wss://" + address.toString() + ":" + QString::number(websocketConfiguration.port));
} else {
writer.writeTextElement("websocketURL", "ws://" + address.toString() + ":" + QString::number(websocketConfiguration.port));
}
}
ServerConfiguration tcpServerConfiguration;
bool tcpServerFound = false;
foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->tcpServerConfigurations()) {
if (config.address == QHostAddress("0.0.0.0") || config.address == address) {
if (!tcpServerFound) {
tcpServerConfiguration = config;
tcpServerFound = true;
} else if (!tcpServerConfiguration.sslEnabled && config.sslEnabled) {
// If the previous one is plaintext but we also have a secure one, upgrade to that.
tcpServerConfiguration = config;
}
}
}
if (tcpServerFound) {
if (tcpServerConfiguration.sslEnabled) {
writer.writeTextElement("nymeaRpcURL", "nymeas://" + address.toString() + ":" + QString::number(tcpServerConfiguration.port));
} else {
writer.writeTextElement("nymeaRpcURL", "nymea://" + address.toString() + ":" + QString::number(tcpServerConfiguration.port));
}
}
writer.writeTextElement("presentationURL", "/");
QString presentationUrl = QString("%1://%2:%3")
.arg(m_configuration.sslEnabled ? "https" : "http")
.arg(address.toString())
.arg(m_configuration.port);
writer.writeStartElement("device");
writer.writeTextElement("presentationURL", presentationUrl);
writer.writeTextElement("deviceType", "urn:schemas-upnp-org:device:Basic:1");
writer.writeTextElement("friendlyName", NymeaCore::instance()->configuration()->serverName());
writer.writeTextElement("manufacturer", "guh GmbH");
@ -764,6 +719,36 @@ QByteArray WebServer::createServerXmlDocument(QHostAddress address)
writer.writeEndElement(); // iconList
writer.writeStartElement("serviceList");
int counter = 1;
int sslCounter = 1;
foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->webSocketServerConfigurations()) {
if (config.address == QHostAddress("0.0.0.0") || config.address == address) {
writer.writeStartElement("service");
writer.writeTextElement("serviceType", QString("urn:nymea.io:service:%1:%2").arg(config.sslEnabled ? "wss" : "ws").arg(config.sslEnabled ? sslCounter : counter));
writer.writeTextElement("serviceId", QString("urn:nymea.io:serviceId:%1:%2").arg(config.sslEnabled ? "wss" : "ws").arg(config.sslEnabled ? sslCounter++ : counter++));
QString url = QString("%1%2:%3").arg(config.sslEnabled ? "wss://" : "ws://").arg(address.toString()).arg(config.port);
writer.writeTextElement("SCPDURL", url);
writer.writeEndElement(); // service
}
}
counter = 1;
sslCounter = 1;
foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->tcpServerConfigurations()) {
if (config.address == QHostAddress("0.0.0.0") || config.address == address) {
writer.writeStartElement("service");
writer.writeTextElement("serviceType", QString("urn:nymea.io:service:%1:%2").arg(config.sslEnabled ? "nymeas" : "nymea").arg(config.sslEnabled ? sslCounter : counter));
writer.writeTextElement("serviceId", QString("urn:nymea.io:serviceId:%1:%2").arg(config.sslEnabled ? "nymeas" : "nymea").arg(config.sslEnabled ? sslCounter++ : counter++));
QString url = QString("%1%2:%3").arg(config.sslEnabled ? "nymeas://" : "nymea://").arg(address.toString()).arg(config.port);
writer.writeTextElement("SCPDURL", url);
writer.writeEndElement(); // service
}
}
writer.writeEndElement(); // serviceList
writer.writeEndElement(); // device
writer.writeEndElement(); // root
writer.writeEndDocument();