diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index bd86bbdd4..08ea48907 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -1,24 +1,15 @@ TEMPLATE = lib -CONFIG += static +CONFIG += static release TARGET = retroshare -CONFIG += release -DEFINES *= MINIUPNPC_VERSION=13 DEFINES -= PQI_USE_XPGP DEFINES += RS_USE_PGPSSL -UPNPC_DIR = ../../../../miniupnpc-1.3 -GPG_ERROR_DIR = ../../../../libgpg-error-1.7 -GPGME_DIR = ../../../../gpgme-1.1.8 - profiling { QMAKE_CXXFLAGS -= -fomit-frame-pointer QMAKE_CXXFLAGS *= -pg -g -fno-omit-frame-pointer } -DEFINES -= PQI_USE_XPGP -DEFINES *= RS_USE_PGPSSL - ################################# Linux ########################################## debug { @@ -32,23 +23,31 @@ debug { linux-g++ { OBJECTS_DIR = temp/linux-g++/obj - DESTDIR = lib.linux-g++ - QMAKE_CXXFLAGS *= -Wall + DESTDIR = lib + QMAKE_CXXFLAGS *= -Wall QMAKE_CC = g++ - + SSL_DIR = /usr/include/openssl - UPNPC_DIR = ../../../../miniupnpc-1.3 - GPG_ERROR_DIR = ../../../../libgpg-error-1.7 - GPGME_DIR = ../../../../gpgme-1.1.8 - + UPNP_DIR = /usr/include/upnp + HEADERS += usr/include/gpg-error.h + HEADERS += usr/include/gpgme.h + INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} + CONFIG += version_detail_bash_script } + linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj - DESTDIR = lib.linux-g++-64 - QMAKE_CXXFLAGS *= -Wall + DESTDIR = lib + QMAKE_CXXFLAGS *= -Wall QMAKE_CC = g++ + SSL_DIR = /usr/include/openssl + UPNP_DIR = /usr/include/upnp + HEADERS += usr/include/gpg-error.h + HEADERS += usr/include/gpgme.h + INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} + CONFIG += version_detail_bash_script } @@ -98,8 +97,6 @@ win32 { } ################################### COMMON stuff ################################## -INCLUDEPATH += . $${SSL_DIR} $${UPNPC_DIR} $${GPGME_DIR}/src $${GPG_ERROR_DIR}/src - #DEPENDPATH += . \ # util \ # tcponudp \ @@ -252,8 +249,8 @@ HEADERS += dbase/cachestrapper.h \ tcponudp/udplayer.h \ tcponudp/udpsorter.h \ upnp/upnphandler.h \ - upnp/upnputil.h \ - util/rsdebug.h \ + upnp/UPnPBase.h \ + util/rsdebug.h \ util/rsdir.h \ util/rsnet.h \ util/rsprint.h \ @@ -287,9 +284,9 @@ SOURCES = \ ft/ftdata.cc \ ft/ftfileprovider.cc \ ft/ftdwlqueue.cc \ - upnp/upnputil.c \ dht/opendhtmgr.cc \ upnp/upnphandler.cc \ + upnp/UPnPBase.cpp \ dht/opendht.cc \ dht/opendhtstr.cc \ dht/b64.c \ diff --git a/libretroshare/src/upnp/UPnPBase.cpp b/libretroshare/src/upnp/UPnPBase.cpp new file mode 100644 index 000000000..ce95d3082 --- /dev/null +++ b/libretroshare/src/upnp/UPnPBase.cpp @@ -0,0 +1,1651 @@ +// +// 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 ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// 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. +// +// 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 +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// + +#define UPNP_C + +#include "UPnPBase.h" +#include + +#include // For dlopen(), dlsym(), dlclose() +#include // For transform() + + +#ifdef __GNUC__ + #if __GNUC__ >= 4 + #define REINTERPRET_CAST(x) reinterpret_cast + #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() +{ + std::ostringstream oss; + oss << ex_port; + m_ex_port = oss.str(); + std::ostringstream oss2; + oss2 << in_port; + m_in_port = oss2.str(); + 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 &messsage, + int errorCode, + const DOMString errorString, + IXML_Document *doc) const +{ + std::ostringstream msg; + if (errorString == NULL || *errorString == 0) { + errorString = "Not available"; + } + if (errorCode > 0) { + std::cerr << "Error: " << + messsage << + ": 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 << "Error: " << + messsage << + ": UPnP SDK error: " << + GetUPnPErrorMessage(errorCode) << + " (" << errorCode << ")."; + std::cerr << std::endl; + } + + return msg.str(); +} + + +void CUPnPLib::ProcessActionResponse( + IXML_Document *RespDoc, + const std::string &actionName) const +{ + std::ostringstream msg; + msg << "Response: "; + 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); + std::cerr << "\n " << + childTag << "='" << + childValue << "'"; + child = Element_GetNextSibling(child); + } + } else { + std::cerr << "\n Empty response for action '" << + actionName << "'."; + } + std::cerr << std::endl; +} + + +/*! + * \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")) +{ + + std::cerr << "\n Argument:" << + "\n name: " << m_name << + "\n direction: " << m_direction << + "\n retval: " << m_retval << + "\n relatedStateVariable: " << m_relatedStateVariable; + std::cerr << std::endl; +} + + +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")) +{ + std::cerr << "\n Action:" << + "\n name: " << m_name; + std::cerr << std::endl; +} + + +CUPnPAllowedValue::CUPnPAllowedValue( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *allowedValue, + const std::string &SCPDURL) +: +m_UPnPControlPoint(upnpControlPoint), +m_allowedValue(upnpLib.Element_GetTextValue(allowedValue)) +{ + std::cerr << "\n AllowedValue:" << + "\n allowedValue: " << m_allowedValue; + std::cerr << std::endl; +} + + +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")) +{ + std::cerr << "\n StateVariable:" << + "\n name: " << m_name << + "\n dataType: " << m_dataType << + "\n defaultValue: " << m_defaultValue << + "\n sendEvents: " << m_sendEvents; + std::cerr << std::endl; +} + + +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) +{ + std::ostringstream msg; + int errcode; + + std::vector 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 ) { + std::cerr << "Error generating scpdURL from " << + "|" << URLBase << "|" << + m_SCPDURL << "|."; + std::cerr << std::endl; + } else { + m_absSCPDURL = scpdURL; + } + + std::vector 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 ) { + std::cerr << "Error generating controlURL from " << + "|" << URLBase << "|" << + m_controlURL << "|."; + std::cerr << std::endl; + } else { + m_absControlURL = controlURL; + } + + std::vector 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 ) { + std::cerr << "Error generating eventURL from " << + "|" << URLBase << "|" << + m_eventSubURL << "|."; + std::cerr << std::endl; + } else { + m_absEventSubURL = eventURL; + } + + std::cerr << "\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; + + 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 + msg.str(""); + std::cerr << "WAN Service Detected: '" << + m_serviceType << "'."; + std::cerr << std::endl; + // Subscribe + upnpLib.m_ctrlPoint.Subscribe(*this); +#if 0 +//#warning Delete this code on release. + } else { + msg.str(""); + std::cerr << "WAN service detected again: '" << + m_serviceType << + "'. Will only use the first instance."; + std::cerr << std::endl; + } +#endif + } else { + msg.str(""); + std::cerr << "Uninteresting service detected: '" << + m_serviceType << "'. Ignoring."; + std::cerr << std::endl; + } +} + + +CUPnPService::~CUPnPService() +{ +} + + +bool CUPnPService::Execute( + const std::string &ActionName, + const std::vector &ArgValue) const +{ + std::ostringstream msg; + if (m_SCPD.get() == NULL) { + std::cerr << "Service without SCPD Document, cannot execute action '" << ActionName << + "' for service '" << GetServiceType() << "'."; + std::cerr << std::endl; + return false; + } + std::ostringstream msgAction("Sending action "); + // Check for correct action name + ActionList::const_iterator itAction = + m_SCPD->GetActionList().find(ActionName); + if (itAction == m_SCPD->GetActionList().end()) { + std::cerr << "Invalid action name '" << ActionName << + "' for service '" << GetServiceType() << "'."; + std::cerr << std::endl; + return false; + } + msgAction << ActionName << "("; + 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()) { + std::cerr << "Invalid argument name '" << ArgValue[i].GetArgument() << + "' for action '" << action.GetName() << + "' for service '" << GetServiceType() << "'."; + std::cerr << std::endl; + return false; + } + const CUPnPArgument &argument = *(itArg->second); + if (tolower(argument.GetDirection()[0]) != 'i' || + tolower(argument.GetDirection()[1]) != 'n') { + std::cerr << "Invalid direction for argument '" << + ArgValue[i].GetArgument() << + "' for action '" << action.GetName() << + "' for service '" << GetServiceType() << "'."; + std::cerr << std::endl; + 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()) { + std::cerr << "Inconsistent Service State Table, did not find '" << + relatedStateVariableName << + "' for argument '" << argument.GetName() << + "' for action '" << action.GetName() << + "' for service '" << GetServiceType() << "'."; + std::cerr << std::endl; + return false; + } + const CUPnPStateVariable &stateVariable = *(itSVT->second); + if ( !stateVariable.GetAllowedValueList().empty() && + stateVariable.GetAllowedValueList().find(ArgValue[i].GetValue()) == + stateVariable.GetAllowedValueList().end()) { + std::cerr << "Value not allowed '" << ArgValue[i].GetValue() << + "' for state variable '" << relatedStateVariableName << + "' for argument '" << argument.GetName() << + "' for action '" << action.GetName() << + "' for service '" << GetServiceType() << "'."; + + return false; + } + } + if (firstTime) { + firstTime = false; + } else { + std::cerr << ", "; + } + std::cerr << + ArgValue[i].GetArgument() << + "='" << + ArgValue[i].GetValue() << + "'"; + } + std::cerr << ")"; + std::cerr << std::endl; + // 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 { + ActionDoc = UpnpMakeAction( + action.GetName().c_str(), + GetServiceType().c_str(), + 0, NULL); + if (!ActionDoc) { + std::cerr << "Error: UpnpMakeAction returned NULL."; + std::cerr << std::endl; + return false; + } + } +#if 0 + // Send the action asynchronously + UpnpSendActionAsync( + m_UPnPControlPoint.GetUPnPClientHandle(), + GetAbsControlURL().c_str(), + GetServiceType().c_str(), + NULL, ActionDoc, + static_cast(&CUPnPControlPoint::Callback), + NULL); + return true; +#endif + + // Send the action synchronously + IXML_Document *RespDoc = NULL; + int ret = UpnpSendAction( + m_UPnPControlPoint.GetUPnPClientHandle(), + GetAbsControlURL().c_str(), + GetServiceType().c_str(), + NULL, ActionDoc, &RespDoc); + if (ret != UPNP_E_SUCCESS) { + m_upnpLib.processUPnPErrorMessage( + "UpnpSendAction", ret, NULL, RespDoc); + ixmlDocument_free(ActionDoc); + ixmlDocument_free(RespDoc); + return false; + } + ixmlDocument_free(ActionDoc); + + // Check the response document + m_upnpLib.ProcessActionResponse( + RespDoc, action.GetName()); + + // Free the response document + ixmlDocument_free(RespDoc); + + return true; +} + + +const std::string CUPnPService::GetStateVariable( + const std::string &stateVariableName) +{ +// DOMString StVarVal; +// int ret = UpnpGetServiceVarStatus( +// m_UPnPControlPoint.GetUPnPClientHandle(), +// GetAbsControlURL().c_str(), +// stateVariableName.c_str(), +// &StVarVal); + std::cerr << "GetAbsControlURL().c_str() : " << GetAbsControlURL().c_str() << std::endl; + std::cerr << "stateVariableName.c_str() : " << stateVariableName.c_str() << std::endl; + int ret = UpnpGetServiceVarStatusAsync( + m_UPnPControlPoint.GetUPnPClientHandle(), /** The handle of the control point. */ + GetAbsControlURL().c_str(), /** The URL of the service. */ + stateVariableName.c_str(), /** The name of the variable to query. */ + static_cast(&CUPnPService::GetServiceVarStatusAsyncCallback), /** Pointer to a callback function to be invoked when the operation is complete. */ + NULL /** Pointer to user data to pass to the callback function when invoked. */ + ); + + if (ret != UPNP_E_SUCCESS) { + std::ostringstream msg; + msg << "GetStateVariable(\"" << + stateVariableName << + "\"): in a call to UpnpGetServiceVarStatus"; + m_upnpLib.processUPnPErrorMessage( + msg.str(), ret, NULL, NULL); + return stdEmptyString; + } + std::cerr << "UpnpGetServiceVarStatusAsync) called successfully" << std::endl; + + //double lock for blocking it. It will be deblocked by the callback funtion GetServiceVarStatusAsyncCallback + CUPnPControlPoint *upnpCP = CUPnPControlPoint::s_CtrlPoint; + upnpCP->m_getStateVariableMutex.lock(); + std::cerr << "m_getStateVariableMutex.lock() 1 finished." << std::endl; + + //return StVarVal; + return upnpCP->m_getStateVariableLastResult; +} + + +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")) +{ + std::ostringstream msg; + int presURLlen = strlen(URLBase.c_str()) + + strlen(m_presentationURL.c_str()) + 2; + std::vector vpresURL(presURLlen); + char* presURL = &vpresURL[0]; + int errcode = UpnpResolveURL( + URLBase.c_str(), + m_presentationURL.c_str(), + presURL); + if (errcode != UPNP_E_SUCCESS) { + std::cerr << "Error generating presentationURL from " << + "|" << URLBase << "|" << + m_presentationURL << "|."; + std::cerr << std::endl; + } else { + m_presentationURL = presURL; + } + + msg.str(""); + std::cerr << "\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; +} + + +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) +{ + std::cerr << + "\n Root Device: " << + "\n URLBase: " << m_URLBase << + "\n Fixed URLBase: " << FixedURLBase << + "\n location: " << m_location << + "\n expires: " << m_expires + << std::endl; +} + + +CUPnPControlPoint *CUPnPControlPoint::s_CtrlPoint = NULL; + + +CUPnPControlPoint::CUPnPControlPoint(unsigned short udpPort) +: +m_upnpLib(*this), +m_UPnPClientHandle(), +m_RootDeviceMap(), +m_ServiceMap(), +m_ActivePortMappingsMap(), +m_RootDeviceListMutex(), +m_IGWDeviceDetected(false), +m_WanService(NULL) +{ + std::cerr << "CUPnPControlPoint Constructor" << std::endl; + // Pointer to self + s_CtrlPoint = this; + + // Start UPnP + int ret; + char *ipAddress = NULL; + unsigned short port = 0; + int resLog = UpnpInitLog(); + ret = UpnpInit(ipAddress, udpPort); + std::cerr << "Init log : " << resLog << std::endl; +#ifdef UPNP_DEBUG + std::cerr << "CUPnPControlPoint Constructor UpnpInit finished" << std::endl; +#endif + if (ret != UPNP_E_SUCCESS) { + std::cerr << "error(UpnpInit): Error code "; + goto error; + } + port = UpnpGetServerPort(); + ipAddress = UpnpGetServerIpAddress(); + std::cerr << "bound to " << ipAddress << ":" << + port << "." << std::endl; + + ret = UpnpRegisterClient( + static_cast(&CUPnPControlPoint::Callback), + &m_UPnPClientHandle, + &m_UPnPClientHandle); + if (ret != UPNP_E_SUCCESS) { + std::cerr << "error(UpnpRegisterClient): Error registering callback: "; + 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, 30, 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) { + std::cerr << "error(UpnpSearchAsync): Error sending search request: "; + 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. + std::cerr << "blocking m_WaitForSearchTimeoutMutex." << std::endl; + //RsMutex toto(m_WaitForSearchTimeoutMutex); + m_WaitForSearchTimeoutMutex.lock(); + std::cerr << "m_WaitForSearchTimeoutMutex blocking finished." << std::endl; + + } + + std::cerr << "CUPnPControlPoint Constructor finished" << std::endl; + return; + + // Error processing +error: + std::cerr << "UpnpFinish called within CUPnPControlPoint constructor." << std::endl; + UpnpFinish(); + std::cerr << ret << ": " << m_upnpLib.GetUPnPErrorMessage(ret) << "." << std::endl; + return; +} + + +char* CUPnPControlPoint::getInternalIpAddress() +{ + return UpnpGetServerIpAddress(); +} + +CUPnPControlPoint::~CUPnPControlPoint() +{ + for( RootDeviceMap::iterator it = m_RootDeviceMap.begin(); + it != m_RootDeviceMap.end(); + ++it) { + delete it->second; + } + // Remove all first + // RemoveAll(); + UpnpUnRegisterClient(m_UPnPClientHandle); + std::cerr << "UpnpFinish called within CUPnPControlPoint destructor." << std::endl; + UpnpFinish(); +} + + +bool CUPnPControlPoint::AddPortMappings( + std::vector &upnpPortMapping) +{ + if (!WanServiceDetected()) { + std::cerr << "UPnP Error: " + "CUPnPControlPoint::AddPortMapping: " + "WAN Service not detected." << std::endl; + return false; + } + std::cerr << "CUPnPControlPoint::AddPortMappings called." << std::endl; + + int n = upnpPortMapping.size(); + bool ok = false; + + // Check the number of port mappings before + std::istringstream PortMappingNumberOfEntries( + m_WanService->GetStateVariable( + "PortMappingNumberOfEntries")); + unsigned long oldNumberOfEntries; + PortMappingNumberOfEntries >> 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]); + } + } + + // Test some variables, this is deprecated, might not work + // with some routers + m_WanService->GetStateVariable("ConnectionType"); + m_WanService->GetStateVariable("PossibleConnectionTypes"); + m_WanService->GetStateVariable("ConnectionStatus"); + m_WanService->GetStateVariable("Uptime"); + m_WanService->GetStateVariable("LastConnectionError"); + m_WanService->GetStateVariable("RSIPAvailable"); + m_WanService->GetStateVariable("NATEnabled"); + m_WanService->GetStateVariable("ExternalIPAddress"); + m_WanService->GetStateVariable("PortMappingNumberOfEntries"); + m_WanService->GetStateVariable("PortMappingLeaseDuration"); + + // Just for testing +// std::vector argval; +// argval.resize(0); +// m_WanService->Execute("GetStatusInfo", argval); + +#if 0 + // These do not work. Their value must be requested for a + // specific port mapping. + m_WanService->GetStateVariable("PortMappingEnabled"); + m_WanService->GetStateVariable("RemoteHost"); + m_WanService->GetStateVariable("ExternalPort"); + m_WanService->GetStateVariable("InternalPort"); + m_WanService->GetStateVariable("PortMappingProtocol"); + m_WanService->GetStateVariable("InternalClient"); + m_WanService->GetStateVariable("PortMappingDescription"); +#endif + + // Debug only +#ifdef UPNP_DEBUG + std::cerr << "CUPnPControlPoint::AddPortMappings: " + "m_ActivePortMappingsMap.size() == " << + m_ActivePortMappingsMap.size() << std::endl; +#endif + + // Not very good, must find a better test + PortMappingNumberOfEntries.str( + m_WanService->GetStateVariable( + "PortMappingNumberOfEntries")); + unsigned long newNumberOfEntries; + PortMappingNumberOfEntries >> newNumberOfEntries; + ok = newNumberOfEntries - oldNumberOfEntries == 4; + + std::cerr << "CUPnPControlPoint::AddPortMappings finished. success : " << ok << std::endl; + + return ok; +} + +std::string CUPnPControlPoint::getExternalAddress() +{ + if (!WanServiceDetected()) { + std::cerr << "UPnP Error: " + "CUPnPControlPoint::AddPortMapping: " + "WAN Service not detected." << std::endl; + return false; + } + + return m_WanService->GetStateVariable("ExternalIPAddress"); +} + +void CUPnPControlPoint::RefreshPortMappings() +{ + for ( PortMappingMap::iterator it = m_ActivePortMappingsMap.begin(); + it != m_ActivePortMappingsMap.end(); + ++it) { + PrivateAddPortMapping(it->second); + } + + // For testing + m_WanService->GetStateVariable("PortMappingNumberOfEntries"); +} + + +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 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 &upnpPortMapping) +{ + if (!WanServiceDetected()) { + std::cerr << "UPnP Error: " + "CUPnPControlPoint::DeletePortMapping: " + "WAN Service not detected." << std::endl; + return false; + } + + int n = upnpPortMapping.size(); + bool ok = false; + + // Check the number of port mappings before + std::istringstream PortMappingNumberOfEntries( + m_WanService->GetStateVariable( + "PortMappingNumberOfEntries")); + unsigned long oldNumberOfEntries; + PortMappingNumberOfEntries >> oldNumberOfEntries; + + // 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 { + std::cerr << "UPnP Error: " + "CUPnPControlPoint::DeletePortMapping: " + "Mapping was not found in the active " + "mapping map." << std::endl; + } + + // Delete the port mapping + PrivateDeletePortMapping(upnpPortMapping[i]); + } + } + + // Debug only + std::cerr << "CUPnPControlPoint::DeletePortMappings: " + "m_ActivePortMappingsMap.size() == " << + m_ActivePortMappingsMap.size() << std::endl; + + // Not very good, must find a better test + PortMappingNumberOfEntries.str( + m_WanService->GetStateVariable( + "PortMappingNumberOfEntries")); + unsigned long newNumberOfEntries; + PortMappingNumberOfEntries >> newNumberOfEntries; + ok = oldNumberOfEntries - newNumberOfEntries == 4; + + return ok; +} + + +bool CUPnPControlPoint::PrivateDeletePortMapping( + CUPnPPortMapping &upnpPortMapping) +{ + // Start building the action + std::string actionName("DeletePortMapping"); + std::vector 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) { + ret &= it->second->Execute(actionName, argval); + } + + return ret; +} + + +// This function is static +int CUPnPControlPoint::Callback(Upnp_EventType EventType, void *Event, void * /*Cookie*/) +{ + std::ostringstream msg; + std::ostringstream msg2; + // Somehow, this is unreliable. UPNP_DISCOVERY_ADVERTISEMENT_ALIVE events + // happen with a wrong cookie and... boom! + // CUPnPControlPoint *upnpCP = static_cast(Cookie); + CUPnPControlPoint *upnpCP = CUPnPControlPoint::s_CtrlPoint; + + //fprintf(stderr, "Callback: %d, Cookie: %p\n", EventType, Cookie); + switch (EventType) { + case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: + //fprintf(stderr, "Callback: UPNP_DISCOVERY_ADVERTISEMENT_ALIVE\n"); + //std::cerr << "error(UPNP_DISCOVERY_ADVERTISEMENT_ALIVE): "; + std::cerr << "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: "; + goto upnpDiscovery; + case UPNP_DISCOVERY_SEARCH_RESULT: { + //fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_RESULT\n"); + //std::cerr << "error(UPNP_DISCOVERY_SEARCH_RESULT): "; + std::cerr << "UPNP_DISCOVERY_SEARCH_RESULT: "; + // 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) { + std::cerr << upnpCP->m_upnpLib.GetUPnPErrorMessage(d_event->ErrCode) << "."; + std::cerr << std::endl; + } + std::cerr << "Retrieving device description from " << + d_event->Location << "." << std::endl; + // Get the XML tree device description in doc + ret = UpnpDownloadXmlDoc(d_event->Location, &doc); + if (ret != UPNP_E_SUCCESS) { + std::cerr << "Error retrieving device description from " << + d_event->Location << ": " << + upnpCP->m_upnpLib.GetUPnPErrorMessage(ret) << "."; + } else { + std::cerr << "Retrieving device description from " << + d_event->Location << "." << std::endl; + } + 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) { + std::cerr << "Internet Gateway Device Detected." << std::endl; + //} + std::cerr << "Getting root device desc." << std::endl; + // Add the root device to our list + upnpCP->AddRootDevice(rootDevice, urlBase, + d_event->Location, d_event->Expires); + std::cerr << "Finishing getting root device desc." << std::endl; + } + // Free the XML doc tree + ixmlDocument_free(doc); + } + break; + } + case UPNP_DISCOVERY_SEARCH_TIMEOUT: { + //fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_TIMEOUT\n"); + // Search timeout + std::cerr << "UPNP_DISCOVERY_SEARCH_TIMEOUT : unlocking mutex." << std::endl; + + // 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) { + std::cerr << "error(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE): " << + upnpCP->m_upnpLib.GetUPnPErrorMessage(dab_event->ErrCode) << + "." << std::endl; + } + 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: { + fprintf(stderr, "Callback: UPNP_EVENT_RECEIVED\n"); + // 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.str(), 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 << "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 << "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, + es_event->PublisherUrl, + &TimeOut, + newSID); + if (ret != UPNP_E_SUCCESS) { + msg << "Error Subscribing to EventURL"; + upnpCP->m_upnpLib.processUPnPErrorMessage( + msg.str(), es_event->ErrCode, NULL, NULL); + } else { + ServiceMap::iterator it = + upnpCP->m_ServiceMap.find(es_event->PublisherUrl); + if (it != upnpCP->m_ServiceMap.end()) { + CUPnPService &service = *(it->second); + service.SetTimeout(TimeOut); + service.SetSID(newSID); + std::cerr << "Re-subscribed to EventURL '" << + es_event->PublisherUrl << + "' 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 { + std::cerr << "Error: did not find service " << + newSID << " in the service map." << std::endl; + } + } + 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, + ""); + } + /* 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: { + fprintf(stderr, "Callback: UPNP_CONTROL_GET_VAR_COMPLETE\n"); + msg << "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.str(), sv_event->ErrCode, NULL, NULL); + } else { + std::cerr << sv_event->StateVarName << std::endl; + std::cerr << sv_event->CtrlUrl << std::endl; + std::cerr << sv_event->CurrentVal << std::endl; +#if 0 + // Warning: The use of UpnpGetServiceVarStatus and + // UpnpGetServiceVarStatusAsync is deprecated by the + // UPnP forum. + TvCtrlPointHandleGetVar( + sv_event->CtrlUrl, + sv_event->StateVarName, + sv_event->CurrentVal ); +#endif + } + 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"); + std::cerr << "error(UPNP_CONTROL_GET_VAR_REQUEST): "; + goto eventSubscriptionRequest; + case UPNP_CONTROL_ACTION_REQUEST: + //fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_REQUEST\n"); + std::cerr << "error(UPNP_CONTROL_ACTION_REQUEST): "; + goto eventSubscriptionRequest; + case UPNP_EVENT_SUBSCRIPTION_REQUEST: + //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_REQUEST\n"); + std::cerr << "error(UPNP_EVENT_SUBSCRIPTION_REQUEST): "; +eventSubscriptionRequest: + std::cerr << "This is not a UPnP Device, this is a UPnP Control Point, event ignored." << std::endl; + break; + default: + // Humm, this is not good, we forgot to handle something... + fprintf(stderr, + "Callback: default... Unknown event:'%d', not good.\n", + EventType); + std::cerr << "error(UPnP::Callback): Event not handled:'" << + EventType << "'." << std::endl; + // Better not throw in the callback. Who would catch it? + //throw CUPnPException(msg); + break; + } + + return 0; +} + +// This function is static +int CUPnPService::GetServiceVarStatusAsyncCallback(Upnp_EventType EventType, void *Event, void * /*Cookie*/) +{ + //fprintf(stderr, "Callback: %d, Cookie: %p\n", EventType, Cookie); + CUPnPControlPoint *upnpCP = CUPnPControlPoint::s_CtrlPoint; + switch (EventType) { + case UPNP_EVENT_RECEIVED: { + fprintf(stderr, "GetServiceVarStatusAsyncCallback: UPNP_EVENT_RECEIVED\n"); + // 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_CONTROL_GET_VAR_COMPLETE: { + fprintf(stderr, "Callback GetServiceVarStatusAsyncCallback : UPNP_CONTROL_GET_VAR_COMPLETE\n"); + struct Upnp_State_Var_Complete *sv_event = + (struct Upnp_State_Var_Complete *)Event; + if (sv_event->ErrCode != UPNP_E_SUCCESS) { + std::cerr << "error(UPNP_CONTROL_GET_VAR_COMPLETE) : "; + std::cerr << "Error Code : " << sv_event->ErrCode << std::endl; + } else { + std::cerr << sv_event->StateVarName << std::endl; + std::cerr << sv_event->CtrlUrl << std::endl; + std::cerr << sv_event->CurrentVal << std::endl; + upnpCP->m_getStateVariableLastResult = sv_event->CurrentVal; + } + break; + } + default: + // Humm, this is not good, we forgot to handle something... + fprintf(stderr, + "Callback: default... Unknown event:'%d', not good.\n", + EventType); + std::cerr << "error(UPnP::Callback): Event not handled:'" << + EventType << "'." << std::endl; + // Better not throw in the callback. Who would catch it? + //throw CUPnPException(msg); + break; + } + + std::cerr << "Unlocking m_getStateVariableMutex." << std::endl; + upnpCP->m_getStateVariableMutex.unlock(); + return 0; +} + + +void CUPnPControlPoint::OnEventReceived( + const std::string &Sid, + int EventKey, + IXML_Document *ChangedVariablesDoc) +{ + std::cerr << "UPNP_EVENT_RECEIVED:" << + "\n SID: " << Sid << + "\n Key: " << EventKey << + "\n Property list:"; + 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); + std::cerr << "\n " << + childTag << "='" << + childValue << "'"; + child = m_upnpLib.Element_GetNextSibling(child); + } + } else { + std::cerr << "\n Empty property list."; + } + std::cerr << std::endl; + // 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; + std::cerr << "Successfully retrieved SCPD Document for service " << + service.GetServiceType() << ", absEventSubURL: " << + service.GetAbsEventSubURL() << "." << std::endl; + + // 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) { + std::cerr << "Successfully subscribed to service " << + service.GetServiceType() << ", absEventSubURL: " << + service.GetAbsEventSubURL() << "." << std::endl; + } else { + std::cerr << "Error subscribing to service " << + service.GetServiceType() << ", absEventSubURL: " << + service.GetAbsEventSubURL() << ", error: " << + m_upnpLib.GetUPnPErrorMessage(errcode) << "."; + goto error; + } + } else { + std::cerr << "Error getting SCPD Document from " << + service.GetAbsSCPDURL() << "." << std::endl; + } + + return; + + // Error processing +error: + std::cerr << std::endl; +} + + +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 diff --git a/libretroshare/src/upnp/UPnPBase.h b/libretroshare/src/upnp/UPnPBase.h new file mode 100644 index 000000000..3ea159da1 --- /dev/null +++ b/libretroshare/src/upnp/UPnPBase.h @@ -0,0 +1,632 @@ +// +// 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 ) +// +// Any parts of this program derived from the xMule, lMule or eMule project, +// or contributed by third-party developers are copyrighted by their +// respective authors. +// +// 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. +// +// 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 +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +// + + +#include +#include +#include +#include +#include + +#include "upnp.h" +#include "upnptools.h" +#include "upnpdebug.h" +#include "util/rsthreads.h" + +#include +#include + +#ifdef UPNP_C + std::string stdEmptyString; +#else // UPNP_C + extern std::string stdEmptyString; +#endif // UPNP_C + + +/** + * Case insensitive std::string comparison + */ +bool stdStringIsEqualCI( + const std::string &s1, + const std::string &s2); + + +class CUPnPPortMapping +{ +private: + std::string m_ex_port; + std::string m_in_port; + std::string m_protocol; + std::string m_enabled; + std::string m_description; + std::string m_key; + +public: + CUPnPPortMapping( + int in_port = 0, + int ex_port = 0, + const std::string &protocol = stdEmptyString, + bool enabled = false, + const std::string &description = stdEmptyString); + ~CUPnPPortMapping() {} + + const std::string &getExPort() const + { return m_ex_port; } + const std::string &getInPort() const + { return m_in_port; } + const std::string &getProtocol() const + { return m_protocol; } + const std::string &getEnabled() const + { return m_enabled; } + const std::string &getDescription() const + { return m_description; } + const std::string &getKey() const + { return m_key; } +}; + + +class CUPnPControlPoint; + + +class CUPnPLib +{ +public: + static const std::string &UPNP_ROOT_DEVICE; + static const std::string &UPNP_DEVICE_IGW; + static const std::string &UPNP_DEVICE_WAN; + static const std::string &UPNP_DEVICE_WAN_CONNECTION; + static const std::string &UPNP_DEVICE_LAN; + static const std::string &UPNP_SERVICE_LAYER3_FORWARDING; + static const std::string &UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG; + static const std::string &UPNP_SERVICE_WAN_IP_CONNECTION; + static const std::string &UPNP_SERVICE_WAN_PPP_CONNECTION; + CUPnPControlPoint &m_ctrlPoint; + +public: + CUPnPLib(CUPnPControlPoint &ctrlPoint); + ~CUPnPLib() {} + + // Convenience function so we don't have to write explicit calls + // to char2unicode every time + std::string GetUPnPErrorMessage(int code) const; + + // Convenience function to avoid repetitive processing of error + // messages + std::string processUPnPErrorMessage( + const std::string &messsage, + int code, + const DOMString errorString, + IXML_Document *doc) const; + + // Processing response to actions + void ProcessActionResponse( + IXML_Document *RespDoc, + const std::string &actionName) const; + + // IXML_Element + IXML_Element *Element_GetRootElement( + IXML_Document *doc) const; + IXML_Element *Element_GetFirstChild( + IXML_Element *parent) const; + IXML_Element *Element_GetNextSibling( + IXML_Element *child) const; + const DOMString Element_GetTag( + IXML_Element *element) const; + const std::string Element_GetTextValue( + IXML_Element *element) const; + const std::string Element_GetChildValueByTag( + IXML_Element *element, + const DOMString tag) const; + IXML_Element *Element_GetFirstChildByTag( + IXML_Element *element, + const DOMString tag) const; + IXML_Element *Element_GetNextSiblingByTag( + IXML_Element *element, + const DOMString tag) const; + const std::string Element_GetAttributeByTag( + IXML_Element *element, + const DOMString tag) const; +}; + + +class CUPnPControlPoint; + +/* + * Even though we can retrieve the upnpLib handler from the upnpControlPoint, + * we must pass it separetly at this point, because the class CUPnPControlPoint + * must be declared after. + * + * CUPnPLib can only be removed from the constructor once we agree to link to + * UPnPLib explicitly, making this dlopen() stuff unnecessary. + */ +template +class CXML_List : public std::map +{ +public: + CXML_List( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *parent, + const std::string &url); + ~CXML_List(); +}; + + +template +CXML_List::CXML_List( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *parent, + const std::string &url) +{ + IXML_Element *elementList = + upnpLib.Element_GetFirstChildByTag(parent, XML_LIST_NAME); + unsigned int i = 0; + for ( IXML_Element *element = upnpLib.Element_GetFirstChildByTag(elementList, XML_ELEMENT_NAME); + element; + element = upnpLib.Element_GetNextSiblingByTag(element, XML_ELEMENT_NAME)) { + // Add a new element to the element list + T *upnpElement = new T(upnpControlPoint, upnpLib, element, url); + (*this)[upnpElement->GetKey()] = upnpElement; + ++i; + } + std::ostringstream msg; + msg << "\n " << XML_LIST_NAME << ": " << + i << " " << XML_ELEMENT_NAME << "s."; + std::cerr << msg; +} + + +template +CXML_List::~CXML_List() +{ + typename CXML_List::iterator it; + for(it = this->begin(); it != this->end(); ++it) { + delete (*it).second; + } +} + +extern const char s_argument[]; +extern const char s_argumentList[]; +extern const char s_action[]; +extern const char s_actionList[]; +extern const char s_allowedValue[]; +extern const char s_allowedValueList[]; +extern const char s_stateVariable[]; +extern const char s_serviceStateTable[]; +extern const char s_service[]; +extern const char s_serviceList[]; +extern const char s_device[]; +extern const char s_deviceList[]; + +#ifdef UPNP_C + const char s_argument[] = "argument"; + const char s_argumentList[] = "argumentList"; + const char s_action[] = "action"; + const char s_actionList[] = "actionList"; + const char s_allowedValue[] = "allowedValue"; + const char s_allowedValueList[] = "allowedValueList"; + const char s_stateVariable[] = "stateVariable"; + const char s_serviceStateTable[] = "serviceStateTable"; + const char s_service[] = "service"; + const char s_serviceList[] = "serviceList"; + const char s_device[] = "device"; + const char s_deviceList[] = "deviceList"; +#endif // UPNP_C + + +class CUPnPArgument; +typedef CXML_List ArgumentList; +class CUPnPAction; +typedef CXML_List ActionList; +class CUPnPStateVariable; +typedef CXML_List ServiceStateTable; +class CUPnPAllowedValue; +typedef CXML_List AllowedValueList; +class CUPnPService; +typedef CXML_List ServiceList; +class CUPnPDevice; +typedef CXML_List DeviceList; + + +class CUPnPError +{ +private: + IXML_Element *m_root; + const std::string m_ErrorCode; + const std::string m_ErrorDescription; +public: + CUPnPError( + const CUPnPLib &upnpLib, + IXML_Document *errorDoc); + ~CUPnPError() {} + const std::string &getErrorCode() const + { return m_ErrorCode; } + const std::string &getErrorDescription() const + { return m_ErrorDescription; } +}; + + +class CUPnPArgument +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + const std::string m_name; + const std::string m_direction; + bool m_retval; + const std::string m_relatedStateVariable; + +public: + CUPnPArgument( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *argument, + const std::string &SCPDURL); + ~CUPnPArgument() {} + const std::string &GetName() const + { return m_name; } + const std::string &GetDirection() const + { return m_direction; } + bool GetRetVal() const + { return m_retval; } + const std::string &GetRelatedStateVariable() const + { return m_relatedStateVariable; } + const std::string &GetKey() const + { return m_name; } +}; + + + +class CUPnPAction +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + ArgumentList m_ArgumentList; + const std::string m_name; + +public: + CUPnPAction( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *action, + const std::string &SCPDURL); + ~CUPnPAction() {} + const std::string &GetName() const + { return m_name; } + const std::string &GetKey() const + { return m_name; } + const ArgumentList &GetArgumentList() const + { return m_ArgumentList; } +}; + + +class CUPnPAllowedValue +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + const std::string m_allowedValue; + +public: + CUPnPAllowedValue( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *allowedValue, + const std::string &SCPDURL); + ~CUPnPAllowedValue() {} + const std::string &GetAllowedValue() const + { return m_allowedValue; } + const std::string &GetKey() const + { return m_allowedValue; } +}; + + +class CUPnPStateVariable +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + AllowedValueList m_AllowedValueList; + const std::string m_name; + const std::string m_dataType; + const std::string m_defaultValue; + const std::string m_sendEvents; + +public: + CUPnPStateVariable( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *stateVariable, + const std::string &URLBase); + ~CUPnPStateVariable() {} + const std::string &GetNname() const + { return m_name; } + const std::string &GetDataType() const + { return m_dataType; } + const std::string &GetDefaultValue() const + { return m_defaultValue; } + const std::string &GetKey() const + { return m_name; } + const AllowedValueList &GetAllowedValueList() const + { return m_AllowedValueList; } +}; + + +class CUPnPSCPD +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + ActionList m_ActionList; + ServiceStateTable m_ServiceStateTable; + const std::string m_SCPDURL; + +public: + CUPnPSCPD( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *scpd, + const std::string &SCPDURL); + ~CUPnPSCPD() {} + const ActionList &GetActionList() const + { return m_ActionList; } + const ServiceStateTable &GetServiceStateTable() const + { return m_ServiceStateTable; } +}; + + +class CUPnPArgumentValue +{ +private: + std::string m_argument; + std::string m_value; + +public: + CUPnPArgumentValue(); + CUPnPArgumentValue(const std::string &argument, const std::string &value); + ~CUPnPArgumentValue() {} + + const std::string &GetArgument() const { return m_argument; } + const std::string &GetValue() const { return m_value; } + const std::string &SetArgument(const std::string& argument) { return m_argument = argument; } + const std::string &SetValue(const std::string &value) { return m_value = value; } +}; + + +class CUPnPService +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + CUPnPLib &m_upnpLib; + const std::string m_serviceType; + const std::string m_serviceId; + const std::string m_SCPDURL; + const std::string m_controlURL; + const std::string m_eventSubURL; + std::string m_absSCPDURL; + std::string m_absControlURL; + std::string m_absEventSubURL; + int m_timeout; + Upnp_SID m_SID; + std::auto_ptr m_SCPD; + +public: + CUPnPService( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *service, + const std::string &URLBase); + ~CUPnPService(); + + const std::string &GetServiceType() const + { return m_serviceType; } + const std::string &GetServiceId() const + { return m_serviceId; } + const std::string &GetSCPDURL() const + { return m_SCPDURL; } + const std::string &GetAbsSCPDURL() const + { return m_absSCPDURL; } + const std::string &GetControlURL() const + { return m_controlURL; } + const std::string &GetEventSubURL() const + { return m_eventSubURL; } + const std::string &GetAbsControlURL() const + { return m_absControlURL; } + const std::string &GetAbsEventSubURL() const + { return m_absEventSubURL; } + int GetTimeout() const + { return m_timeout; } + void SetTimeout(int t) + { m_timeout = t; } + int *GetTimeoutAddr() + { return &m_timeout; } + char *GetSID() + { return m_SID; } + void SetSID(const char *s) + { memcpy(m_SID, s, sizeof(Upnp_SID)); } + const std::string &GetKey() const + { return m_serviceId; } + bool IsSubscribed() const + { return m_SCPD.get() != NULL; } + void SetSCPD(CUPnPSCPD *SCPD) + { m_SCPD.reset(SCPD); } + + bool Execute( + const std::string &ActionName, + const std::vector &ArgValue) const; + const std::string GetStateVariable( + const std::string &stateVariableName); + + //callback Function + static int GetServiceVarStatusAsyncCallback( + Upnp_EventType EventType, + void* Event, + void* Cookie); + +}; + + +class CUPnPDevice +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + + // Please, lock these lists before use + DeviceList m_DeviceList; + ServiceList m_ServiceList; + + const std::string m_deviceType; + const std::string m_friendlyName; + const std::string m_manufacturer; + const std::string m_manufacturerURL; + const std::string m_modelDescription; + const std::string m_modelName; + const std::string m_modelNumber; + const std::string m_modelURL; + const std::string m_serialNumber; + const std::string m_UDN; + const std::string m_UPC; + std::string m_presentationURL; + +public: + CUPnPDevice( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *device, + const std::string &URLBase); + ~CUPnPDevice() {} + + const std::string &GetUDN() const + { return m_UDN; } + const std::string &GetDeviceType() const + { return m_deviceType; } + const std::string &GetFriendlyName() const + { return m_friendlyName; } + const std::string &GetPresentationURL() const + { return m_presentationURL; } + const std::string &GetKey() const + { return m_UDN; } +}; + + +class CUPnPRootDevice : public CUPnPDevice +{ +private: + const CUPnPControlPoint &m_UPnPControlPoint; + const std::string m_URLBase; + const std::string m_location; + int m_expires; + +public: + CUPnPRootDevice( + const CUPnPControlPoint &upnpControlPoint, + CUPnPLib &upnpLib, + IXML_Element *rootDevice, + const std::string &OriginalURLBase, + const std::string &FixedURLBase, + const char *location, + int expires); + ~CUPnPRootDevice() {} + + const std::string &GetURLBase() const + { return m_URLBase; } + const std::string &GetLocation() const + { return m_location; } + int GetExpires() const + { return m_expires; } + void SetExpires(int expires) + { m_expires = expires; } +}; + + +typedef std::map RootDeviceMap; +typedef std::map ServiceMap; +typedef std::map PortMappingMap; + + +class CUPnPControlPoint +{ +private: + // upnp stuff + CUPnPLib m_upnpLib; + UpnpClient_Handle m_UPnPClientHandle; + RootDeviceMap m_RootDeviceMap; + ServiceMap m_ServiceMap; + PortMappingMap m_ActivePortMappingsMap; + RsMutex m_RootDeviceListMutex; + bool m_IGWDeviceDetected; + CUPnPService *m_WanService; + RsMutex m_WaitForSearchTimeoutMutex; + +public: + RsMutex m_getStateVariableMutex; + std::string m_getStateVariableLastResult; + static CUPnPControlPoint *s_CtrlPoint; + CUPnPControlPoint(unsigned short udpPort); + ~CUPnPControlPoint(); + char* getInternalIpAddress(); + std::string getExternalAddress(); + void Subscribe(CUPnPService &service); + void Unsubscribe(CUPnPService &service); + bool AddPortMappings( + std::vector &upnpPortMapping); + bool DeletePortMappings( + std::vector &upnpPortMapping); + + UpnpClient_Handle GetUPnPClientHandle() const + { return m_UPnPClientHandle; } + + bool GetIGWDeviceDetected() const + { return m_IGWDeviceDetected; } + void SetIGWDeviceDetected(bool b) + { m_IGWDeviceDetected = b; } + bool WanServiceDetected() const + { return !m_ServiceMap.empty(); } + void SetWanService(CUPnPService *service) + { m_WanService = service; } + + // Callback function + static int Callback( + Upnp_EventType EventType, + void* Event, + void* Cookie); + void OnEventReceived( + const std::string &Sid, + int EventKey, + IXML_Document *ChangedVariables); + +private: + void AddRootDevice( + IXML_Element *rootDevice, + const std::string &urlBase, + const char *location, + int expires); + void RemoveRootDevice( + const char *udn); + void RefreshPortMappings(); + bool PrivateAddPortMapping( + CUPnPPortMapping &upnpPortMapping); + bool PrivateDeletePortMapping( + CUPnPPortMapping &upnpPortMapping); +}; + +// File_checked_for_headers diff --git a/libretroshare/src/upnp/upnphandler.cc b/libretroshare/src/upnp/upnphandler.cc index a95218d84..da8892290 100644 --- a/libretroshare/src/upnp/upnphandler.cc +++ b/libretroshare/src/upnp/upnphandler.cc @@ -13,183 +13,59 @@ extern "C" { #include "upnp/upnphandler.h" #include "upnp/upnputil.h" +struct WanDevice { + char UDN[250]; + char DescDocURL[250]; + char FriendlyName[250]; + char PresURL[250]; + int AdvrTimeOut; +}; + class uPnPConfigData { public: - struct UPNPDev * devlist; - struct UPNPUrls urls; - struct IGDdatas data; - char lanaddr[16]; /* my ip address on the LAN */ + struct WanDevice * WanDevice; + char lanaddr[16]; /* my ip address on the LAN */ }; -#include -#include - #include "util/rsnet.h" +UpnpClient_Handle ctrlpt_handle = -1; + bool upnphandler::initUPnPState() { - /* allocate memory */ - uPnPConfigData *upcd = new uPnPConfigData; + std::cerr << "upnphandler::initUPnPState" << std::endl; + cUPnPControlPoint = new CUPnPControlPoint(2000); -#if MINIUPNPC_VERSION >= 11 - /* Starting from version 1.1, miniupnpc api has a new parameter (int sameport) */ - upcd->devlist = upnpDiscover(2000, NULL, NULL, 0); -#else - upcd->devlist = upnpDiscover(2000, NULL, NULL); -#endif - - if(upcd->devlist) - { - struct UPNPDev * device; - printf("List of UPNP devices found on the network :\n"); - for(device=upcd->devlist;device;device=device->pNext) - { - printf("\n desc: %s\n st: %s\n", - device->descURL, device->st); - } - putchar('\n'); - if(UPNP_GetValidIGD(upcd->devlist, &(upcd->urls), - &(upcd->data), upcd->lanaddr, - sizeof(upcd->lanaddr))) - { - printf("Found valid IGD : %s\n", - upcd->urls.controlURL); - printf("Local LAN ip address : %s\n", - upcd->lanaddr); - - /* MODIFY STATE */ - dataMtx.lock(); /* LOCK MUTEX */ - - /* convert to ipaddress. */ - inet_aton(upcd->lanaddr, &(upnp_iaddr.sin_addr)); - upnp_iaddr.sin_port = htons(iport); - - upnpState = RS_UPNP_S_READY; - if (upnpConfig) - { - delete upnpConfig; - } - upnpConfig = upcd; /* */ - - dataMtx.unlock(); /* UNLOCK MUTEX */ - - - /* done -> READY */ - return 1; - - } - else - { - fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); - } - - - freeUPNPDevlist(upcd->devlist); - upcd->devlist = 0; - } - else - { - fprintf(stderr, "No IGD UPnP Device found on the network !\n"); - } + bool IGWDetected = cUPnPControlPoint->GetIGWDeviceDetected(); /* MODIFY STATE */ dataMtx.lock(); /* LOCK MUTEX */ + std::cerr << "upnphandler::initUPnPState cUPnPControlPoint internal ip adress : "; + std::cerr << cUPnPControlPoint->getInternalIpAddress() << std::endl; - upnpState = RS_UPNP_S_UNAVAILABLE; - delete upcd; - upnpConfig = NULL; + //const char ipaddr = cUPnPControlPoint->getInternalIpAddress().c_str(); + inet_aton(cUPnPControlPoint->getInternalIpAddress(), &(upnp_iaddr.sin_addr)); + upnp_iaddr.sin_port = htons(iport); + + if (IGWDetected) { + upnpState = RS_UPNP_S_READY; + } else { + upnpState = RS_UPNP_S_UNAVAILABLE; + } dataMtx.unlock(); /* UNLOCK MUTEX */ - /* done, FAILED -> NOT AVAILABLE */ + /* done, NOT AVAILABLE YET */ + if (upnpState == RS_UPNP_S_READY) { + std::cerr << "upnphandler::initUPnPState READY" << std::endl; + } else { + std::cerr << "upnphandler::initUPnPState UNAVAILABLE" << std::endl; + } return 0; } -bool upnphandler::printUPnPState() -{ - std::cerr << "upnphandler::printUPnPState() ... locking"; - std::cerr << std::endl; - - RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ - - std::cerr << "upnphandler::printUPnPState() ... locked"; - std::cerr << std::endl; - - uPnPConfigData *config = upnpConfig; - if ((upnpState >= RS_UPNP_S_READY) && (config)) - { - DisplayInfos(&(config -> urls), &(config->data)); - GetConnectionStatus(&(config -> urls), &(config->data)); - ListRedirections(&(config -> urls), &(config->data)); - } - else - { - std::cerr << "UPNP not Ready" << std::endl; - } - - return 1; -} - - -bool upnphandler::checkUPnPActive() -{ - RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ - - uPnPConfigData *config = upnpConfig; - if ((upnpState > RS_UPNP_S_READY) && (config)) - { - char eprot1[] = "TCP"; - char eprot2[] = "UDP"; - - char in_addr[256]; - char in_port1[256]; - char in_port2[256]; - char eport1[256]; - char eport2[256]; - - struct sockaddr_in localAddr = upnp_iaddr; - uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); - - snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); - snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port)); - - snprintf(in_addr, 256, "%d.%d.%d.%d", - ((linaddr >> 24) & 0xff), - ((linaddr >> 16) & 0xff), - ((linaddr >> 8) & 0xff), - ((linaddr >> 0) & 0xff)); - - snprintf(eport1, 256, "%d", eport_curr); - snprintf(eport2, 256, "%d", eport_curr); - - std::cerr << "upnphandler::checkUPnPState()"; - std::cerr << " Checking Redirection: InAddr: " << in_addr; - std::cerr << " InPort: " << in_port1; - std::cerr << " ePort: " << eport1; - std::cerr << " eProt: " << eprot1; - std::cerr << std::endl; - - - bool tcpOk = TestRedirect(&(config -> urls), &(config->data), - in_addr, in_port1, eport1, eprot1); - bool udpOk = TestRedirect(&(config -> urls), &(config->data), - in_addr, in_port2, eport2, eprot2); - - if ((!tcpOk) || (!udpOk)) - { - std::cerr << "upnphandler::checkUPnPState() ... Redirect Expired, restarting"; - std::cerr << std::endl; - - toStop = true; - toStart = true; - } - } - - return true; -} - class upnpThreadData { public: @@ -219,8 +95,6 @@ extern "C" void* doSetupUPnP(void* p) data->handler->start_upnp(); } - data->handler->printUPnPState(); - delete data; pthread_exit(NULL); @@ -247,11 +121,9 @@ bool upnphandler::start_upnp() { RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ - uPnPConfigData *config = upnpConfig; - if (!((upnpState >= RS_UPNP_S_READY) && (config))) + if (!(upnpState >= RS_UPNP_S_READY)) { - std::cerr << "upnphandler::start_upnp() Not Ready"; - std::cerr << std::endl; + std::cerr << "upnphandler::start_upnp() Not Ready" << std::endl; return false; } @@ -280,16 +152,13 @@ bool upnphandler::start_upnp() /* our port */ char in_addr[256]; char in_port1[256]; - char in_port2[256]; char eport1[256]; - char eport2[256]; upnp_iaddr.sin_port = htons(iport); struct sockaddr_in localAddr = upnp_iaddr; uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); - snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port)); snprintf(in_addr, 256, "%d.%d.%d.%d", ((linaddr >> 24) & 0xff), ((linaddr >> 16) & 0xff), @@ -297,7 +166,6 @@ bool upnphandler::start_upnp() ((linaddr >> 0) & 0xff)); snprintf(eport1, 256, "%d", eport_curr); - snprintf(eport2, 256, "%d", eport_curr); std::cerr << "Attempting Redirection: InAddr: " << in_addr; std::cerr << " InPort: " << in_port1; @@ -305,32 +173,35 @@ bool upnphandler::start_upnp() std::cerr << " eProt: " << eprot1; std::cerr << std::endl; - if (!SetRedirectAndTest(&(config -> urls), &(config->data), - in_addr, in_port1, eport1, eprot1)) - { - upnpState = RS_UPNP_S_TCP_FAILED; - } - else if (!SetRedirectAndTest(&(config -> urls), &(config->data), - in_addr, in_port2, eport2, eprot2)) - { - upnpState = RS_UPNP_S_UDP_FAILED; - } - else - { - upnpState = RS_UPNP_S_ACTIVE; - } + //build port mapping config + std::vector upnpPortMapping1; + CUPnPPortMapping cUPnPPortMapping1 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "TCP", true, "tcp retroshare redirection"); + upnpPortMapping1.push_back(cUPnPPortMapping1); + bool res = cUPnPControlPoint->AddPortMappings(upnpPortMapping1); + if (res) { + upnpState = RS_UPNP_S_ACTIVE; + } else { + upnpState = RS_UPNP_S_TCP_FAILED; + std::vector upnpPortMapping2; + CUPnPPortMapping cUPnPPortMapping2 = CUPnPPortMapping(eport_curr, ntohs(localAddr.sin_port), "UDP", true, "udp retroshare redirection"); + upnpPortMapping2.push_back(cUPnPPortMapping2); + bool res2 = cUPnPControlPoint->AddPortMappings(upnpPortMapping2); + if (res) { + upnpState = RS_UPNP_S_ACTIVE; + } else { + upnpState = RS_UPNP_S_UDP_FAILED; + } + } /* now store the external address */ - char externalIPAddress[32]; - UPNP_GetExternalIPAddress(config -> urls.controlURL, - config->data.servicetype, - externalIPAddress); - + std::string externalAdress = cUPnPControlPoint->getExternalAddress(); sockaddr_clear(&upnp_eaddr); - if(externalIPAddress[0]) + if(!externalAdress.empty()) { + const char* externalIPAddress = externalAdress.c_str(); + std::cerr << "Stored External address: " << externalIPAddress; std::cerr << ":" << eport_curr; std::cerr << std::endl; @@ -355,8 +226,7 @@ bool upnphandler::shutdown_upnp() { RsStackMutex stack(dataMtx); /* LOCK STACK MUTEX */ - uPnPConfigData *config = upnpConfig; - if (!((upnpState >= RS_UPNP_S_READY) && (config))) + if (!(upnpState >= RS_UPNP_S_READY)) { return false; } @@ -378,18 +248,23 @@ bool upnphandler::shutdown_upnp() std::cerr << " Prot: " << eprot1; std::cerr << std::endl; - RemoveRedirect(&(config -> urls), &(config->data), - eport1, eprot1); - + std::vector upnpPortMapping1; + CUPnPPortMapping *cUPnPPortMapping1 = &CUPnPPortMapping(eport_curr, 0, eprot1, true, "tcp redirection"); + upnpPortMapping1.push_back(*cUPnPPortMapping1); + cUPnPControlPoint->DeletePortMappings(upnpPortMapping1); std::cerr << "Attempting To Remove Redirection: port: " << eport2; std::cerr << " Prot: " << eprot2; std::cerr << std::endl; - RemoveRedirect(&(config -> urls), &(config->data), - eport2, eprot2); + std::vector upnpPortMapping2; + CUPnPPortMapping *cUPnPPortMapping2 = &CUPnPPortMapping(eport_curr, 0, eprot2, true, "tcp redirection"); + upnpPortMapping2.push_back(*cUPnPPortMapping2); + cUPnPControlPoint->DeletePortMappings(upnpPortMapping2); - upnpState = RS_UPNP_S_READY; + //destroy the upnp object + cUPnPControlPoint->~CUPnPControlPoint(); + upnpState = RS_UPNP_S_UNINITIALISED; toStop = false; } @@ -405,11 +280,8 @@ bool upnphandler::shutdown_upnp() upnphandler::upnphandler() :toEnable(false), toStart(false), toStop(false), - eport(0), eport_curr(0), - upnpState(RS_UPNP_S_UNINITIALISED), - upnpConfig(NULL) + eport(0), eport_curr(0) { - return; } upnphandler::~upnphandler() @@ -444,8 +316,6 @@ void upnphandler::enable(bool active) /* make background thread to startup UPnP */ background_setup_upnp(true, false); } - - } @@ -490,9 +360,9 @@ bool upnphandler::getActive() /* the address that the listening port is on */ void upnphandler::setInternalPort(unsigned short iport_in) { -// std::cerr << "UPnPHandler::setInternalAddress() pre Lock!" << std::endl; + std::cerr << "UPnPHandler::setInternalAddress() pre Lock!" << std::endl; dataMtx.lock(); /*** LOCK MUTEX ***/ -// std::cerr << "UPnPHandler::setInternalAddress() postLock!" << std::endl; + std::cerr << "UPnPHandler::setInternalAddress() postLock!" << std::endl; std::cerr << "UPnPHandler::setInternalPort(" << iport_in << ") current port: "; std::cerr << iport << std::endl; @@ -512,9 +382,9 @@ void upnphandler::setInternalPort(unsigned short iport_in) void upnphandler::setExternalPort(unsigned short eport_in) { -// std::cerr << "UPnPHandler::getExternalPort() pre Lock!" << std::endl; + std::cerr << "UPnPHandler::setExternalPort() pre Lock!" << std::endl; dataMtx.lock(); /*** LOCK MUTEX ***/ -// std::cerr << "UPnPHandler::getExternalPort() postLock!" << std::endl; + std::cerr << "UPnPHandler::setExternalPort() postLock!" << std::endl; std::cerr << "UPnPHandler::setExternalPort(" << eport_in << ") current port: "; std::cerr << eport << std::endl; @@ -565,5 +435,3 @@ bool upnphandler::getExternalAddress(struct sockaddr_in &addr) return valid; } - - diff --git a/libretroshare/src/upnp/upnphandler.h b/libretroshare/src/upnp/upnphandler.h index 5cdc61e02..e67b90dfd 100644 --- a/libretroshare/src/upnp/upnphandler.h +++ b/libretroshare/src/upnp/upnphandler.h @@ -3,15 +3,15 @@ #include -#include -#include - /* platform independent networking... */ #include "pqi/pqinetwork.h" #include "pqi/pqiassist.h" #include "util/rsthreads.h" +#include "upnp.h" +#include "upnp/UPnPBase.h" + class upnpentry { public: @@ -48,58 +48,60 @@ class upnphandler: public pqiNetAssistFirewall { public: - upnphandler(); -virtual ~upnphandler(); + upnphandler(); + virtual ~upnphandler(); - /* External Interface (pqiNetAssistFirewall) */ -virtual void enable(bool active); -virtual void shutdown(); -virtual void restart(); + /* External Interface (pqiNetAssistFirewall) */ + virtual void enable(bool active); + virtual void shutdown(); + virtual void restart(); -virtual bool getEnabled(); -virtual bool getActive(); + virtual bool getEnabled(); + virtual bool getActive(); -virtual void setInternalPort(unsigned short iport_in); -virtual void setExternalPort(unsigned short eport_in); -virtual bool getInternalAddress(struct sockaddr_in &addr); -virtual bool getExternalAddress(struct sockaddr_in &addr); + virtual void setInternalPort(unsigned short iport_in); + virtual void setExternalPort(unsigned short eport_in); + virtual bool getInternalAddress(struct sockaddr_in &addr); + virtual bool getExternalAddress(struct sockaddr_in &addr); -/* Public functions - for background thread operation, - * but effectively private from rest of RS, as in derived class - */ + /* Public functions - for background thread operation, + * but effectively private from rest of RS, as in derived class + */ + unsigned int upnpState; -bool start_upnp(); -bool shutdown_upnp(); + bool start_upnp(); + bool shutdown_upnp(); -bool initUPnPState(); -bool printUPnPState(); + bool initUPnPState(); + + /* Mutex for data below */ + RsMutex dataMtx; private: -bool background_setup_upnp(bool, bool); -bool checkUPnPActive(); + CUPnPControlPoint *cUPnPControlPoint; - /* Mutex for data below */ - RsMutex dataMtx; + bool background_setup_upnp(bool, bool); - bool toEnable; /* overall on/off switch */ - bool toStart; /* if set start forwarding */ - bool toStop; /* if set stop forwarding */ - unsigned short iport; - unsigned short eport; /* config */ - unsigned short eport_curr; /* current forwarded */ + bool toEnable; /* overall on/off switch */ + bool toStart; /* if set start forwarding */ + bool toStop; /* if set stop forwarding */ - /* info from upnp */ - unsigned int upnpState; - uPnPConfigData *upnpConfig; + unsigned short iport; + unsigned short eport; /* config */ + unsigned short eport_curr; /* current forwarded */ - struct sockaddr_in upnp_iaddr; - struct sockaddr_in upnp_eaddr; + /* info from upnp */ + struct sockaddr_in upnp_iaddr; + struct sockaddr_in upnp_eaddr; - /* active port forwarding */ - std::list activeForwards; + /* active port forwarding */ + std::list activeForwards; }; +/* info from upnp */ +int CtrlPointCallbackEventHandler(Upnp_EventType ,void* , void*); + #endif /* _RS_UPNP_IFACE_H */ diff --git a/libretroshare/src/upnp/upnputil.c b/libretroshare/src/upnp/upnputil.c deleted file mode 100644 index 7d0f3beb8..000000000 --- a/libretroshare/src/upnp/upnputil.c +++ /dev/null @@ -1,290 +0,0 @@ - -#include "upnp/upnputil.h" - -/* protofix() checks if protocol is "UDP" or "TCP" - * returns NULL if not */ -const char * protofix(const char * proto) -{ - static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; - static const char proto_udp[4] = { 'U', 'D', 'P', 0}; - int i, b; - for(i=0, b=1; i<4; i++) - b = b && ( (proto[i] == proto_tcp[i]) - || (proto[i] == (proto_tcp[i] | 32)) ); - if(b) - return proto_tcp; - for(i=0, b=1; i<4; i++) - b = b && ( (proto[i] == proto_udp[i]) - || (proto[i] == (proto_udp[i] | 32)) ); - if(b) - return proto_udp; - return 0; -} - -void DisplayInfos(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - char externalIPAddress[16]; - char connectionType[64]; - char status[64]; - char lastconnerror[64]; - unsigned int uptime; - unsigned int brUp, brDown; - UPNP_GetConnectionTypeInfo(urls->controlURL, - data->servicetype, - connectionType); - if(connectionType[0]) - printf("Connection Type : %s\n", connectionType); - else - printf("GetConnectionTypeInfo failed.\n"); - UPNP_GetStatusInfo(urls->controlURL, data->servicetype, status, &uptime, lastconnerror); - printf("Status : %s, uptime=%u LastConnError %s\n", status, uptime, lastconnerror); - UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->servicetype_CIF, - &brDown, &brUp); - printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp); - UPNP_GetExternalIPAddress(urls->controlURL, - data->servicetype, - externalIPAddress); - if(externalIPAddress[0]) - printf("ExternalIPAddress = %s\n", externalIPAddress); - else - printf("GetExternalIPAddress failed.\n"); -} - -void GetConnectionStatus(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - unsigned int bytessent, bytesreceived, packetsreceived, packetssent; - DisplayInfos(urls, data); - bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->servicetype_CIF); - bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->servicetype_CIF); - packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->servicetype_CIF); - packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->servicetype_CIF); - printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); - printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); -} - -void ListRedirections(struct UPNPUrls * urls, - struct IGDdatas * data) -{ - int r; - int i = 0; - char index[6]; - char intClient[16]; - char intPort[6]; - char extPort[6]; - char protocol[4]; - char desc[80]; - char enabled[6]; - char rHost[64]; - char duration[16]; - /*unsigned int num=0; - UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); - printf("PortMappingNumberOfEntries : %u\n", num);*/ - do { - snprintf(index, 6, "%d", i); - rHost[0] = '\0'; enabled[0] = '\0'; - duration[0] = '\0'; desc[0] = '\0'; - extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; - r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->servicetype, - index, - extPort, intClient, intPort, - protocol, desc, enabled, - rHost, duration); - if(r==0) - printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" - " desc='%s' rHost='%s'\n", - i, protocol, extPort, intClient, intPort, - enabled, duration, - desc, rHost); - i++; - } while(r==0); -} - -/* Test function - * 1 - get connection type - * 2 - get extenal ip address - * 3 - Add port mapping - * 4 - get this port mapping from the IGD */ -bool SetRedirectAndTest(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * iaddr, - const char * iport, - const char * eport, - const char * proto) -{ - char externalIPAddress[16]; - char intClient[16]; - char intPort[6]; - char leaseDuration[] = "3600"; /* 60 mins */ - int r; - int ok = 1; - - if(!iaddr || !iport || !eport || !proto) - { - fprintf(stderr, "Wrong arguments\n"); - return 0; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "invalid protocol\n"); - return 0; - } - - UPNP_GetExternalIPAddress(urls->controlURL, - data->servicetype, - externalIPAddress); - if(externalIPAddress[0]) - printf("ExternalIPAddress = %s\n", externalIPAddress); - else - printf("GetExternalIPAddress failed.\n"); - -// Unix at the moment! -#if MINIUPNPC_VERSION >= 13 - /* Starting from miniupnpc version 1.2, lease duration parameter is gone */ - r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, - eport, iport, iaddr, 0, proto, NULL); -#else - #if MINIUPNPC_VERSION >= 12 - /* Starting from miniupnpc version 1.2, lease duration parameter is gone */ - r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, - eport, iport, iaddr, 0, proto); - #else - /* The lease parameter is also gone in minupnpc 1.0 */ - r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, - eport, iport, iaddr,0, 0, proto); - #endif -#endif - -// r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, -// eport, iport, iaddr, 0, leaseDuration, proto); - -// r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, -// eport, iport, iaddr, 0, proto); - if(r==0) - { - printf("AddPortMapping(%s, %s, %s) failed\n", eport, iport, iaddr); - //this seems to trigger for unknown reasons sometimes. - //rely on Checking it afterwards... - //should check IP address then! - //ok = 0; - } - - UPNP_GetSpecificPortMappingEntry(urls->controlURL, - data->servicetype, - eport, proto, - intClient, intPort); - if(intClient[0]) - printf("InternalIP:Port = %s:%s\n", intClient, intPort); - else - { - printf("GetSpecificPortMappingEntry failed.\n"); - ok = 0; - } - - if ((strcmp(iaddr, intClient) != 0) || (strcmp(iport, intPort) != 0)) - { - printf("PortMappingEntry to wrong location! FAILED\n"); - printf("IP1:\"%s\"\n", iaddr); - printf("IP2:\"%s\"\n", intClient); - printf("PORT1:\"%s\"\n", iport); - printf("PORT2:\"%s\"\n", intPort); - ok = 0; - } - - printf("external %s:%s is redirected to internal %s:%s\n", - externalIPAddress, eport, intClient, intPort); - - if (ok) - { - printf("uPnP Forward/Mapping Succeeded\n"); - } - else - { - printf("uPnP Forward/Mapping Failed\n"); - } - - return ok; -} - -bool TestRedirect(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * iaddr, - const char * iport, - const char * eport, - const char * proto) -{ - char intClient[16]; - char intPort[6]; - int ok = 1; - - if(!iaddr || !iport || !eport || !proto) - { - fprintf(stderr, "Wrong arguments\n"); - return 0; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "invalid protocol\n"); - return 0; - } - - UPNP_GetSpecificPortMappingEntry(urls->controlURL, - data->servicetype, - eport, proto, - intClient, intPort); - if(intClient[0]) - printf("uPnP Check: InternalIP:Port = %s:%s\n", intClient, intPort); - else - { - printf("GetSpecificPortMappingEntry failed.\n"); - ok = 0; - } - - printf("uPnP Check: External port %s is redirected to internal %s:%s\n", - eport, intClient, intPort); - - if (ok) - { - printf("uPnP Check: uPnP Forward/Mapping still Active\n"); - } - else - { - printf("uPnP Check: Forward/Mapping has been Dropped\n"); - } - - return ok; -} - - - -bool -RemoveRedirect(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * eport, - const char * proto) -{ - if(!proto || !eport) - { - fprintf(stderr, "invalid arguments\n"); - return 0; - } - proto = protofix(proto); - if(!proto) - { - fprintf(stderr, "protocol invalid\n"); - return 0; - } -#if MINIUPNPC_VERSION >= 13 - UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto, NULL); -#else - UPNP_DeletePortMapping(urls->controlURL, data->servicetype, eport, proto); -#endif - - return 1; -} - - -/* EOF */ diff --git a/libretroshare/src/upnp/upnputil.h b/libretroshare/src/upnp/upnputil.h deleted file mode 100644 index df1e14db8..000000000 --- a/libretroshare/src/upnp/upnputil.h +++ /dev/null @@ -1,55 +0,0 @@ - -#ifndef MINIUPNP_UTIL_H_ -#define MINIUPNP_UTIL_H_ - -/* $Id: upnpc.c,v 1.50 2007/04/26 19:00:10 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#include -#include -#include -#ifdef WIN32 -#include -#define snprintf _snprintf -#endif -#include -#include -#include - -/* protofix() checks if protocol is "UDP" or "TCP" - * returns NULL if not */ -const char * protofix(const char * proto); -void DisplayInfos(struct UPNPUrls * urls, - struct IGDdatas * data); - -void GetConnectionStatus(struct UPNPUrls * urls, - struct IGDdatas * data); - -void ListRedirections(struct UPNPUrls * urls, - struct IGDdatas * data); - -bool SetRedirectAndTest(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * iaddr, - const char * iport, - const char * eport, - const char * proto); - -bool TestRedirect(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * iaddr, - const char * iport, - const char * eport, - const char * proto); - -bool RemoveRedirect(struct UPNPUrls * urls, - struct IGDdatas * data, - const char * eport, - const char * proto); - -/* EOF */ -#endif diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index ae428ce1d..374d562c9 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -1,4 +1,4 @@ -CONFIG += qt gui uic qrc resources uitools debug pluginmgr newsettings #release +CONFIG += qt gui uic qrc resources uitools debug pluginmgr newsettings #release QT += network xml script TEMPLATE = app TARGET = RetroShare @@ -13,15 +13,16 @@ MOC_DIR = temp/moc # Put lib dir in QMAKE_LFLAGS so it appears before -L/usr/lib linux-g++ { OBJECTS_DIR = temp/linux-g++/obj - QMAKE_LFLAGS += -L"../../../../lib/linux-g++" - CONFIG += version_detail_bash_script - LIBS += -L"../../../../lib" -lretroshare -lssl -lcrypto -lgpgme -lpthread -lminiupnpc -lz + CONFIG += version_detail_bash_script + LIBS += ../../libretroshare/src/lib/libretroshare.a + LIBS += -lssl -lcrypto -lgpgme -lpthread -lz -lupnp } + linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj - QMAKE_LFLAGS += -L"../../../../lib/linux-g++-64" CONFIG += version_detail_bash_script - LIBS += -L"../../../../lib" -lretroshare -lssl -lcrypto -lgpgme -lpthread -lminiupnpc -lz + LIBS += ../../libretroshare/src/lib/libretroshare.a + LIBS += -lssl -lcrypto -lgpgme -lpthread -lz -lupnp } version_detail_bash_script {