mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-31 18:36:24 -05:00
329050a9c2
Avoid problems to serialization on different platforms, without breaking nested STL containers serialization. The conversion have been made with sed, and checked with grep, plus kdiff3 visual ispection, plus rutime tests, so it should be fine.
1779 lines
54 KiB
C++
1779 lines
54 KiB
C++
//
|
|
// This file is part of the aMule Project.
|
|
//
|
|
// Copyright (c) 2004-2009 Marcelo Roberto Jimenez ( phoenix@amule.org )
|
|
// Copyright (c) 2006-2009 aMule Team ( admin@amule.org / http://www.amule.org )
|
|
// Copyright (c) 2009-2010 Retroshare Team
|
|
//
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
// You are also granted to use it with the LGPL License
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License or the LGPL
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
//
|
|
|
|
//This file uses libupnp
|
|
|
|
#define UPNP_C
|
|
|
|
#include "UPnPBase.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sstream> // for std::istringstream
|
|
|
|
#include <algorithm> // For transform()
|
|
#include "util/rsstring.h"
|
|
|
|
#ifdef __GNUC__
|
|
#if __GNUC__ >= 4
|
|
#define REINTERPRET_CAST(x) reinterpret_cast<x>
|
|
#endif
|
|
#endif
|
|
#ifndef REINTERPRET_CAST
|
|
// Let's hope that function pointers are equal in size to data pointers
|
|
#define REINTERPRET_CAST(x) (x)
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Case insensitive std::string comparison
|
|
*/
|
|
bool stdStringIsEqualCI(const std::string &s1, const std::string &s2)
|
|
{
|
|
std::string ns1(s1);
|
|
std::string ns2(s2);
|
|
std::transform(ns1.begin(), ns1.end(), ns1.begin(), tolower);
|
|
std::transform(ns2.begin(), ns2.end(), ns2.begin(), tolower);
|
|
return ns1 == ns2;
|
|
}
|
|
|
|
|
|
CUPnPPortMapping::CUPnPPortMapping(
|
|
int ex_port,
|
|
int in_port,
|
|
const std::string &protocol,
|
|
bool enabled,
|
|
const std::string &description)
|
|
:
|
|
m_ex_port(),
|
|
m_in_port(),
|
|
m_protocol(protocol),
|
|
m_enabled(enabled ? "1" : "0"),
|
|
m_description(description),
|
|
m_key()
|
|
{
|
|
rs_sprintf(m_ex_port, "%d", ex_port);
|
|
rs_sprintf(m_in_port, "%d", in_port);
|
|
m_key = m_protocol + m_ex_port;
|
|
}
|
|
|
|
|
|
const std::string &CUPnPLib::UPNP_ROOT_DEVICE =
|
|
"upnp:rootdevice";
|
|
|
|
const std::string &CUPnPLib::UPNP_DEVICE_IGW =
|
|
"urn:schemas-upnp-org:device:InternetGatewayDevice:1";
|
|
const std::string &CUPnPLib::UPNP_DEVICE_WAN =
|
|
"urn:schemas-upnp-org:device:WANDevice:1";
|
|
const std::string &CUPnPLib::UPNP_DEVICE_WAN_CONNECTION =
|
|
"urn:schemas-upnp-org:device:WANConnectionDevice:1";
|
|
const std::string &CUPnPLib::UPNP_DEVICE_LAN =
|
|
"urn:schemas-upnp-org:device:LANDevice:1";
|
|
|
|
const std::string &CUPnPLib::UPNP_SERVICE_LAYER3_FORWARDING =
|
|
"urn:schemas-upnp-org:service:Layer3Forwarding:1";
|
|
const std::string &CUPnPLib::UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG =
|
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1";
|
|
const std::string &CUPnPLib::UPNP_SERVICE_WAN_IP_CONNECTION =
|
|
"urn:schemas-upnp-org:service:WANIPConnection:1";
|
|
const std::string &CUPnPLib::UPNP_SERVICE_WAN_PPP_CONNECTION =
|
|
"urn:schemas-upnp-org:service:WANPPPConnection:1";
|
|
|
|
|
|
CUPnPLib::CUPnPLib(CUPnPControlPoint &ctrlPoint)
|
|
:
|
|
m_ctrlPoint(ctrlPoint)
|
|
{
|
|
}
|
|
|
|
|
|
std::string CUPnPLib::GetUPnPErrorMessage(int code) const
|
|
{
|
|
return UpnpGetErrorMessage(code);
|
|
}
|
|
|
|
|
|
std::string CUPnPLib::processUPnPErrorMessage(
|
|
const std::string &message,
|
|
int errorCode,
|
|
const DOMString errorString,
|
|
IXML_Document *doc) const
|
|
{
|
|
/* remove unused parameter warnings */
|
|
(void) message;
|
|
(void) errorCode;
|
|
(void) errorString;
|
|
(void) doc;
|
|
|
|
std::string msg;
|
|
#ifdef UPNP_DEBUG
|
|
if (errorString == NULL || *errorString == 0) {
|
|
errorString = "Not available";
|
|
}
|
|
if (errorCode > 0) {
|
|
std::cerr << "CUPnPLib::processUPnPErrorMessage() Error: " <<
|
|
message <<
|
|
": Error code :'";
|
|
if (doc) {
|
|
CUPnPError e(*this, doc);
|
|
std::cerr << e.getErrorCode() <<
|
|
"', Error description :'" <<
|
|
e.getErrorDescription() <<
|
|
"'.";
|
|
} else {
|
|
std::cerr << errorCode <<
|
|
"', Error description :'" <<
|
|
errorString <<
|
|
"'.";
|
|
}
|
|
std::cerr << std::endl;
|
|
} else {
|
|
std::cerr << "CUPnPLib::processUPnPErrorMessage() Error: " <<
|
|
message <<
|
|
": UPnP SDK error: " <<
|
|
GetUPnPErrorMessage(errorCode) <<
|
|
" (" << errorCode << ").";
|
|
std::cerr << std::endl;
|
|
}
|
|
#endif
|
|
return msg;
|
|
}
|
|
|
|
|
|
void CUPnPLib::ProcessActionResponse(
|
|
IXML_Document *RespDoc,
|
|
const std::string &actionName) const
|
|
{
|
|
/* remove unused parameter warnings */
|
|
(void) actionName;
|
|
|
|
IXML_Element *root = Element_GetRootElement(RespDoc);
|
|
IXML_Element *child = Element_GetFirstChild(root);
|
|
if (child) {
|
|
while (child) {
|
|
const DOMString childTag = Element_GetTag(child);
|
|
std::string childValue = Element_GetTextValue(child);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPLib::ProcessActionResponse() \n " <<
|
|
childTag << "='" <<
|
|
childValue << "'";
|
|
#endif
|
|
//add the variable to the wanservice property map
|
|
(m_ctrlPoint.m_WanService->propertyMap)[std::string(childTag)] = std::string(childValue);
|
|
child = Element_GetNextSibling(child);
|
|
}
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPLib::ProcessActionResponse() \n Empty response for action '" <<
|
|
actionName << "'.";
|
|
#endif
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the root node of a given document.
|
|
*/
|
|
IXML_Element *CUPnPLib::Element_GetRootElement(
|
|
IXML_Document *doc) const
|
|
{
|
|
IXML_Element *root = REINTERPRET_CAST(IXML_Element *)(
|
|
ixmlNode_getFirstChild(
|
|
REINTERPRET_CAST(IXML_Node *)(doc)));
|
|
|
|
return root;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the first child of a given element.
|
|
*/
|
|
IXML_Element *CUPnPLib::Element_GetFirstChild(
|
|
IXML_Element *parent) const
|
|
{
|
|
IXML_Node *node = REINTERPRET_CAST(IXML_Node *)(parent);
|
|
IXML_Node *child = ixmlNode_getFirstChild(node);
|
|
|
|
return REINTERPRET_CAST(IXML_Element *)(child);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the next sibling of a given child.
|
|
*/
|
|
IXML_Element *CUPnPLib::Element_GetNextSibling(
|
|
IXML_Element *child) const
|
|
{
|
|
IXML_Node *node = REINTERPRET_CAST(IXML_Node *)(child);
|
|
IXML_Node *sibling = ixmlNode_getNextSibling(node);
|
|
|
|
return REINTERPRET_CAST(IXML_Element *)(sibling);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the element tag (name)
|
|
*/
|
|
const DOMString CUPnPLib::Element_GetTag(
|
|
IXML_Element *element) const
|
|
{
|
|
IXML_Node *node = REINTERPRET_CAST(IXML_Node *)(element);
|
|
const DOMString tag = ixmlNode_getNodeName(node);
|
|
|
|
return tag;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the TEXT node value of the current node.
|
|
*/
|
|
const std::string CUPnPLib::Element_GetTextValue(
|
|
IXML_Element *element) const
|
|
{
|
|
if (!element) {
|
|
return stdEmptyString;
|
|
}
|
|
IXML_Node *text = ixmlNode_getFirstChild(
|
|
REINTERPRET_CAST(IXML_Node *)(element));
|
|
const DOMString s = ixmlNode_getNodeValue(text);
|
|
std::string ret;
|
|
if (s) {
|
|
ret = s;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the TEXT node value of the first child matching tag.
|
|
*/
|
|
const std::string CUPnPLib::Element_GetChildValueByTag(
|
|
IXML_Element *element,
|
|
const DOMString tag) const
|
|
{
|
|
IXML_Element *child =
|
|
Element_GetFirstChildByTag(element, tag);
|
|
|
|
return Element_GetTextValue(child);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the first child element that matches the requested tag or
|
|
* NULL if not found.
|
|
*/
|
|
IXML_Element *CUPnPLib::Element_GetFirstChildByTag(
|
|
IXML_Element *element,
|
|
const DOMString tag) const
|
|
{
|
|
if (!element || !tag) {
|
|
return NULL;
|
|
}
|
|
|
|
IXML_Node *node = REINTERPRET_CAST(IXML_Node *)(element);
|
|
IXML_Node *child = ixmlNode_getFirstChild(node);
|
|
const DOMString childTag = ixmlNode_getNodeName(child);
|
|
while(child && childTag && strcmp(tag, childTag)) {
|
|
child = ixmlNode_getNextSibling(child);
|
|
childTag = ixmlNode_getNodeName(child);
|
|
}
|
|
|
|
return REINTERPRET_CAST(IXML_Element *)(child);
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief Returns the next sibling element that matches the requested tag. Should be
|
|
* used with the return value of Element_GetFirstChildByTag().
|
|
*/
|
|
IXML_Element *CUPnPLib::Element_GetNextSiblingByTag(
|
|
IXML_Element *element, const DOMString tag) const
|
|
{
|
|
if (!element || !tag) {
|
|
return NULL;
|
|
}
|
|
|
|
IXML_Node *child = REINTERPRET_CAST(IXML_Node *)(element);
|
|
const DOMString childTag = NULL;
|
|
do {
|
|
child = ixmlNode_getNextSibling(child);
|
|
childTag = ixmlNode_getNodeName(child);
|
|
} while(child && childTag && strcmp(tag, childTag));
|
|
|
|
return REINTERPRET_CAST(IXML_Element *)(child);
|
|
}
|
|
|
|
|
|
const std::string CUPnPLib::Element_GetAttributeByTag(
|
|
IXML_Element *element, const DOMString tag) const
|
|
{
|
|
IXML_NamedNodeMap *NamedNodeMap = ixmlNode_getAttributes(
|
|
REINTERPRET_CAST(IXML_Node *)(element));
|
|
IXML_Node *attribute = ixmlNamedNodeMap_getNamedItem(NamedNodeMap, tag);
|
|
const DOMString s = ixmlNode_getNodeValue(attribute);
|
|
std::string ret;
|
|
if (s) {
|
|
ret = s;
|
|
}
|
|
ixmlNamedNodeMap_free(NamedNodeMap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
CUPnPError::CUPnPError(
|
|
const CUPnPLib &upnpLib,
|
|
IXML_Document *errorDoc)
|
|
:
|
|
m_root (upnpLib.Element_GetRootElement(errorDoc)),
|
|
m_ErrorCode (upnpLib.Element_GetChildValueByTag(m_root, "errorCode")),
|
|
m_ErrorDescription(upnpLib.Element_GetChildValueByTag(m_root, "errorDescription"))
|
|
{
|
|
}
|
|
|
|
|
|
CUPnPArgument::CUPnPArgument(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *argument,
|
|
const std::string &/*SCPDURL*/)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_name (upnpLib.Element_GetChildValueByTag(argument, "name")),
|
|
m_direction (upnpLib.Element_GetChildValueByTag(argument, "direction")),
|
|
m_retval (upnpLib.Element_GetFirstChildByTag(argument, "retval")),
|
|
m_relatedStateVariable(upnpLib.Element_GetChildValueByTag(argument, "relatedStateVariable"))
|
|
{
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPArgument::CUPnPArgument() \n Argument:" <<
|
|
"\n name: " << m_name <<
|
|
"\n direction: " << m_direction <<
|
|
"\n retval: " << m_retval <<
|
|
"\n relatedStateVariable: " << m_relatedStateVariable;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPAction::CUPnPAction(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *action,
|
|
const std::string &SCPDURL)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_ArgumentList(upnpControlPoint, upnpLib, action, SCPDURL),
|
|
m_name(upnpLib.Element_GetChildValueByTag(action, "name"))
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPAction::CUPnPAction() \n Action:" <<
|
|
"\n name: " << m_name;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPAllowedValue::CUPnPAllowedValue(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *allowedValue,
|
|
const std::string &/*SCPDURL*/)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_allowedValue(upnpLib.Element_GetTextValue(allowedValue))
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPAllowedValue::CUPnPAllowedValue() \n AllowedValue:" <<
|
|
"\n allowedValue: " << m_allowedValue;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPStateVariable::CUPnPStateVariable(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *stateVariable,
|
|
const std::string &SCPDURL)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_AllowedValueList(upnpControlPoint, upnpLib, stateVariable, SCPDURL),
|
|
m_name (upnpLib.Element_GetChildValueByTag(stateVariable, "name")),
|
|
m_dataType (upnpLib.Element_GetChildValueByTag(stateVariable, "dataType")),
|
|
m_defaultValue(upnpLib.Element_GetChildValueByTag(stateVariable, "defaultValue")),
|
|
m_sendEvents (upnpLib.Element_GetAttributeByTag (stateVariable, "sendEvents"))
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPStateVariable::CUPnPStateVariable() \n StateVariable:" <<
|
|
"\n name: " << m_name <<
|
|
"\n dataType: " << m_dataType <<
|
|
"\n defaultValue: " << m_defaultValue <<
|
|
"\n sendEvents: " << m_sendEvents;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPSCPD::CUPnPSCPD(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *scpd,
|
|
const std::string &SCPDURL)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_ActionList(upnpControlPoint, upnpLib, scpd, SCPDURL),
|
|
m_ServiceStateTable(upnpControlPoint, upnpLib, scpd, SCPDURL),
|
|
m_SCPDURL(SCPDURL)
|
|
{
|
|
}
|
|
|
|
|
|
CUPnPArgumentValue::CUPnPArgumentValue()
|
|
:
|
|
m_argument(),
|
|
m_value()
|
|
{
|
|
}
|
|
|
|
|
|
CUPnPArgumentValue::CUPnPArgumentValue(
|
|
const std::string &argument, const std::string &value)
|
|
:
|
|
m_argument(argument),
|
|
m_value(value)
|
|
{
|
|
}
|
|
|
|
|
|
CUPnPService::CUPnPService(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *service,
|
|
const std::string &URLBase)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_upnpLib(upnpLib),
|
|
m_serviceType(upnpLib.Element_GetChildValueByTag(service, "serviceType")),
|
|
m_serviceId (upnpLib.Element_GetChildValueByTag(service, "serviceId")),
|
|
m_SCPDURL (upnpLib.Element_GetChildValueByTag(service, "SCPDURL")),
|
|
m_controlURL (upnpLib.Element_GetChildValueByTag(service, "controlURL")),
|
|
m_eventSubURL(upnpLib.Element_GetChildValueByTag(service, "eventSubURL")),
|
|
m_timeout(1801),
|
|
m_SCPD(NULL)
|
|
{
|
|
int errcode;
|
|
|
|
std::vector<char> vscpdURL(URLBase.length() + m_SCPDURL.length() + 1);
|
|
char *scpdURL = &vscpdURL[0];
|
|
errcode = UpnpResolveURL(
|
|
URLBase.c_str(),
|
|
m_SCPDURL.c_str(),
|
|
scpdURL);
|
|
if( errcode != UPNP_E_SUCCESS ) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() Error generating scpdURL from " <<
|
|
"|" << URLBase << "|" <<
|
|
m_SCPDURL << "|.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
} else {
|
|
m_absSCPDURL = scpdURL;
|
|
}
|
|
|
|
std::vector<char> vcontrolURL(
|
|
URLBase.length() + m_controlURL.length() + 1);
|
|
char *controlURL = &vcontrolURL[0];
|
|
errcode = UpnpResolveURL(
|
|
URLBase.c_str(),
|
|
m_controlURL.c_str(),
|
|
controlURL);
|
|
if( errcode != UPNP_E_SUCCESS ) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() Error generating controlURL from " <<
|
|
"|" << URLBase << "|" <<
|
|
m_controlURL << "|.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
} else {
|
|
m_absControlURL = controlURL;
|
|
}
|
|
|
|
std::vector<char> veventURL(
|
|
URLBase.length() + m_eventSubURL.length() + 1);
|
|
char *eventURL = &veventURL[0];
|
|
errcode = UpnpResolveURL(
|
|
URLBase.c_str(),
|
|
m_eventSubURL.c_str(),
|
|
eventURL);
|
|
if( errcode != UPNP_E_SUCCESS ) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() Error generating eventURL from " <<
|
|
"|" << URLBase << "|" <<
|
|
m_eventSubURL << "|.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
} else {
|
|
m_absEventSubURL = eventURL;
|
|
}
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() \n Service:" <<
|
|
"\n serviceType: " << m_serviceType <<
|
|
"\n serviceId: " << m_serviceId <<
|
|
"\n SCPDURL: " << m_SCPDURL <<
|
|
"\n absSCPDURL: " << m_absSCPDURL <<
|
|
"\n controlURL: " << m_controlURL <<
|
|
"\n absControlURL: " << m_absControlURL <<
|
|
"\n eventSubURL: " << m_eventSubURL <<
|
|
"\n absEventSubURL: " << m_absEventSubURL;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
if (m_serviceType == upnpLib.UPNP_SERVICE_WAN_IP_CONNECTION ||
|
|
m_serviceType == upnpLib.UPNP_SERVICE_WAN_PPP_CONNECTION) {
|
|
#if 0
|
|
m_serviceType == upnpLib.UPNP_SERVICE_WAN_PPP_CONNECTION ||
|
|
m_serviceType == upnpLib.UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG ||
|
|
m_serviceType == upnpLib.UPNP_SERVICE_LAYER3_FORWARDING) {
|
|
#endif
|
|
#if 0
|
|
//#warning Delete this code on release.
|
|
if (!upnpLib.m_ctrlPoint.WanServiceDetected()) {
|
|
// This condition can be used to suspend the parse
|
|
// of the XML tree.
|
|
#endif
|
|
//#warning Delete this code when m_WanService is no longer used.
|
|
upnpLib.m_ctrlPoint.SetWanService(this);
|
|
// Log it
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() WAN Service Detected: '" <<
|
|
m_serviceType << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
// Subscribe
|
|
upnpLib.m_ctrlPoint.Subscribe(*this);
|
|
#if 0
|
|
//#warning Delete this code on release.
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "WAN service detected again: '" <<
|
|
m_serviceType <<
|
|
"'. Will only use the first instance.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
#endif
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::CUPnPService() Uninteresting service detected: '" <<
|
|
m_serviceType << "'. Ignoring.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
CUPnPService::~CUPnPService()
|
|
{
|
|
}
|
|
|
|
|
|
bool CUPnPService::Execute(
|
|
const std::string &ActionName,
|
|
const std::vector<CUPnPArgumentValue> &ArgValue) const
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() called." << std::endl;
|
|
#endif
|
|
if (m_SCPD.get() == NULL) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Service without SCPD Document, cannot execute action '" << ActionName <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Sending action " << std::endl;
|
|
#endif
|
|
// Check for correct action name
|
|
ActionList::const_iterator itAction =
|
|
m_SCPD->GetActionList().find(ActionName);
|
|
if (itAction == m_SCPD->GetActionList().end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() invalid action name '" << ActionName <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << ActionName << "(";
|
|
#endif
|
|
bool firstTime = true;
|
|
// Check for correct Argument/Value pairs
|
|
const CUPnPAction &action = *(itAction->second);
|
|
for (unsigned int i = 0; i < ArgValue.size(); ++i) {
|
|
ArgumentList::const_iterator itArg =
|
|
action.GetArgumentList().find(ArgValue[i].GetArgument());
|
|
if (itArg == action.GetArgumentList().end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Invalid argument name '" << ArgValue[i].GetArgument() <<
|
|
"' for action '" << action.GetName() <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
const CUPnPArgument &argument = *(itArg->second);
|
|
if (tolower(argument.GetDirection()[0]) != 'i' ||
|
|
tolower(argument.GetDirection()[1]) != 'n') {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Invalid direction for argument '" <<
|
|
ArgValue[i].GetArgument() <<
|
|
"' for action '" << action.GetName() <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
const std::string relatedStateVariableName =
|
|
argument.GetRelatedStateVariable();
|
|
if (!relatedStateVariableName.empty()) {
|
|
ServiceStateTable::const_iterator itSVT =
|
|
m_SCPD->GetServiceStateTable().
|
|
find(relatedStateVariableName);
|
|
if (itSVT == m_SCPD->GetServiceStateTable().end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Inconsistent Service State Table, did not find '" <<
|
|
relatedStateVariableName <<
|
|
"' for argument '" << argument.GetName() <<
|
|
"' for action '" << action.GetName() <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
const CUPnPStateVariable &stateVariable = *(itSVT->second);
|
|
if ( !stateVariable.GetAllowedValueList().empty() &&
|
|
stateVariable.GetAllowedValueList().find(ArgValue[i].GetValue()) ==
|
|
stateVariable.GetAllowedValueList().end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Value not allowed '" << ArgValue[i].GetValue() <<
|
|
"' for state variable '" << relatedStateVariableName <<
|
|
"' for argument '" << argument.GetName() <<
|
|
"' for action '" << action.GetName() <<
|
|
"' for service '" << GetServiceType() << "'.";
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
}
|
|
if (firstTime) {
|
|
firstTime = false;
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << ", ";
|
|
#endif
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr <<
|
|
ArgValue[i].GetArgument() <<
|
|
"='" <<
|
|
ArgValue[i].GetValue() <<
|
|
"'";
|
|
#endif
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << ")" << std::endl;
|
|
#endif
|
|
// Everything is ok, make the action
|
|
IXML_Document *ActionDoc = NULL;
|
|
if (ArgValue.size()) {
|
|
for (unsigned int i = 0; i < ArgValue.size(); ++i) {
|
|
int ret = UpnpAddToAction(
|
|
&ActionDoc,
|
|
action.GetName().c_str(),
|
|
GetServiceType().c_str(),
|
|
ArgValue[i].GetArgument().c_str(),
|
|
ArgValue[i].GetValue().c_str());
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
m_upnpLib.processUPnPErrorMessage(
|
|
"UpnpAddToAction", ret, NULL, NULL);
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() UpnpMakeAction" << std::endl;
|
|
#endif
|
|
ActionDoc = UpnpMakeAction(
|
|
action.GetName().c_str(),
|
|
GetServiceType().c_str(),
|
|
0, NULL);
|
|
if (!ActionDoc) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::Execute() Error: UpnpMakeAction returned NULL." << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Send the action asynchronously
|
|
UpnpSendActionAsync(
|
|
m_UPnPControlPoint.GetUPnPClientHandle(),
|
|
GetAbsControlURL().c_str(),
|
|
GetServiceType().c_str(),
|
|
NULL, ActionDoc,
|
|
static_cast<Upnp_FunPtr>(&CUPnPControlPoint::Callback),
|
|
NULL);
|
|
return true;
|
|
}
|
|
|
|
|
|
const std::string CUPnPService::GetStateVariable(
|
|
const std::string &stateVariableName)
|
|
{
|
|
std::map<std::string, std::string>::iterator it;
|
|
it = propertyMap.find(stateVariableName);
|
|
if (it != propertyMap.end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::GetStateVariable(" << stateVariableName << ") = " << (*it).second << std::endl;
|
|
#endif
|
|
return (*it).second;
|
|
} else {
|
|
//property map is not populated with the specified value.
|
|
//we will try to get it with an event
|
|
|
|
//this getvar is just to make the event happening
|
|
DOMString StVarVal;
|
|
UpnpGetServiceVarStatus(
|
|
m_UPnPControlPoint.GetUPnPClientHandle(),
|
|
GetAbsControlURL().c_str(),
|
|
stateVariableName.c_str(),
|
|
&StVarVal);
|
|
if (StVarVal != NULL) {
|
|
std::string varValue = std::string(StVarVal);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::GetStateVariable() varValue returned by UpnpGetServiceVarStatus : " << varValue << std::endl;
|
|
#endif
|
|
return varValue;
|
|
} else {
|
|
//use event to get state variable
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::GetStateVariable() pausing in case of an UPnP event incomming.";
|
|
#endif
|
|
rstime_t begin_time = time(NULL);
|
|
while (true) {
|
|
if (time(NULL) - begin_time > 7) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//propertyMap should be populated by nom
|
|
it = propertyMap.find(stateVariableName);
|
|
if (it != propertyMap.end()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::GetStateVariable(" << stateVariableName << ") = " << (*it).second << std::endl;
|
|
#endif
|
|
return (*it).second;
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPService::GetStateVariable(" << stateVariableName << ") = " << "Empty String" << std::endl;
|
|
#endif
|
|
return stdEmptyString;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CUPnPDevice::CUPnPDevice(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *device,
|
|
const std::string &URLBase)
|
|
:
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_DeviceList(upnpControlPoint, upnpLib, device, URLBase),
|
|
m_ServiceList(upnpControlPoint, upnpLib, device, URLBase),
|
|
m_deviceType (upnpLib.Element_GetChildValueByTag(device, "deviceType")),
|
|
m_friendlyName (upnpLib.Element_GetChildValueByTag(device, "friendlyName")),
|
|
m_manufacturer (upnpLib.Element_GetChildValueByTag(device, "manufacturer")),
|
|
m_manufacturerURL (upnpLib.Element_GetChildValueByTag(device, "manufacturerURL")),
|
|
m_modelDescription (upnpLib.Element_GetChildValueByTag(device, "modelDescription")),
|
|
m_modelName (upnpLib.Element_GetChildValueByTag(device, "modelName")),
|
|
m_modelNumber (upnpLib.Element_GetChildValueByTag(device, "modelNumber")),
|
|
m_modelURL (upnpLib.Element_GetChildValueByTag(device, "modelURL")),
|
|
m_serialNumber (upnpLib.Element_GetChildValueByTag(device, "serialNumber")),
|
|
m_UDN (upnpLib.Element_GetChildValueByTag(device, "UDN")),
|
|
m_UPC (upnpLib.Element_GetChildValueByTag(device, "UPC")),
|
|
m_presentationURL (upnpLib.Element_GetChildValueByTag(device, "presentationURL"))
|
|
{
|
|
int presURLlen = strlen(URLBase.c_str()) +
|
|
strlen(m_presentationURL.c_str()) + 2;
|
|
std::vector<char> vpresURL(presURLlen);
|
|
char* presURL = &vpresURL[0];
|
|
int errcode = UpnpResolveURL(
|
|
URLBase.c_str(),
|
|
m_presentationURL.c_str(),
|
|
presURL);
|
|
if (errcode != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPDevice::CUPnPDevice() Error generating presentationURL from " <<
|
|
"|" << URLBase << "|" <<
|
|
m_presentationURL << "|.";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
} else {
|
|
m_presentationURL = presURL;
|
|
}
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPDevice::CUPnPDevice() \n Device: " <<
|
|
"\n friendlyName: " << m_friendlyName <<
|
|
"\n deviceType: " << m_deviceType <<
|
|
"\n manufacturer: " << m_manufacturer <<
|
|
"\n manufacturerURL: " << m_manufacturerURL <<
|
|
"\n modelDescription: " << m_modelDescription <<
|
|
"\n modelName: " << m_modelName <<
|
|
"\n modelNumber: " << m_modelNumber <<
|
|
"\n modelURL: " << m_modelURL <<
|
|
"\n serialNumber: " << m_serialNumber <<
|
|
"\n UDN: " << m_UDN <<
|
|
"\n UPC: " << m_UPC <<
|
|
"\n presentationURL: " << m_presentationURL
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPRootDevice::CUPnPRootDevice(
|
|
const CUPnPControlPoint &upnpControlPoint,
|
|
CUPnPLib &upnpLib,
|
|
IXML_Element *rootDevice,
|
|
const std::string &OriginalURLBase,
|
|
const std::string &FixedURLBase,
|
|
const char *location,
|
|
int expires)
|
|
:
|
|
CUPnPDevice(upnpControlPoint, upnpLib, rootDevice, FixedURLBase),
|
|
m_UPnPControlPoint(upnpControlPoint),
|
|
m_URLBase(OriginalURLBase),
|
|
m_location(location),
|
|
m_expires(expires)
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr <<
|
|
"CUPnPRootDevice::CUPnPRootDevice() \n Root Device: " <<
|
|
"\n URLBase: " << m_URLBase <<
|
|
"\n Fixed URLBase: " << FixedURLBase <<
|
|
"\n location: " << m_location <<
|
|
"\n expires: " << m_expires
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
CUPnPControlPoint *CUPnPControlPoint::s_CtrlPoint = NULL;
|
|
|
|
|
|
CUPnPControlPoint::CUPnPControlPoint(unsigned short udpPort)
|
|
:
|
|
m_upnpLib(*this),
|
|
m_UPnPClientHandle(),
|
|
m_RootDeviceMap(),
|
|
m_ServiceMap(),
|
|
m_ActivePortMappingsMap(),
|
|
m_RootDeviceListMutex("UPnPControlPoint-RootDeviceList"),
|
|
m_IGWDeviceDetected(false),
|
|
m_WaitForSearchTimeoutMutex("UPnPControlPoint-WaitForSearchTimeout"),
|
|
m_WanService(NULL)
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() Constructor" << std::endl;
|
|
#endif
|
|
// Pointer to self
|
|
s_CtrlPoint = this;
|
|
|
|
// Start UPnP
|
|
int ret;
|
|
char *ipAddress = NULL;
|
|
unsigned short port = 0;
|
|
#ifdef UPNP_DEBUG
|
|
int resLog = UpnpInitLog();
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() Init log : " << resLog << std::endl;
|
|
#endif
|
|
ret = UpnpInit(ipAddress, udpPort);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint Constructor UpnpInit finished" << std::endl;
|
|
#endif
|
|
if (ret != UPNP_E_SUCCESS && ret !=UPNP_E_INIT) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() error(UpnpInit): Error code : ";
|
|
#endif
|
|
goto error;
|
|
}
|
|
port = UpnpGetServerPort();
|
|
ipAddress = UpnpGetServerIpAddress();
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() bound to " << ipAddress << ":" <<
|
|
port << "." << std::endl;
|
|
#else
|
|
// unused variable
|
|
(void)port;
|
|
#endif
|
|
|
|
ret = UpnpRegisterClient(
|
|
static_cast<Upnp_FunPtr>(&CUPnPControlPoint::Callback),
|
|
&m_UPnPClientHandle,
|
|
&m_UPnPClientHandle);
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() error(UpnpRegisterClient): Error registering callback: ";
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
// We could ask for just the right device here. If the root device
|
|
// contains the device we want, it will respond with the full XML doc,
|
|
// including the root device and every sub-device it has.
|
|
//
|
|
// But lets find out what we have in our network by calling UPNP_ROOT_DEVICE.
|
|
//
|
|
// We should not search twice, because this will produce two
|
|
// UPNP_DISCOVERY_SEARCH_TIMEOUT events, and we might end with problems
|
|
// on the mutex.
|
|
// UpnpSetContentLength(m_UPnPClientHandle, 5000000);
|
|
// UpnpSetMaxContentLength(5000000);
|
|
ret = UpnpSearchAsync(m_UPnPClientHandle, 20, m_upnpLib.UPNP_DEVICE_IGW.c_str(), NULL);
|
|
//ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_IGW.c_str(), this);
|
|
//ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_LAN.c_str(), this);
|
|
//ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_WAN_CONNECTION.c_str(), this);
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() error(UpnpSearchAsync): Error sending search request: ";
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
// Wait for the UPnP initialization to complete.
|
|
{
|
|
// Lock the search timeout mutex
|
|
m_WaitForSearchTimeoutMutex.lock();
|
|
|
|
// Lock it again, so that we block. Unlocking will only happen
|
|
// when the UPNP_DISCOVERY_SEARCH_TIMEOUT event occurs at the
|
|
// callback.
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() blocking m_WaitForSearchTimeoutMutex." << std::endl;
|
|
#endif
|
|
//RsMutex toto(m_WaitForSearchTimeoutMutex);
|
|
m_WaitForSearchTimeoutMutex.lock();
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() m_WaitForSearchTimeoutMutex blocking finished." << std::endl;
|
|
#endif
|
|
}
|
|
|
|
//clean the PortMappingNumberOfEntries as it is erroneus on the first event with the french neufbox
|
|
if (WanServiceDetected()) {
|
|
m_WanService->propertyMap.erase("PortMappingNumberOfEntries");
|
|
}
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() CUPnPControlPoint Constructor finished" << std::endl;
|
|
#endif
|
|
return;
|
|
|
|
// Error processing
|
|
error:
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << ret << ": " << m_upnpLib.GetUPnPErrorMessage(ret) << "." << std::endl;
|
|
#endif
|
|
UpnpFinish();
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnPControlPoint::CUPnPControlPoint() UpnpFinish called within CUPnPControlPoint constructor." << std::endl;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
char* CUPnPControlPoint::getInternalIpAddress()
|
|
{
|
|
char * addr = UpnpGetServerIpAddress();
|
|
if (addr == NULL) {
|
|
addr = new char[10] ;
|
|
sprintf(addr,"%s","127.0.0.1");
|
|
}
|
|
return addr;
|
|
}
|
|
|
|
CUPnPControlPoint::~CUPnPControlPoint()
|
|
{
|
|
for( RootDeviceMap::iterator it = m_RootDeviceMap.begin();
|
|
it != m_RootDeviceMap.end();
|
|
++it) {
|
|
delete it->second;
|
|
}
|
|
// Remove all first
|
|
// RemoveAll();
|
|
UpnpUnRegisterClient(m_UPnPClientHandle);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::~CUPnPControlPoint() UpnpFinish called within CUPnPControlPoint destructor." << std::endl;
|
|
#endif
|
|
UpnpFinish();
|
|
}
|
|
|
|
|
|
bool CUPnPControlPoint::AddPortMappings(
|
|
std::vector<CUPnPPortMapping> &upnpPortMapping)
|
|
{
|
|
if (!WanServiceDetected()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::AddPortMappings() UPnP Error: "
|
|
"CUPnPControlPoint::AddPortMapping: "
|
|
"WAN Service not detected." << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::AddPortMappings() called." << std::endl;
|
|
#endif
|
|
|
|
int n = upnpPortMapping.size();
|
|
bool ok = false;
|
|
|
|
// Check the number of port mappings before
|
|
//have a little break in case we just modified the variable, so we have to wait for an event
|
|
// std::cerr << "GetStateVariable pausing in case of an UPnP event incomming.";
|
|
// rstime_t begin_time = time(NULL);
|
|
// while (true) {
|
|
// if (time(NULL) - begin_time > 7) {
|
|
// break;
|
|
// }
|
|
// }
|
|
std::istringstream OldPortMappingNumberOfEntries(
|
|
m_WanService->GetStateVariable(
|
|
"PortMappingNumberOfEntries"));
|
|
int oldNumberOfEntries;
|
|
OldPortMappingNumberOfEntries >> oldNumberOfEntries;
|
|
|
|
// Add the enabled port mappings
|
|
for (int i = 0; i < n; ++i) {
|
|
if (upnpPortMapping[i].getEnabled() == "1") {
|
|
// Add the mapping to the control point
|
|
// active mappings list
|
|
m_ActivePortMappingsMap[upnpPortMapping[i].getKey()] =
|
|
upnpPortMapping[i];
|
|
|
|
// Add the port mapping
|
|
PrivateAddPortMapping(upnpPortMapping[i]);
|
|
}
|
|
}
|
|
|
|
// Not very good, must find a better test : check the new number of port entries
|
|
//have a little break in case we just modified the variable, so we have to wait for an event
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::AddPortMappings() GetStateVariable pausing in case of an UPnP event incomming.";
|
|
#endif
|
|
rstime_t begin_time = time(NULL);
|
|
while (true) {
|
|
if (time(NULL) - begin_time > 4) {
|
|
break;
|
|
}
|
|
}
|
|
std::istringstream NewPortMappingNumberOfEntries(
|
|
m_WanService->GetStateVariable(
|
|
"PortMappingNumberOfEntries"));
|
|
int newNumberOfEntries;
|
|
NewPortMappingNumberOfEntries >> newNumberOfEntries;
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::AddPortMappings() CUPnPControlPoint::AddPortMappings() newNumberOfEntries - oldNumberOfEntries : " << (newNumberOfEntries - oldNumberOfEntries) << std::endl;
|
|
#endif
|
|
ok = newNumberOfEntries - oldNumberOfEntries >= 1;
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::AddPortMappings() finished. Success = " << ok << std::endl;
|
|
#endif
|
|
|
|
return ok;
|
|
}
|
|
|
|
std::string CUPnPControlPoint::getExternalAddress()
|
|
{
|
|
if (!WanServiceDetected()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::getExternalAddress() UPnP Error: "
|
|
"CUPnPControlPoint::AddPortMapping: "
|
|
"WAN Service not detected." << std::endl;
|
|
#endif
|
|
return "";
|
|
}
|
|
std::string result = m_WanService->GetStateVariable("NewExternalIPAddress");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::getExternalAddress() m_WanService->GetStateVariable(NewExternalIPAddress) = " << result << std::endl;
|
|
#endif
|
|
if (result == "") {
|
|
PrivateGetExternalIpAdress();
|
|
result = m_WanService->GetStateVariable("NewExternalIPAddress");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::getExternalAddress() m_WanService->GetStateVariable(NewExternalIPAddress) = " << result << std::endl;
|
|
#endif
|
|
if (result == "") {
|
|
result = m_WanService->GetStateVariable("ExternalIPAddress");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::getExternalAddress() m_WanService->GetStateVariable(ExternalIPAddress) = " << result << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CUPnPControlPoint::RefreshPortMappings()
|
|
{
|
|
for ( PortMappingMap::iterator it = m_ActivePortMappingsMap.begin();
|
|
it != m_ActivePortMappingsMap.end();
|
|
++it) {
|
|
PrivateAddPortMapping(it->second);
|
|
}
|
|
}
|
|
|
|
|
|
bool CUPnPControlPoint::PrivateAddPortMapping(
|
|
CUPnPPortMapping &upnpPortMapping)
|
|
{
|
|
// Get an IP address. The UPnP server one must do.
|
|
std::string ipAddress(UpnpGetServerIpAddress());
|
|
|
|
// Start building the action
|
|
std::string actionName("AddPortMapping");
|
|
std::vector<CUPnPArgumentValue> argval(8);
|
|
|
|
// Action parameters
|
|
argval[0].SetArgument("NewRemoteHost");
|
|
argval[0].SetValue("");
|
|
argval[1].SetArgument("NewExternalPort");
|
|
argval[1].SetValue(upnpPortMapping.getExPort());
|
|
argval[2].SetArgument("NewProtocol");
|
|
argval[2].SetValue(upnpPortMapping.getProtocol());
|
|
argval[3].SetArgument("NewInternalPort");
|
|
argval[3].SetValue(upnpPortMapping.getInPort());
|
|
argval[4].SetArgument("NewInternalClient");
|
|
argval[4].SetValue(ipAddress);
|
|
argval[5].SetArgument("NewEnabled");
|
|
argval[5].SetValue("1");
|
|
argval[6].SetArgument("NewPortMappingDescription");
|
|
argval[6].SetValue(upnpPortMapping.getDescription());
|
|
argval[7].SetArgument("NewLeaseDuration");
|
|
argval[7].SetValue("0");
|
|
|
|
// Execute
|
|
bool ret = true;
|
|
for (ServiceMap::iterator it = m_ServiceMap.begin();
|
|
it != m_ServiceMap.end(); ++it) {
|
|
ret &= it->second->Execute(actionName, argval);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool CUPnPControlPoint::DeletePortMappings(
|
|
std::vector<CUPnPPortMapping> &upnpPortMapping)
|
|
{
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::DeletePortMappings() called." << std::endl;
|
|
#endif
|
|
if (!WanServiceDetected()) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPnP Error: "
|
|
"CUPnPControlPoint::DeletePortMapping: "
|
|
"WAN Service not detected." << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int n = upnpPortMapping.size();
|
|
|
|
// Delete the enabled port mappings
|
|
for (int i = 0; i < n; ++i) {
|
|
if (upnpPortMapping[i].getEnabled() == "1") {
|
|
// Delete the mapping from the control point
|
|
// active mappings list
|
|
PortMappingMap::iterator it =
|
|
m_ActivePortMappingsMap.find(
|
|
upnpPortMapping[i].getKey());
|
|
if (it != m_ActivePortMappingsMap.end()) {
|
|
m_ActivePortMappingsMap.erase(it);
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::DeletePortMappings() UPnP Error: "
|
|
"CUPnPControlPoint::DeletePortMapping: "
|
|
"Mapping was not found in the active "
|
|
"mapping map." << std::endl;
|
|
#endif
|
|
}
|
|
|
|
// Delete the port mapping
|
|
PrivateDeletePortMapping(upnpPortMapping[i]);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CUPnPControlPoint::PrivateDeletePortMapping(
|
|
CUPnPPortMapping &upnpPortMapping)
|
|
{
|
|
// Start building the action
|
|
std::string actionName("DeletePortMapping");
|
|
std::vector<CUPnPArgumentValue> argval(3);
|
|
|
|
// Action parameters
|
|
argval[0].SetArgument("NewRemoteHost");
|
|
argval[0].SetValue("");
|
|
argval[1].SetArgument("NewExternalPort");
|
|
argval[1].SetValue(upnpPortMapping.getExPort());
|
|
argval[2].SetArgument("NewProtocol");
|
|
argval[2].SetValue(upnpPortMapping.getProtocol());
|
|
|
|
// Execute
|
|
bool ret = true;
|
|
for (ServiceMap::iterator it = m_ServiceMap.begin();
|
|
it != m_ServiceMap.end(); ++it) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::PrivateDeletePortMapping() Sending a delete port mapping action." << std::endl;
|
|
#endif
|
|
ret &= it->second->Execute(actionName, argval);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::PrivateDeletePortMapping() Delete port mapping action finished." << std::endl;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool CUPnPControlPoint::PrivateGetExternalIpAdress()
|
|
{
|
|
// Start building the action
|
|
std::string actionName("GetExternalIPAddress");
|
|
std::vector<CUPnPArgumentValue> argval(0);
|
|
|
|
// Execute
|
|
bool ret = true;
|
|
for (ServiceMap::iterator it = m_ServiceMap.begin();
|
|
it != m_ServiceMap.end(); ++it) {
|
|
ret &= it->second->Execute(actionName, argval);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
// This function is static
|
|
int CUPnPControlPoint::Callback(Upnp_EventType EventType, void *Event, void * /*Cookie*/)
|
|
{
|
|
std::string msg;
|
|
std::string msg2;
|
|
// Somehow, this is unreliable. UPNP_DISCOVERY_ADVERTISEMENT_ALIVE events
|
|
// happen with a wrong cookie and... boom!
|
|
// CUPnPControlPoint *upnpCP = static_cast<CUPnPControlPoint *>(Cookie);
|
|
CUPnPControlPoint *upnpCP = CUPnPControlPoint::s_CtrlPoint ;
|
|
|
|
if (upnpCP == NULL)
|
|
return 0;
|
|
|
|
//fprintf(stderr, "Callback: %d, Cookie: %p\n", EventType, Cookie);
|
|
switch (EventType) {
|
|
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: ";
|
|
#endif
|
|
goto upnpDiscovery;
|
|
case UPNP_DISCOVERY_SEARCH_RESULT: {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "UPNP_DISCOVERY_SEARCH_RESULT: ";
|
|
#endif
|
|
// UPnP Discovery
|
|
upnpDiscovery:
|
|
struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)Event;
|
|
IXML_Document *doc = NULL;
|
|
int ret;
|
|
if (d_event->ErrCode != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << upnpCP->m_upnpLib.GetUPnPErrorMessage(d_event->ErrCode) << "." << std::endl;
|
|
#endif
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() URetrieving device description from " <<
|
|
d_event->Location << "." << std::endl;
|
|
#endif
|
|
// Get the XML tree device description in doc
|
|
ret = UpnpDownloadXmlDoc(d_event->Location, &doc);
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() UError retrieving device description from " <<
|
|
d_event->Location << ": " <<
|
|
upnpCP->m_upnpLib.GetUPnPErrorMessage(ret) << ".";
|
|
#endif
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() URetrieving device description from " <<
|
|
d_event->Location << "." << std::endl;
|
|
#endif
|
|
}
|
|
if (doc) {
|
|
// Get the root node
|
|
IXML_Element *root =
|
|
upnpCP->m_upnpLib.Element_GetRootElement(doc);
|
|
// Extract the URLBase
|
|
const std::string urlBase = upnpCP->m_upnpLib.
|
|
Element_GetChildValueByTag(root, "URLBase");
|
|
// Get the root device
|
|
IXML_Element *rootDevice = upnpCP->m_upnpLib.
|
|
Element_GetFirstChildByTag(root, "device");
|
|
// Extract the deviceType
|
|
std::string devType(upnpCP->m_upnpLib.
|
|
Element_GetChildValueByTag(rootDevice, "deviceType"));
|
|
// Only add device if it is an InternetGatewayDevice
|
|
if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) {
|
|
// This condition can be used to auto-detect
|
|
// the UPnP device we are interested in.
|
|
// Obs.: Don't block the entry here on this
|
|
// condition! There may be more than one device,
|
|
// and the first that enters may not be the one
|
|
// we are interested in!
|
|
upnpCP->SetIGWDeviceDetected(true);
|
|
// Log it if not UPNP_DISCOVERY_ADVERTISEMENT_ALIVE,
|
|
// we don't want to spam our logs.
|
|
//if (EventType != UPNP_DISCOVERY_ADVERTISEMENT_ALIVE) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "Internet Gateway Device Detected." << std::endl;
|
|
#endif
|
|
//}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() UGetting root device desc." << std::endl;
|
|
#endif
|
|
// Add the root device to our list
|
|
upnpCP->AddRootDevice(rootDevice, urlBase,
|
|
d_event->Location, d_event->Expires);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() UFinishing getting root device desc." << std::endl;
|
|
#endif
|
|
}
|
|
// Free the XML doc tree
|
|
ixmlDocument_free(doc);
|
|
}
|
|
break;
|
|
}
|
|
case UPNP_DISCOVERY_SEARCH_TIMEOUT: {
|
|
//fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_TIMEOUT\n");
|
|
// Search timeout
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() UUPNP_DISCOVERY_SEARCH_TIMEOUT : unlocking mutex." << std::endl;
|
|
#endif
|
|
|
|
// Unlock the search timeout mutex
|
|
upnpCP->m_WaitForSearchTimeoutMutex.unlock();
|
|
|
|
break;
|
|
}
|
|
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: {
|
|
//fprintf(stderr, "Callback: UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n");
|
|
// UPnP Device Removed
|
|
struct Upnp_Discovery *dab_event = (struct Upnp_Discovery *)Event;
|
|
if (dab_event->ErrCode != UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() Uerror(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE): " <<
|
|
upnpCP->m_upnpLib.GetUPnPErrorMessage(dab_event->ErrCode) <<
|
|
"." << std::endl;
|
|
#endif
|
|
}
|
|
std::string devType = dab_event->DeviceType;
|
|
// Check for an InternetGatewayDevice and removes it from the list
|
|
std::transform(devType.begin(), devType.end(), devType.begin(), tolower);
|
|
if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) {
|
|
upnpCP->RemoveRootDevice(dab_event->DeviceId);
|
|
}
|
|
break;
|
|
}
|
|
case UPNP_EVENT_RECEIVED: {
|
|
#ifdef UPNP_DEBUG
|
|
fprintf(stderr, "Callback: UPNP_EVENT_RECEIVED\n");
|
|
#endif
|
|
// Event reveived
|
|
struct Upnp_Event *e_event = (struct Upnp_Event *)Event;
|
|
const std::string Sid = e_event->Sid;
|
|
// Parses the event
|
|
upnpCP->OnEventReceived(Sid, e_event->EventKey, e_event->ChangedVariables);
|
|
break;
|
|
}
|
|
case UPNP_EVENT_SUBSCRIBE_COMPLETE:
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIBE_COMPLETE\n");
|
|
msg += "error(UPNP_EVENT_SUBSCRIBE_COMPLETE): ";
|
|
goto upnpEventRenewalComplete;
|
|
case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n");
|
|
msg += "error(UPNP_EVENT_UNSUBSCRIBE_COMPLETE): ";
|
|
goto upnpEventRenewalComplete;
|
|
case UPNP_EVENT_RENEWAL_COMPLETE: {
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_RENEWAL_COMPLETE\n");
|
|
msg += "error(UPNP_EVENT_RENEWAL_COMPLETE): ";
|
|
upnpEventRenewalComplete:
|
|
struct Upnp_Event_Subscribe *es_event =
|
|
(struct Upnp_Event_Subscribe *)Event;
|
|
if (es_event->ErrCode != UPNP_E_SUCCESS) {
|
|
msg += "Error in Event Subscribe Callback";
|
|
upnpCP->m_upnpLib.processUPnPErrorMessage(
|
|
msg, es_event->ErrCode, NULL, NULL);
|
|
} else {
|
|
#if 0
|
|
TvCtrlPointHandleSubscribeUpdate(
|
|
es_event->PublisherUrl,
|
|
es_event->Sid,
|
|
es_event->TimeOut );
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case UPNP_EVENT_AUTORENEWAL_FAILED:
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_AUTORENEWAL_FAILED\n");
|
|
msg += "CUPnPControlPoint::Callback() error(UPNP_EVENT_AUTORENEWAL_FAILED): ";
|
|
msg2 += "UPNP_EVENT_AUTORENEWAL_FAILED: ";
|
|
goto upnpEventSubscriptionExpired;
|
|
case UPNP_EVENT_SUBSCRIPTION_EXPIRED: {
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_EXPIRED\n");
|
|
msg += "CUPnPControlPoint::Callback() error(UPNP_EVENT_SUBSCRIPTION_EXPIRED): ";
|
|
msg2 += "UPNP_EVENT_SUBSCRIPTION_EXPIRED: ";
|
|
upnpEventSubscriptionExpired:
|
|
struct Upnp_Event_Subscribe *es_event =
|
|
(struct Upnp_Event_Subscribe *)Event;
|
|
Upnp_SID newSID;
|
|
int TimeOut = 1801;
|
|
int ret = UpnpSubscribe(
|
|
upnpCP->m_UPnPClientHandle,
|
|
#ifdef PATCHED_LIBUPNP
|
|
UpnpString_get_String(es_event->PublisherUrl),
|
|
#else
|
|
es_event->PublisherUrl,
|
|
#endif
|
|
&TimeOut,
|
|
newSID);
|
|
if (ret != UPNP_E_SUCCESS) {
|
|
msg += "Error Subscribing to EventURL";
|
|
upnpCP->m_upnpLib.processUPnPErrorMessage(
|
|
msg, es_event->ErrCode, NULL, NULL);
|
|
} else {
|
|
ServiceMap::iterator it =
|
|
#ifdef PATCHED_LIBUPNP
|
|
upnpCP->m_ServiceMap.find(UpnpString_get_String(es_event->PublisherUrl));
|
|
#else
|
|
upnpCP->m_ServiceMap.find(es_event->PublisherUrl);
|
|
#endif
|
|
if (it != upnpCP->m_ServiceMap.end()) {
|
|
CUPnPService &service = *(it->second);
|
|
service.SetTimeout(TimeOut);
|
|
service.SetSID(newSID);
|
|
std::cerr << "CUPnPControlPoint::Callback() Re-subscribed to EventURL '" <<
|
|
#ifdef PATCHED_LIBUPNP
|
|
UpnpString_get_String(es_event->PublisherUrl) <<
|
|
#else
|
|
es_event->PublisherUrl <<
|
|
#endif
|
|
"' with SID == '" <<
|
|
newSID << "'." << std::endl;
|
|
// In principle, we should test to see if the
|
|
// service is the same. But here we only have one
|
|
// service, so...
|
|
upnpCP->RefreshPortMappings();
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() Error: did not find service " <<
|
|
newSID << " in the service map." << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case UPNP_CONTROL_ACTION_COMPLETE: {
|
|
//fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_COMPLETE\n");
|
|
// This is here if we choose to do this asynchronously
|
|
struct Upnp_Action_Complete *a_event =
|
|
(struct Upnp_Action_Complete *)Event;
|
|
if (a_event->ErrCode != UPNP_E_SUCCESS) {
|
|
upnpCP->m_upnpLib.processUPnPErrorMessage(
|
|
"UpnpSendActionAsync",
|
|
a_event->ErrCode, NULL,
|
|
a_event->ActionResult);
|
|
} else {
|
|
// Check the response document
|
|
upnpCP->m_upnpLib.ProcessActionResponse(
|
|
a_event->ActionResult,
|
|
"<UpnpSendActionAsync>");
|
|
}
|
|
/* No need for any processing here, just print out results.
|
|
* Service state table updates are handled by events.
|
|
*/
|
|
break;
|
|
}
|
|
case UPNP_CONTROL_GET_VAR_COMPLETE: {
|
|
#ifdef UPNP_DEBUG
|
|
fprintf(stderr, "CUPnPControlPoint::Callback() Callback: UPNP_CONTROL_GET_VAR_COMPLETE\n");
|
|
#endif
|
|
msg += "CUPnPControlPoint::Callback() error(UPNP_CONTROL_GET_VAR_COMPLETE): ";
|
|
struct Upnp_State_Var_Complete *sv_event =
|
|
(struct Upnp_State_Var_Complete *)Event;
|
|
if (sv_event->ErrCode != UPNP_E_SUCCESS) {
|
|
msg += "m_UpnpGetServiceVarStatusAsync";
|
|
upnpCP->m_upnpLib.processUPnPErrorMessage(
|
|
msg, sv_event->ErrCode, NULL, NULL);
|
|
} else {
|
|
//add the variable to the wanservice property map
|
|
(upnpCP->m_WanService->propertyMap)[std::string(sv_event->StateVarName)] = std::string(sv_event->CurrentVal);
|
|
}
|
|
break;
|
|
}
|
|
// ignore these cases, since this is not a device
|
|
case UPNP_CONTROL_GET_VAR_REQUEST:
|
|
//fprintf(stderr, "Callback: UPNP_CONTROL_GET_VAR_REQUEST\n");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() error(UPNP_CONTROL_GET_VAR_REQUEST): ";
|
|
#endif
|
|
goto eventSubscriptionRequest;
|
|
case UPNP_CONTROL_ACTION_REQUEST:
|
|
//fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_REQUEST\n");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() error(UPNP_CONTROL_ACTION_REQUEST): ";
|
|
#endif
|
|
goto eventSubscriptionRequest;
|
|
case UPNP_EVENT_SUBSCRIPTION_REQUEST:
|
|
//fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_REQUEST\n");
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() error(UPNP_EVENT_SUBSCRIPTION_REQUEST): ";
|
|
#endif
|
|
eventSubscriptionRequest:
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Callback() This is not a UPnP Device, this is a UPnP Control Point, event ignored." << std::endl;
|
|
#endif
|
|
break;
|
|
default:
|
|
// Humm, this is not good, we forgot to handle something...
|
|
#ifdef UPNP_DEBUG
|
|
fprintf(stderr,
|
|
"Callback: default... Unknown event:'%d', not good.\n",
|
|
EventType);
|
|
std::cerr << "CUPnPControlPoint::Callback() error(UPnP::Callback): Event not handled:'" <<
|
|
EventType << "'." << std::endl;
|
|
#endif
|
|
// Better not throw in the callback. Who would catch it?
|
|
//throw CUPnPException(msg);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CUPnPControlPoint::OnEventReceived(
|
|
const std::string &Sid,
|
|
int EventKey,
|
|
IXML_Document *ChangedVariablesDoc)
|
|
{
|
|
/* remove unused parameter warnings */
|
|
(void) EventKey;
|
|
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::OnEventReceived() UPNP_EVENT_RECEIVED:" <<
|
|
"\n SID: " << Sid <<
|
|
"\n Key: " << EventKey << std::endl;
|
|
std::cerr << "CUPnPControlPoint::OnEventReceived() m_WanService->GetServiceId() : " << m_WanService->GetSID() << std::endl;
|
|
#endif
|
|
|
|
if (m_WanService->GetSID() == Sid) {
|
|
//let's store the properties if it is an event of the wan device
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::OnEventReceived() \n Property list:";
|
|
#endif
|
|
|
|
IXML_Element *root =
|
|
m_upnpLib.Element_GetRootElement(ChangedVariablesDoc);
|
|
IXML_Element *child =
|
|
m_upnpLib.Element_GetFirstChild(root);
|
|
if (child) {
|
|
while (child) {
|
|
IXML_Element *child2 =
|
|
m_upnpLib.Element_GetFirstChild(child);
|
|
const DOMString childTag =
|
|
m_upnpLib.Element_GetTag(child2);
|
|
std::string childValue =
|
|
m_upnpLib.Element_GetTextValue(child2);
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "\n " <<
|
|
childTag << "='" <<
|
|
childValue << "'";
|
|
#endif
|
|
const std::string cTag(childTag);
|
|
const std::string cValue(childValue);
|
|
(m_WanService->propertyMap)[cTag] = cValue;
|
|
child = m_upnpLib.Element_GetNextSibling(child);
|
|
}
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::OnEventReceived() \n Empty property list.";
|
|
#endif
|
|
}
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << std::endl;
|
|
#endif
|
|
// Freeing that doc segfaults. Probably should not be freed.
|
|
//ixmlDocument_free(ChangedVariablesDoc);
|
|
}
|
|
}
|
|
|
|
|
|
void CUPnPControlPoint::AddRootDevice(
|
|
IXML_Element *rootDevice, const std::string &urlBase,
|
|
const char *location, int expires)
|
|
{
|
|
// Lock the Root Device List
|
|
RsMutex toto(m_RootDeviceListMutex);
|
|
|
|
// Root node's URLBase
|
|
std::string OriginalURLBase(urlBase);
|
|
std::string FixedURLBase(OriginalURLBase.empty() ?
|
|
location :
|
|
OriginalURLBase);
|
|
|
|
// Get the UDN (Unique Device Name)
|
|
std::string UDN(
|
|
m_upnpLib.Element_GetChildValueByTag(rootDevice, "UDN"));
|
|
RootDeviceMap::iterator it = m_RootDeviceMap.find(UDN);
|
|
bool alreadyAdded = it != m_RootDeviceMap.end();
|
|
if (alreadyAdded) {
|
|
// Just set the expires field
|
|
it->second->SetExpires(expires);
|
|
} else {
|
|
// Add a new root device to the root device list
|
|
CUPnPRootDevice *upnpRootDevice = new CUPnPRootDevice(
|
|
*this, m_upnpLib, rootDevice,
|
|
OriginalURLBase, FixedURLBase,
|
|
location, expires);
|
|
m_RootDeviceMap[upnpRootDevice->GetUDN()] = upnpRootDevice;
|
|
}
|
|
}
|
|
|
|
|
|
void CUPnPControlPoint::RemoveRootDevice(const char *udn)
|
|
{
|
|
// Lock the Root Device List
|
|
RsMutex toto(m_RootDeviceListMutex);
|
|
|
|
// Remove
|
|
std::string UDN(udn);
|
|
RootDeviceMap::iterator it = m_RootDeviceMap.find(UDN);
|
|
if (it != m_RootDeviceMap.end()) {
|
|
delete it->second;
|
|
m_RootDeviceMap.erase(UDN);
|
|
}
|
|
}
|
|
|
|
|
|
void CUPnPControlPoint::Subscribe(CUPnPService &service)
|
|
{
|
|
|
|
IXML_Document *scpdDoc = NULL;
|
|
int errcode = UpnpDownloadXmlDoc(
|
|
service.GetAbsSCPDURL().c_str(), &scpdDoc);
|
|
if (errcode == UPNP_E_SUCCESS) {
|
|
// Get the root node of this service (the SCPD Document)
|
|
IXML_Element *scpdRoot =
|
|
m_upnpLib.Element_GetRootElement(scpdDoc);
|
|
CUPnPSCPD *scpd = new CUPnPSCPD(*this, m_upnpLib,
|
|
scpdRoot, service.GetAbsSCPDURL());
|
|
service.SetSCPD(scpd);
|
|
m_ServiceMap[service.GetAbsEventSubURL()] = &service;
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Subscribe() Successfully retrieved SCPD Document for service " <<
|
|
service.GetServiceType() << ", absEventSubURL: " <<
|
|
service.GetAbsEventSubURL() << "." << std::endl;
|
|
#endif
|
|
|
|
// Now try to subscribe to this service. If the subscription
|
|
// is not successfull, we will not be notified about events,
|
|
// but it may be possible to use the service anyway.
|
|
errcode = UpnpSubscribe(m_UPnPClientHandle,
|
|
service.GetAbsEventSubURL().c_str(),
|
|
service.GetTimeoutAddr(),
|
|
service.GetSID());
|
|
if (errcode == UPNP_E_SUCCESS) {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Subscribe() Successfully subscribed to service " <<
|
|
service.GetServiceType() << ", absEventSubURL: " <<
|
|
service.GetAbsEventSubURL() << "." << std::endl;
|
|
#endif
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Subscribe() Error subscribing to service " <<
|
|
service.GetServiceType() << ", absEventSubURL: " <<
|
|
service.GetAbsEventSubURL() << ", error: " <<
|
|
m_upnpLib.GetUPnPErrorMessage(errcode) << ".";
|
|
#endif
|
|
goto error;
|
|
}
|
|
} else {
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << "CUPnPControlPoint::Subscribe() Error getting SCPD Document from " <<
|
|
service.GetAbsSCPDURL() << "." << std::endl;
|
|
#endif
|
|
}
|
|
|
|
return;
|
|
|
|
error:
|
|
;
|
|
#ifdef UPNP_DEBUG
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
|
|
|
|
void CUPnPControlPoint::Unsubscribe(CUPnPService &service)
|
|
{
|
|
ServiceMap::iterator it = m_ServiceMap.find(service.GetAbsEventSubURL());
|
|
if (it != m_ServiceMap.end()) {
|
|
m_ServiceMap.erase(it);
|
|
UpnpUnSubscribe(m_UPnPClientHandle, service.GetSID());
|
|
}
|
|
}
|
|
|
|
|
|
// File_checked_for_headers
|