diff options
| author | 2016-04-29 23:57:30 +0100 | |
|---|---|---|
| committer | 2016-04-29 23:57:48 +0100 | |
| commit | 690dd7a33ddc90678367d73adf313533536e10f2 (patch) | |
| tree | 2276fe7c384ebbc222b40a19c536d5c3c5606ce8 /src/modules/upnp/Service.cpp | |
| parent | Add config for clang-format. (diff) | |
| download | KVIrc-690dd7a33ddc90678367d73adf313533536e10f2.tar.gz KVIrc-690dd7a33ddc90678367d73adf313533536e10f2.tar.bz2 KVIrc-690dd7a33ddc90678367d73adf313533536e10f2.zip | |
Apply clang-format
Diffstat (limited to 'src/modules/upnp/Service.cpp')
| -rw-r--r-- | src/modules/upnp/Service.cpp | 462 |
1 files changed, 219 insertions, 243 deletions
diff --git a/src/modules/upnp/Service.cpp b/src/modules/upnp/Service.cpp index 747250531..e0547bfc2 100644 --- a/src/modules/upnp/Service.cpp +++ b/src/modules/upnp/Service.cpp @@ -45,304 +45,280 @@ // http://www.knoxscape.com/Upnp/NAT.htm // http://www.artima.com/spontaneous/upnp_digihome2.html - namespace UPnP { - -// The constructor for information services -Service::Service(const QString &hostname, int port, const QString &informationUrl) -: m_iPendingRequests(0) -, m_szBaseXmlPrefix("s") -, m_szHostname(hostname) -, m_iPort(port) -{ - m_szInformationUrl = informationUrl; - qDebug() << "UPnP::Service: created information service url='" << m_szInformationUrl << "'." << endl; -} - - -// The constructor for action services -Service::Service(const ServiceParameters ¶ms) -: m_szControlUrl(params.controlUrl) -, m_szInformationUrl(params.scpdUrl) -, m_iPendingRequests(0) -, m_szServiceId(params.serviceId) -, m_szServiceType(params.serviceType) -, m_szBaseXmlPrefix("s") -, m_szHostname(params.hostname) -, m_iPort(params.port) -{ - qDebug() << "CREATED UPnP::Service: url='" << m_szControlUrl << "' id='" << m_szServiceId << "'." << endl; -} - - - -// The destructor -Service::~Service() -{ - qDebug() << "DESTROYED UPnP::Service [url=" << m_szControlUrl << ", id=" << m_szServiceId << "]" << endl; -} - - - -// Makes a UPnP action request -// TODO: rename to callMethod / callSoapMethod -int Service::callAction(const QString &actionName, const QString &prefix) -{ - return callActionInternal(actionName, 0, prefix); -} - - - -// Makes a UPnP action request -int Service::callAction(const QString &actionName, const QMap<QString,QString> &arguments, const QString &prefix) -{ - return callActionInternal(actionName, &arguments, prefix); -} - - - -// Makes a UPnP action request (keeps pointers from the external interface) -int Service::callActionInternal(const QString &actionName, const QMap<QString,QString> *arguments, const QString &prefix) -{ - qDebug() << "UPnP::Service: calling remote procedure '" << actionName << "'." << endl; - - // Create the data message - //NOTE: we shouldm use serviceId_ instead of serviceType_, but it seems that my router - // (and maybe others) are reporting wrong Ids, while they're gonna accepting only the - // correct ones. This is a decoded reply from my Zyxel: - - // Service : - // servicetype = urn:schemas-upnp-org:service:Layer3Forwarding:1 - // controlurl = /UD/act?0 - // eventsuburl = /?0 - // scpdurl = /L3Fwd.xml - // serviceid = urn:upnp-org:serviceId:L3Forwarding1 - - // this router wants us to use servicetype in the following requests - - QString soapMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" - "<" + m_szBaseXmlPrefix + ":Envelope xmlns:" + m_szBaseXmlPrefix + "=\"http://schemas.xmlsoap.org/soap/envelope/\"" - " " + m_szBaseXmlPrefix + ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" - " <" + m_szBaseXmlPrefix + ":Body>\n" - " <" + prefix + ":" + actionName + " xmlns:" + prefix + "=\"" + m_szServiceType + "\">\n"; - - // Do we have any arguments? - if(arguments != 0) + // The constructor for information services + Service::Service(const QString & hostname, int port, const QString & informationUrl) + : m_iPendingRequests(0), m_szBaseXmlPrefix("s"), m_szHostname(hostname), m_iPort(port) { - // Add the arguments - QMap<QString,QString>::const_iterator it; - for(it = arguments->begin(); it != arguments->end(); ++it) - { - QString argumentName = it.key(); - soapMessage += "<" + argumentName + ">" + it.value() + "</" + argumentName + ">"; - } + m_szInformationUrl = informationUrl; + qDebug() << "UPnP::Service: created information service url='" << m_szInformationUrl << "'." << endl; } - // Add the closing tags - soapMessage += " </" + prefix + ":" + actionName + ">\n </" + m_szBaseXmlPrefix + ":Body>\n</" + m_szBaseXmlPrefix + ":Envelope>\n"; - - // Get an utf8 encoding string - QByteArray content = soapMessage.toUtf8().data(); - - // Create the HTTP header - QNetworkRequest request; - request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml"); - request.setHeader(QNetworkRequest::ContentLengthHeader, content.size()); - request.setRawHeader("SOAPAction", QString("\"%1#%2\"").arg(m_szServiceType, actionName).toUtf8()); - - QString port; - port.setNum(m_iPort); - request.setRawHeader("HOST", QString("%1:%2").arg(m_szHostname, port).toUtf8()); - - QUrl url; - url.setHost(m_szHostname); - url.setPort(m_iPort); - request.setUrl(url); - - // Send the POST request - m_iPendingRequests++; - - QByteArray dummy; - QNetworkReply * pReply = KviNetworkAccessManager::getInstance()->post(request, dummy); - connect(pReply, SIGNAL(finished()), this, SLOT(slotRequestFinished())); - - return 0; -} - + // The constructor for action services + Service::Service(const ServiceParameters & params) + : m_szControlUrl(params.controlUrl), m_szInformationUrl(params.scpdUrl), m_iPendingRequests(0), m_szServiceId(params.serviceId), m_szServiceType(params.serviceType), m_szBaseXmlPrefix("s"), m_szHostname(params.hostname), m_iPort(params.port) + { + qDebug() << "CREATED UPnP::Service: url='" << m_szControlUrl << "' id='" << m_szServiceId << "'." << endl; + } + // The destructor + Service::~Service() + { + qDebug() << "DESTROYED UPnP::Service [url=" << m_szControlUrl << ", id=" << m_szServiceId << "]" << endl; + } + // Makes a UPnP action request + // TODO: rename to callMethod / callSoapMethod + int Service::callAction(const QString & actionName, const QString & prefix) + { + return callActionInternal(actionName, 0, prefix); + } -// Makes a UPnP service request -// TODO: rename to downloadFile() -int Service::callInformationUrl() -{ - qDebug() << "UPnP::Service: requesting file '" << m_szInformationUrl << "'." << endl; + // Makes a UPnP action request + int Service::callAction(const QString & actionName, const QMap<QString, QString> & arguments, const QString & prefix) + { + return callActionInternal(actionName, &arguments, prefix); + } - // Send the GET request - // TODO: User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1) - m_iPendingRequests++; + // Makes a UPnP action request (keeps pointers from the external interface) + int Service::callActionInternal(const QString & actionName, const QMap<QString, QString> * arguments, const QString & prefix) + { + qDebug() << "UPnP::Service: calling remote procedure '" << actionName << "'." << endl; - QNetworkRequest request; - QByteArray dummy; - QUrl url; - url.setHost(m_szHostname); - url.setPort(m_iPort); - url.setPath(m_szInformationUrl); - request.setUrl(url); - QNetworkReply * pReply = KviNetworkAccessManager::getInstance()->post(request, dummy); - connect(pReply, SIGNAL(finished()), this, SLOT(slotRequestFinished())); + // Create the data message + //NOTE: we shouldm use serviceId_ instead of serviceType_, but it seems that my router + // (and maybe others) are reporting wrong Ids, while they're gonna accepting only the + // correct ones. This is a decoded reply from my Zyxel: - return 0; -} + // Service : + // servicetype = urn:schemas-upnp-org:service:Layer3Forwarding:1 + // controlurl = /UD/act?0 + // eventsuburl = /?0 + // scpdurl = /L3Fwd.xml + // serviceid = urn:upnp-org:serviceId:L3Forwarding1 + // this router wants us to use servicetype in the following requests + QString soapMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<" + + m_szBaseXmlPrefix + ":Envelope xmlns:" + m_szBaseXmlPrefix + "=\"http://schemas.xmlsoap.org/soap/envelope/\"" + " " + + m_szBaseXmlPrefix + ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" + " <" + + m_szBaseXmlPrefix + ":Body>\n" + " <" + + prefix + ":" + actionName + " xmlns:" + prefix + "=\"" + m_szServiceType + "\">\n"; -// Get the number of pending requests -int Service::getPendingRequests() const -{ - return m_iPendingRequests; -} + // Do we have any arguments? + if(arguments != 0) + { + // Add the arguments + QMap<QString, QString>::const_iterator it; + for(it = arguments->begin(); it != arguments->end(); ++it) + { + QString argumentName = it.key(); + soapMessage += "<" + argumentName + ">" + it.value() + "</" + argumentName + ">"; + } + } + // Add the closing tags + soapMessage += " </" + prefix + ":" + actionName + ">\n </" + m_szBaseXmlPrefix + ":Body>\n</" + m_szBaseXmlPrefix + ":Envelope>\n"; -// The control point received an action failure indication -void Service::gotActionErrorResponse(const QDomNode &response) -{ - QString faultString = XmlFunctions::getNodeValue(response, "/faultstring"); - QString errorCode = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorCode"); - QString errorDescription = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorDescription"); - qWarning() << "UPnP::Service - Action failed: " << errorCode << " " << errorDescription << endl; -} + // Get an utf8 encoding string + QByteArray content = soapMessage.toUtf8().data(); + // Create the HTTP header + QNetworkRequest request; + request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml"); + request.setHeader(QNetworkRequest::ContentLengthHeader, content.size()); + request.setRawHeader("SOAPAction", QString("\"%1#%2\"").arg(m_szServiceType, actionName).toUtf8()); + QString port; + port.setNum(m_iPort); + request.setRawHeader("HOST", QString("%1:%2").arg(m_szHostname, port).toUtf8()); -// The control point received a response to callAction() -void Service::gotActionResponse(const QString &responseType, const QMap<QString,QString> &/*resultValues*/) -{ - qWarning() << "UPnP::Service - Action response '" << responseType << "' is not handled." << endl; -} + QUrl url; + url.setHost(m_szHostname); + url.setPort(m_iPort); + request.setUrl(url); + // Send the POST request + m_iPendingRequests++; + QByteArray dummy; + QNetworkReply * pReply = KviNetworkAccessManager::getInstance()->post(request, dummy); + connect(pReply, SIGNAL(finished()), this, SLOT(slotRequestFinished())); -// The control point received a response to callInformationUrl() -void Service::gotInformationResponse(const QDomNode &response) -{ - QString rootTagName = response.nodeName(); - qWarning() << "UPnP::Service - Service response (with root '" << rootTagName << "') is not handled." << endl; -} + return 0; + } + // Makes a UPnP service request + // TODO: rename to downloadFile() + int Service::callInformationUrl() + { + qDebug() << "UPnP::Service: requesting file '" << m_szInformationUrl << "'." << endl; + // Send the GET request + // TODO: User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1) + m_iPendingRequests++; -// The QHttp object retrieved data. -void Service::slotRequestFinished() -{ - QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); + QNetworkRequest request; + QByteArray dummy; + QUrl url; + url.setHost(m_szHostname); + url.setPort(m_iPort); + url.setPath(m_szInformationUrl); + request.setUrl(url); + QNetworkReply * pReply = KviNetworkAccessManager::getInstance()->post(request, dummy); + connect(pReply, SIGNAL(finished()), this, SLOT(slotRequestFinished())); - qDebug() << "UPnP::Service: received HTTP response for request " << endl; + return 0; + } - if(!reply) + // Get the number of pending requests + int Service::getPendingRequests() const { - qWarning() << "UPnP::Service - HTTP Request failed: " << reply->errorString() << endl; - m_iPendingRequests--; - emit queryFinished(true); - return; + return m_iPendingRequests; } - if (reply->error() != QNetworkReply::NoError) + // The control point received an action failure indication + void Service::gotActionErrorResponse(const QDomNode & response) { - qWarning() << "UPnP::Service - HTTP Request failed: " << reply->errorString() << endl; - m_iPendingRequests--; - emit queryFinished(true); - reply->deleteLater(); - return; + QString faultString = XmlFunctions::getNodeValue(response, "/faultstring"); + QString errorCode = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorCode"); + QString errorDescription = XmlFunctions::getNodeValue(response, "/detail/" + faultString + "/errorDescription"); + qWarning() << "UPnP::Service - Action failed: " << errorCode << " " << errorDescription << endl; } - // Get the XML content - QByteArray response = reply->readAll(); - QDomDocument xml; - - qDebug() << "Response:\n" << response << "\n---\n"; + // The control point received a response to callAction() + void Service::gotActionResponse(const QString & responseType, const QMap<QString, QString> & /*resultValues*/) + { + qWarning() << "UPnP::Service - Action response '" << responseType << "' is not handled." << endl; + } - // Parse the XML - QString errorMessage; - bool error = ! xml.setContent(response, false, &errorMessage); + // The control point received a response to callInformationUrl() + void Service::gotInformationResponse(const QDomNode & response) + { + QString rootTagName = response.nodeName(); + qWarning() << "UPnP::Service - Service response (with root '" << rootTagName << "') is not handled." << endl; + } - if(!error) + // The QHttp object retrieved data. + void Service::slotRequestFinished() { - //extract the xml prefix used by the device; should be "s" + QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender()); - //this is the reply of my Zyxel: - // <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" > - // <SOAP-ENV:Body> - // <u:GetDefaultConnectionServiceResponse xmlns:u="urn:schemas-upnp-org:service:Layer3Forwarding:1" > - // <NewDefaultConnectionService>WANIPConnection</NewDefaultConnectionService> - // </u:GetDefaultConnectionServiceResponse> - // </SOAP-ENV:Body> - // </SOAP-ENV:Envelope> + qDebug() << "UPnP::Service: received HTTP response for request " << endl; - QString baseNamespace = xml.documentElement().tagName(); + if(!reply) + { + qWarning() << "UPnP::Service - HTTP Request failed: " << reply->errorString() << endl; + m_iPendingRequests--; + emit queryFinished(true); + return; + } - if(baseNamespace.length() > 0) + if(reply->error() != QNetworkReply::NoError) { - int cutAt = baseNamespace.indexOf(':'); - if(cutAt > -1) - { - baseNamespace.truncate(cutAt); - qDebug() << "Device is using " << baseNamespace << " as XML namespace" << endl; - m_szBaseXmlPrefix = baseNamespace; - } + qWarning() << "UPnP::Service - HTTP Request failed: " << reply->errorString() << endl; + m_iPendingRequests--; + emit queryFinished(true); + reply->deleteLater(); + return; } - // Determine how to process the data - if(xml.namedItem(m_szBaseXmlPrefix + ":Envelope").isNull()) + // Get the XML content + QByteArray response = reply->readAll(); + QDomDocument xml; + + qDebug() << "Response:\n" << response << "\n---\n"; + + // Parse the XML + QString errorMessage; + bool error = !xml.setContent(response, false, &errorMessage); + + if(!error) { - qDebug() << "UPnP::Service: plain XML detected, calling gotInformationResponse()." << endl; - // No SOAP envelope found, this is a normal response to callService() - gotInformationResponse( xml.lastChild() ); - } else { - qDebug() << xml.toString() << endl; - // Got a SOAP message response to callAction() - QDomNode resultNode = XmlFunctions::getNode(xml, "/" + m_szBaseXmlPrefix + ":Envelope/" + m_szBaseXmlPrefix + ":Body").firstChild(); + //extract the xml prefix used by the device; should be "s" - error = (resultNode.nodeName() == m_szBaseXmlPrefix + ":Fault"); + //this is the reply of my Zyxel: + // <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" > + // <SOAP-ENV:Body> + // <u:GetDefaultConnectionServiceResponse xmlns:u="urn:schemas-upnp-org:service:Layer3Forwarding:1" > + // <NewDefaultConnectionService>WANIPConnection</NewDefaultConnectionService> + // </u:GetDefaultConnectionServiceResponse> + // </SOAP-ENV:Body> + // </SOAP-ENV:Envelope> - if(! error) + QString baseNamespace = xml.documentElement().tagName(); + + if(baseNamespace.length() > 0) { - if(resultNode.nodeName().startsWith("m:") || resultNode.nodeName().startsWith("u:")) + int cutAt = baseNamespace.indexOf(':'); + if(cutAt > -1) { - qDebug() << "UPnP::Service: SOAP envelope detected, calling gotActionResponse()." << endl; - // Action success, return SOAP body - QMap<QString,QString> resultValues; + baseNamespace.truncate(cutAt); + qDebug() << "Device is using " << baseNamespace << " as XML namespace" << endl; + m_szBaseXmlPrefix = baseNamespace; + } + } - // Parse all parameters - // It's possible to pass the entire QDomNode object to the gotActionResponse() - // function, but this is somewhat nicer, and reduces code boat in the subclasses - QDomNodeList children = resultNode.childNodes(); - for(int i = 0; i < children.count(); i++) + // Determine how to process the data + if(xml.namedItem(m_szBaseXmlPrefix + ":Envelope").isNull()) + { + qDebug() << "UPnP::Service: plain XML detected, calling gotInformationResponse()." << endl; + // No SOAP envelope found, this is a normal response to callService() + gotInformationResponse(xml.lastChild()); + } + else + { + qDebug() << xml.toString() << endl; + // Got a SOAP message response to callAction() + QDomNode resultNode = XmlFunctions::getNode(xml, "/" + m_szBaseXmlPrefix + ":Envelope/" + m_szBaseXmlPrefix + ":Body").firstChild(); + + error = (resultNode.nodeName() == m_szBaseXmlPrefix + ":Fault"); + + if(!error) + { + if(resultNode.nodeName().startsWith("m:") || resultNode.nodeName().startsWith("u:")) { - QString key = children.item(i).nodeName(); - resultValues[ key ] = children.item(i).toElement().text(); - } + qDebug() << "UPnP::Service: SOAP envelope detected, calling gotActionResponse()." << endl; + // Action success, return SOAP body + QMap<QString, QString> resultValues; + + // Parse all parameters + // It's possible to pass the entire QDomNode object to the gotActionResponse() + // function, but this is somewhat nicer, and reduces code boat in the subclasses + QDomNodeList children = resultNode.childNodes(); + for(int i = 0; i < children.count(); i++) + { + QString key = children.item(i).nodeName(); + resultValues[key] = children.item(i).toElement().text(); + } - // Call the gotActionResponse() - gotActionResponse(resultNode.nodeName().mid(2), resultValues); + // Call the gotActionResponse() + gotActionResponse(resultNode.nodeName().mid(2), resultValues); + } } - } else { - qDebug() << "UPnP::Service: SOAP error detected, calling gotActionResponse()." << endl; + else + { + qDebug() << "UPnP::Service: SOAP error detected, calling gotActionResponse()." << endl; - // Action failed - gotActionErrorResponse(resultNode); + // Action failed + gotActionErrorResponse(resultNode); + } } } - } else { - qWarning() << "UPnP::Service - XML parsing failed: " << errorMessage << endl; - } - - // Only emit when bytes>0 - m_iPendingRequests--; - emit queryFinished(error); -} + else + { + qWarning() << "UPnP::Service - XML parsing failed: " << errorMessage << endl; + } + // Only emit when bytes>0 + m_iPendingRequests--; + emit queryFinished(error); + } } // end of namespace |
