1// 2// This file is part of the aMule Project. 3// 4// Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org ) 5// Copyright (c) 2006-2011 aMule Team ( admin@amule.org / http://www.amule.org ) 6// 7// Any parts of this program derived from the xMule, lMule or eMule project, 8// or contributed by third-party developers are copyrighted by their 9// respective authors. 10// 11// This program is free software; you can redistribute it and/or modify 12// it under the terms of the GNU General Public License as published by 13// the Free Software Foundation; either version 2 of the License, or 14// (at your option) any later version. 15// 16// This program is distributed in the hope that it will be useful, 17// but WITHOUT ANY WARRANTY; without even the implied warranty of 18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19// GNU General Public License for more details. 20// 21// You should have received a copy of the GNU General Public License 22// along with this program; if not, write to the Free Software 23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 24// 25 26 27// This define must not conflict with the one in the standard header 28#ifndef AMULE_UPNP_H 29#define AMULE_UPNP_H 30 31 32#include <map> 33#include <string> 34#include <sstream> 35#include <memory> 36 37#include "UPnPCompatibility.h" 38 39 40#ifdef UPNP_C 41 std::string stdEmptyString; 42#else // UPNP_C 43 extern std::string stdEmptyString; 44#endif // UPNP_C 45 46 47/** 48 * Case insensitive std::string comparison 49 */ 50bool stdStringIsEqualCI( 51 const std::string &s1, 52 const std::string &s2); 53 54 55class CUPnPPortMapping 56{ 57private: 58 std::string m_port; 59 std::string m_protocol; 60 std::string m_enabled; 61 std::string m_description; 62 std::string m_key; 63 64public: 65 CUPnPPortMapping( 66 int port = 0, 67 const std::string &protocol = stdEmptyString, 68 bool enabled = false, 69 const std::string &description = stdEmptyString); 70 ~CUPnPPortMapping() {} 71 72 const std::string &getPort() const 73 { return m_port; } 74 const std::string &getProtocol() const 75 { return m_protocol; } 76 const std::string &getEnabled() const 77 { return m_enabled; } 78 const std::string &getDescription() const 79 { return m_description; } 80 const std::string &getKey() const 81 { return m_key; } 82}; 83 84 85class CUPnPControlPoint; 86 87 88class CUPnPLib 89{ 90public: 91 static const std::string &UPNP_ROOT_DEVICE; 92 static const std::string &UPNP_DEVICE_IGW; 93 static const std::string &UPNP_DEVICE_WAN; 94 static const std::string &UPNP_DEVICE_WAN_CONNECTION; 95 static const std::string &UPNP_DEVICE_LAN; 96 static const std::string &UPNP_SERVICE_LAYER3_FORWARDING; 97 static const std::string &UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG; 98 static const std::string &UPNP_SERVICE_WAN_IP_CONNECTION; 99 static const std::string &UPNP_SERVICE_WAN_PPP_CONNECTION; 100 CUPnPControlPoint &m_ctrlPoint; 101 102public: 103 CUPnPLib(CUPnPControlPoint &ctrlPoint); 104 ~CUPnPLib() {} 105 106 // Convenience function so we don't have to write explicit calls 107 // to char2unicode every time 108 std::string GetUPnPErrorMessage(int code) const; 109 110 // Convenience function to avoid repetitive processing of error 111 // messages 112 std::string processUPnPErrorMessage( 113 const std::string &messsage, 114 int code, 115 const DOMString errorString, 116 IXML_Document *doc) const; 117 118 // Processing response to actions 119 void ProcessActionResponse( 120 IXML_Document *RespDoc, 121 const std::string &actionName) const; 122 123 // IXML_Element 124 IXML_Element *Element_GetRootElement( 125 IXML_Document *doc) const; 126 IXML_Element *Element_GetFirstChild( 127 IXML_Element *parent) const; 128 IXML_Element *Element_GetNextSibling( 129 IXML_Element *child) const; 130 const DOMString Element_GetTag( 131 IXML_Element *element) const; 132 const std::string Element_GetTextValue( 133 IXML_Element *element) const; 134 const std::string Element_GetChildValueByTag( 135 IXML_Element *element, 136 const DOMString tag) const; 137 IXML_Element *Element_GetFirstChildByTag( 138 IXML_Element *element, 139 const DOMString tag) const; 140 IXML_Element *Element_GetNextSiblingByTag( 141 IXML_Element *element, 142 const DOMString tag) const; 143 const std::string Element_GetAttributeByTag( 144 IXML_Element *element, 145 const DOMString tag) const; 146}; 147 148 149class CUPnPControlPoint; 150 151/* 152 * Even though we can retrieve the upnpLib handler from the upnpControlPoint, 153 * we must pass it separetly at this point, because the class CUPnPControlPoint 154 * must be declared after. 155 * 156 * CUPnPLib can only be removed from the constructor once we agree to link to 157 * UPnPLib explicitly, making this dlopen() stuff unnecessary. 158 */ 159template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME> 160class CXML_List : public std::map<const std::string, T *> 161{ 162public: 163 CXML_List( 164 const CUPnPControlPoint &upnpControlPoint, 165 CUPnPLib &upnpLib, 166 IXML_Element *parent, 167 const std::string &url); 168 ~CXML_List(); 169}; 170 171 172template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME> 173CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::CXML_List( 174 const CUPnPControlPoint &upnpControlPoint, 175 CUPnPLib &upnpLib, 176 IXML_Element *parent, 177 const std::string &url) 178{ 179 IXML_Element *elementList = 180 upnpLib.Element_GetFirstChildByTag(parent, XML_LIST_NAME); 181 unsigned int i = 0; 182 for ( IXML_Element *element = upnpLib.Element_GetFirstChildByTag(elementList, XML_ELEMENT_NAME); 183 element; 184 element = upnpLib.Element_GetNextSiblingByTag(element, XML_ELEMENT_NAME)) { 185 // Add a new element to the element list 186 T *upnpElement = new T(upnpControlPoint, upnpLib, element, url); 187 (*this)[upnpElement->GetKey()] = upnpElement; 188 ++i; 189 } 190 std::ostringstream msg; 191 msg << "\n " << XML_LIST_NAME << ": " << 192 i << " " << XML_ELEMENT_NAME << "s."; 193 AddDebugLogLineN(logUPnP, msg); 194} 195 196 197template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME> 198CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::~CXML_List() 199{ 200 typename CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::iterator it; 201 for(it = this->begin(); it != this->end(); ++it) { 202 delete (*it).second; 203 } 204} 205 206extern const char s_argument[]; 207extern const char s_argumentList[]; 208extern const char s_action[]; 209extern const char s_actionList[]; 210extern const char s_allowedValue[]; 211extern const char s_allowedValueList[]; 212extern const char s_stateVariable[]; 213extern const char s_serviceStateTable[]; 214extern const char s_service[]; 215extern const char s_serviceList[]; 216extern const char s_device[]; 217extern const char s_deviceList[]; 218 219#ifdef UPNP_C 220 const char s_argument[] = "argument"; 221 const char s_argumentList[] = "argumentList"; 222 const char s_action[] = "action"; 223 const char s_actionList[] = "actionList"; 224 const char s_allowedValue[] = "allowedValue"; 225 const char s_allowedValueList[] = "allowedValueList"; 226 const char s_stateVariable[] = "stateVariable"; 227 const char s_serviceStateTable[] = "serviceStateTable"; 228 const char s_service[] = "service"; 229 const char s_serviceList[] = "serviceList"; 230 const char s_device[] = "device"; 231 const char s_deviceList[] = "deviceList"; 232#endif // UPNP_C 233 234 235class CUPnPArgument; 236typedef CXML_List<CUPnPArgument, s_argument, s_argumentList> ArgumentList; 237class CUPnPAction; 238typedef CXML_List<CUPnPAction, s_action, s_actionList> ActionList; 239class CUPnPStateVariable; 240typedef CXML_List<CUPnPStateVariable, s_stateVariable, s_serviceStateTable> ServiceStateTable; 241class CUPnPAllowedValue; 242typedef CXML_List<CUPnPAllowedValue, s_allowedValue, s_allowedValueList> AllowedValueList; 243class CUPnPService; 244typedef CXML_List<CUPnPService, s_service, s_serviceList> ServiceList; 245class CUPnPDevice; 246typedef CXML_List<CUPnPDevice, s_device, s_deviceList> DeviceList; 247 248 249class CUPnPError 250{ 251private: 252 IXML_Element *m_root; 253 const std::string m_ErrorCode; 254 const std::string m_ErrorDescription; 255public: 256 CUPnPError( 257 const CUPnPLib &upnpLib, 258 IXML_Document *errorDoc); 259 ~CUPnPError() {} 260 const std::string &getErrorCode() const 261 { return m_ErrorCode; } 262 const std::string &getErrorDescription() const 263 { return m_ErrorDescription; } 264}; 265 266 267class CUPnPArgument 268{ 269private: 270 const CUPnPControlPoint &m_UPnPControlPoint; 271 const std::string m_name; 272 const std::string m_direction; 273 bool m_retval; 274 const std::string m_relatedStateVariable; 275 276public: 277 CUPnPArgument( 278 const CUPnPControlPoint &upnpControlPoint, 279 CUPnPLib &upnpLib, 280 IXML_Element *argument, 281 const std::string &SCPDURL); 282 ~CUPnPArgument() {} 283 const std::string &GetName() const 284 { return m_name; } 285 const std::string &GetDirection() const 286 { return m_direction; } 287 bool GetRetVal() const 288 { return m_retval; } 289 const std::string &GetRelatedStateVariable() const 290 { return m_relatedStateVariable; } 291 const std::string &GetKey() const 292 { return m_name; } 293}; 294 295 296 297class CUPnPAction 298{ 299private: 300 const CUPnPControlPoint &m_UPnPControlPoint; 301 ArgumentList m_ArgumentList; 302 const std::string m_name; 303 304public: 305 CUPnPAction( 306 const CUPnPControlPoint &upnpControlPoint, 307 CUPnPLib &upnpLib, 308 IXML_Element *action, 309 const std::string &SCPDURL); 310 ~CUPnPAction() {} 311 const std::string &GetName() const 312 { return m_name; } 313 const std::string &GetKey() const 314 { return m_name; } 315 const ArgumentList &GetArgumentList() const 316 { return m_ArgumentList; } 317}; 318 319 320class CUPnPAllowedValue 321{ 322private: 323 const CUPnPControlPoint &m_UPnPControlPoint; 324 const std::string m_allowedValue; 325 326public: 327 CUPnPAllowedValue( 328 const CUPnPControlPoint &upnpControlPoint, 329 CUPnPLib &upnpLib, 330 IXML_Element *allowedValue, 331 const std::string &SCPDURL); 332 ~CUPnPAllowedValue() {} 333 const std::string &GetAllowedValue() const 334 { return m_allowedValue; } 335 const std::string &GetKey() const 336 { return m_allowedValue; } 337}; 338 339 340class CUPnPStateVariable 341{ 342private: 343 const CUPnPControlPoint &m_UPnPControlPoint; 344 AllowedValueList m_AllowedValueList; 345 const std::string m_name; 346 const std::string m_dataType; 347 const std::string m_defaultValue; 348 const std::string m_sendEvents; 349 350public: 351 CUPnPStateVariable( 352 const CUPnPControlPoint &upnpControlPoint, 353 CUPnPLib &upnpLib, 354 IXML_Element *stateVariable, 355 const std::string &URLBase); 356 ~CUPnPStateVariable() {} 357 const std::string &GetNname() const 358 { return m_name; } 359 const std::string &GetDataType() const 360 { return m_dataType; } 361 const std::string &GetDefaultValue() const 362 { return m_defaultValue; } 363 const std::string &GetKey() const 364 { return m_name; } 365 const AllowedValueList &GetAllowedValueList() const 366 { return m_AllowedValueList; } 367}; 368 369 370class CUPnPSCPD 371{ 372private: 373 const CUPnPControlPoint &m_UPnPControlPoint; 374 ActionList m_ActionList; 375 ServiceStateTable m_ServiceStateTable; 376 const std::string m_SCPDURL; 377 378public: 379 CUPnPSCPD( 380 const CUPnPControlPoint &upnpControlPoint, 381 CUPnPLib &upnpLib, 382 IXML_Element *scpd, 383 const std::string &SCPDURL); 384 ~CUPnPSCPD() {} 385 const ActionList &GetActionList() const 386 { return m_ActionList; } 387 const ServiceStateTable &GetServiceStateTable() const 388 { return m_ServiceStateTable; } 389}; 390 391 392class CUPnPArgumentValue 393{ 394private: 395 std::string m_argument; 396 std::string m_value; 397 398public: 399 CUPnPArgumentValue(); 400 CUPnPArgumentValue(const std::string &argument, const std::string &value); 401 ~CUPnPArgumentValue() {} 402 403 const std::string &GetArgument() const { return m_argument; } 404 const std::string &GetValue() const { return m_value; } 405 const std::string &SetArgument(const std::string& argument) { return m_argument = argument; } 406 const std::string &SetValue(const std::string &value) { return m_value = value; } 407}; 408 409 410class CUPnPService 411{ 412private: 413 const CUPnPControlPoint &m_UPnPControlPoint; 414 CUPnPLib &m_upnpLib; 415 const std::string m_serviceType; 416 const std::string m_serviceId; 417 const std::string m_SCPDURL; 418 const std::string m_controlURL; 419 const std::string m_eventSubURL; 420 std::string m_absSCPDURL; 421 std::string m_absControlURL; 422 std::string m_absEventSubURL; 423 int m_timeout; 424 Upnp_SID m_SID; 425 std::auto_ptr<CUPnPSCPD> m_SCPD; 426 427public: 428 CUPnPService( 429 const CUPnPControlPoint &upnpControlPoint, 430 CUPnPLib &upnpLib, 431 IXML_Element *service, 432 const std::string &URLBase); 433 ~CUPnPService(); 434 435 const std::string &GetServiceType() const 436 { return m_serviceType; } 437 const std::string &GetServiceId() const 438 { return m_serviceId; } 439 const std::string &GetSCPDURL() const 440 { return m_SCPDURL; } 441 const std::string &GetAbsSCPDURL() const 442 { return m_absSCPDURL; } 443 const std::string &GetControlURL() const 444 { return m_controlURL; } 445 const std::string &GetEventSubURL() const 446 { return m_eventSubURL; } 447 const std::string &GetAbsControlURL() const 448 { return m_absControlURL; } 449 const std::string &GetAbsEventSubURL() const 450 { return m_absEventSubURL; } 451 int GetTimeout() const 452 { return m_timeout; } 453 void SetTimeout(int t) 454 { m_timeout = t; } 455 int *GetTimeoutAddr() 456 { return &m_timeout; } 457 char *GetSID() 458 { return m_SID; } 459 void SetSID(const char *s) 460 { memcpy(m_SID, s, sizeof(Upnp_SID)); } 461 const std::string &GetKey() const 462 { return m_serviceId; } 463 bool IsSubscribed() const 464 { return m_SCPD.get() != NULL; } 465 void SetSCPD(CUPnPSCPD *SCPD) 466 { m_SCPD.reset(SCPD); } 467 468 bool Execute( 469 const std::string &ActionName, 470 const std::vector<CUPnPArgumentValue> &ArgValue) const; 471 const std::string GetStateVariable( 472 const std::string &stateVariableName) const; 473}; 474 475 476class CUPnPDevice 477{ 478private: 479 const CUPnPControlPoint &m_UPnPControlPoint; 480 481 // Please, lock these lists before use 482 DeviceList m_DeviceList; 483 ServiceList m_ServiceList; 484 485 const std::string m_deviceType; 486 const std::string m_friendlyName; 487 const std::string m_manufacturer; 488 const std::string m_manufacturerURL; 489 const std::string m_modelDescription; 490 const std::string m_modelName; 491 const std::string m_modelNumber; 492 const std::string m_modelURL; 493 const std::string m_serialNumber; 494 const std::string m_UDN; 495 const std::string m_UPC; 496 std::string m_presentationURL; 497 498public: 499 CUPnPDevice( 500 const CUPnPControlPoint &upnpControlPoint, 501 CUPnPLib &upnpLib, 502 IXML_Element *device, 503 const std::string &URLBase); 504 ~CUPnPDevice() {} 505 506 const std::string &GetUDN() const 507 { return m_UDN; } 508 const std::string &GetDeviceType() const 509 { return m_deviceType; } 510 const std::string &GetFriendlyName() const 511 { return m_friendlyName; } 512 const std::string &GetPresentationURL() const 513 { return m_presentationURL; } 514 const std::string &GetKey() const 515 { return m_UDN; } 516}; 517 518 519class CUPnPRootDevice : public CUPnPDevice 520{ 521private: 522 const CUPnPControlPoint &m_UPnPControlPoint; 523 const std::string m_URLBase; 524 const std::string m_location; 525 int m_expires; 526 527public: 528 CUPnPRootDevice( 529 const CUPnPControlPoint &upnpControlPoint, 530 CUPnPLib &upnpLib, 531 IXML_Element *rootDevice, 532 const std::string &OriginalURLBase, 533 const std::string &FixedURLBase, 534 const char *location, 535 int expires); 536 ~CUPnPRootDevice() {} 537 538 const std::string &GetURLBase() const 539 { return m_URLBase; } 540 const std::string &GetLocation() const 541 { return m_location; } 542 int GetExpires() const 543 { return m_expires; } 544 void SetExpires(int expires) 545 { m_expires = expires; } 546}; 547 548 549typedef std::map<const std::string, CUPnPRootDevice *> RootDeviceMap; 550typedef std::map<const std::string, CUPnPService *> ServiceMap; 551typedef std::map<const std::string, CUPnPPortMapping> PortMappingMap; 552 553 554class CUPnPControlPoint 555{ 556private: 557 static CUPnPControlPoint *s_CtrlPoint; 558 // upnp stuff 559 CUPnPLib m_upnpLib; 560 UpnpClient_Handle m_UPnPClientHandle; 561 RootDeviceMap m_RootDeviceMap; 562 ServiceMap m_ServiceMap; 563 PortMappingMap m_ActivePortMappingsMap; 564 CUPnPMutex m_RootDeviceListMutex; 565 bool m_IGWDeviceDetected; 566//#warning This variable is for testing purposes only and should disappear on release. 567 CUPnPService *m_WanService; 568 CUPnPMutex m_WaitForSearchTimeoutMutex; 569 570public: 571 CUPnPControlPoint(unsigned short udpPort); 572 ~CUPnPControlPoint(); 573 void Subscribe(CUPnPService &service); 574 void Unsubscribe(CUPnPService &service); 575 bool AddPortMappings( 576 std::vector<CUPnPPortMapping> &upnpPortMapping); 577 bool DeletePortMappings( 578 std::vector<CUPnPPortMapping> &upnpPortMapping); 579 580 UpnpClient_Handle GetUPnPClientHandle() const 581 { return m_UPnPClientHandle; } 582 583 bool GetIGWDeviceDetected() const 584 { return m_IGWDeviceDetected; } 585 void SetIGWDeviceDetected(bool b) 586 { m_IGWDeviceDetected = b; } 587 bool WanServiceDetected() const 588 { return !m_ServiceMap.empty(); } 589 void SetWanService(CUPnPService *service) 590 { m_WanService = service; } 591 592 // Callback function 593 static int Callback( 594 Upnp_EventType EventType, 595 void* Event, 596 void* Cookie); 597 598private: 599 void OnEventReceived( 600 const std::string &Sid, 601 int EventKey, 602 IXML_Document *ChangedVariables); 603 void AddRootDevice( 604 IXML_Element *rootDevice, 605 const std::string &urlBase, 606 const char *location, 607 int expires); 608 void RemoveRootDevice( 609 const char *udn); 610 void RefreshPortMappings(); 611 bool PrivateAddPortMapping( 612 CUPnPPortMapping &upnpPortMapping); 613 bool PrivateDeletePortMapping( 614 CUPnPPortMapping &upnpPortMapping); 615}; 616 617 618#endif /* AMULE_UPNP_H */ 619 620// File_checked_for_headers 621