/******************************************************************************* * libretroshare/src/upnp: UPnPBase.h * * * * libretroshare: retroshare core library * * * * Copyright (c) 2004-2009 Marcelo Roberto Jimenez ( phoenix@amule.org ) * * Copyright (c) 2006-2009 aMule Team ( admin@amule.org / http://www.amule.org)* * Copyright (c) 2009-2010 Retroshare Team * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see . * * * *******************************************************************************/ #include #include #include #include #include #include #include //#include #include "util/rsthreads.h" #include #include #ifdef UPNP_C std::string stdEmptyString; #else // UPNP_C extern std::string stdEmptyString; #endif // UPNP_C //#define UPNP_DEBUG 1 /** * 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 ex_port = 0, int in_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: explicit 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, const IXML_Document* doc) const; // Processing response to actions void ProcessActionResponse( const IXML_Document* RespDoc, const std::string& actionName ) const; // IXML_Element IXML_Element* Element_GetRootElement(const 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::cerr << "\n " << XML_LIST_NAME << ": " << i << " " << XML_ELEMENT_NAME << "s."; } 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, const 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: std::map propertyMap; 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); }; 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; RsMutex m_WaitForSearchTimeoutMutex; public: CUPnPService *m_WanService; std::string m_getStateVariableLastResult; static CUPnPControlPoint *s_CtrlPoint; explicit 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, const void* Event, void* Cookie ); void OnEventReceived(const std::string &Sid, int EventKey, const 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); bool PrivateGetExternalIpAdress(); }; // File_checked_for_headers