2 // This file is part of the aMule Project.
4 // Copyright (c) 2006-2008 Marcelo Roberto Jimenez ( phoenix@amule.org )
5 // Copyright (c) 2006-2008 aMule Team ( admin@amule.org / http://www.amule.org )
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
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.
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.
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
27 // This define must not conflict with the one in the standard header
37 #include "UPnPCompatibility.h"
41 std::string stdEmptyString
;
43 extern std::string stdEmptyString
;
48 * Case insensitive std::string comparison
50 bool stdStringIsEqualCI(
51 const std::string
&s1
,
52 const std::string
&s2
);
55 class CUPnPPortMapping
59 std::string m_protocol
;
60 std::string m_enabled
;
61 std::string m_description
;
67 const std::string
&protocol
= stdEmptyString
,
69 const std::string
&description
= stdEmptyString
);
70 ~CUPnPPortMapping() {}
72 const std::string
&getPort() const
74 const std::string
&getProtocol() const
75 { return m_protocol
; }
76 const std::string
&getEnabled() const
78 const std::string
&getDescription() const
79 { return m_description
; }
80 const std::string
&getKey() const
85 class CDynamicLibHandle
88 std::string m_libname
;
89 void *const m_LibraryHandle
;
90 CDynamicLibHandle(const CDynamicLibHandle
&);
91 CDynamicLibHandle
&operator=(const CDynamicLibHandle
&);
94 CDynamicLibHandle(const char *libname
);
96 void *Get() const { return m_LibraryHandle
; }
100 class CUPnPControlPoint
;
106 static const std::string
&UPNP_ROOT_DEVICE
;
107 static const std::string
&UPNP_DEVICE_IGW
;
108 static const std::string
&UPNP_DEVICE_WAN
;
109 static const std::string
&UPNP_DEVICE_WAN_CONNECTION
;
110 static const std::string
&UPNP_DEVICE_LAN
;
111 static const std::string
&UPNP_SERVICE_LAYER3_FORWARDING
;
112 static const std::string
&UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG
;
113 static const std::string
&UPNP_SERVICE_WAN_IP_CONNECTION
;
114 static const std::string
&UPNP_SERVICE_WAN_PPP_CONNECTION
;
115 CUPnPControlPoint
&m_ctrlPoint
;
119 static const int NUM_LIB_IXML_SYMBOLS
= 8;
120 static const char *s_LibIXMLSymbols
[NUM_LIB_IXML_SYMBOLS
];
121 static const int NUM_LIB_UPNP_SYMBOLS
= 17;
122 static const char *s_LibUPnPSymbols
[NUM_LIB_UPNP_SYMBOLS
];
123 CDynamicLibHandle m_LibIXMLHandle
;
124 CDynamicLibHandle m_LibUPnPHandle2
;
125 CDynamicLibHandle m_LibUPnPHandle3
;
126 CDynamicLibHandle
*m_LibUPnPHandle
;
127 const std::string
addLibraryPath(const char *name
);
130 CUPnPLib(CUPnPControlPoint
&ctrlPoint
);
133 // Convenience function so we don't have to write explicit calls
134 // to char2unicode every time
135 std::string
GetUPnPErrorMessage(int code
) const;
137 // Convenience function to avoid repetitive processing of error
139 std::string
processUPnPErrorMessage(
140 const std::string
&messsage
,
142 const DOMString errorString
,
143 IXML_Document
*doc
) const;
145 // Processing response to actions
146 void ProcessActionResponse(
147 IXML_Document
*RespDoc
,
148 const std::string
&actionName
) const;
151 IXML_Element
*Element_GetRootElement(
152 IXML_Document
*doc
) const;
153 IXML_Element
*Element_GetFirstChild(
154 IXML_Element
*parent
) const;
155 IXML_Element
*Element_GetNextSibling(
156 IXML_Element
*child
) const;
157 const DOMString
Element_GetTag(
158 IXML_Element
*element
) const;
159 const std::string
Element_GetTextValue(
160 IXML_Element
*element
) const;
161 const std::string
Element_GetChildValueByTag(
162 IXML_Element
*element
,
163 const DOMString tag
) const;
164 IXML_Element
*Element_GetFirstChildByTag(
165 IXML_Element
*element
,
166 const DOMString tag
) const;
167 IXML_Element
*Element_GetNextSiblingByTag(
168 IXML_Element
*element
,
169 const DOMString tag
) const;
170 const std::string
Element_GetAttributeByTag(
171 IXML_Element
*element
,
172 const DOMString tag
) const;
175 IXML_Node
*(*m_ixmlNode_getFirstChild
)(IXML_Node
*nodeptr
);
176 IXML_Node
*(*m_ixmlNode_getNextSibling
)(IXML_Node
*nodeptr
);
177 const DOMString (*m_ixmlNode_getNodeName
)(IXML_Node
*nodeptr
);
178 const DOMString (*m_ixmlNode_getNodeValue
)(IXML_Node
*nodeptr
);
179 IXML_NamedNodeMap
*(*m_ixmlNode_getAttributes
)(IXML_Node
*nodeptr
);
180 void (*m_ixmlDocument_free
)(IXML_Document
*doc
);
181 IXML_Node
*(*m_ixmlNamedNodeMap_getNamedItem
)(
182 IXML_NamedNodeMap
*nnMap
, const DOMString name
);
183 void (*m_ixmlNamedNodeMap_free
)(IXML_NamedNodeMap
*nnMap
);
186 // 1 - Initialization and Registration
187 int (*m_UpnpInit
)(const char *IPAddress
, int Port
);
188 void (*m_UpnpFinish
)();
189 unsigned short (*m_UpnpGetServerPort
)();
190 char *(*m_UpnpGetServerIpAddress
)();
191 int (*m_UpnpRegisterClient
)(Upnp_FunPtr Callback
,
192 const void *Cookie
, UpnpClient_Handle
*Hnd
);
193 int (*m_UpnpUnRegisterClient
)(UpnpClient_Handle Hnd
);
195 int (*m_UpnpSearchAsync
)(UpnpClient_Handle Hnd
, int Mx
,
196 const char *Target
, const void *Cookie
);
198 int (*m_UpnpGetServiceVarStatus
)(UpnpClient_Handle Hnd
, const char *ActionURL
,
199 const char *VarName
, DOMString
*StVarVal
);
200 int (*m_UpnpSendAction
)(UpnpClient_Handle Hnd
, const char *ActionURL
,
201 const char *ServiceType
, const char *DevUDN
, IXML_Document
*Action
,
202 IXML_Document
**RespNode
);
203 int (*m_UpnpSendActionAsync
)(UpnpClient_Handle Hnd
, const char *ActionURL
,
204 const char *ServiceType
, const char *DevUDN
, IXML_Document
*Action
,
205 Upnp_FunPtr Callback
, const void *Cookie
);
207 int (*m_UpnpSubscribe
)(UpnpClient_Handle Hnd
,
208 const char *PublisherUrl
, int *TimeOut
, Upnp_SID SubsId
);
209 int (*m_UpnpUnSubscribe
)(UpnpClient_Handle Hnd
, Upnp_SID SubsId
);
211 int (*m_UpnpDownloadXmlDoc
)(const char *url
, IXML_Document
**xmlDoc
);
212 // 6 - Optional Tools API
213 int (*m_UpnpResolveURL
)(const char *BaseURL
,
214 const char *RelURL
, char *AbsURL
);
215 IXML_Document
*(*m_UpnpMakeAction
)(
216 const char *ActionName
, const char *ServType
, int NumArg
,
217 const char *Arg
, ...);
218 int (*m_UpnpAddToAction
)(
219 IXML_Document
**ActionDoc
, const char *ActionName
,
220 const char *ServType
, const char *ArgName
, const char *ArgVal
);
221 const char *(*m_UpnpGetErrorMessage
)(int ErrorCode
);
225 class CUPnPControlPoint
;
228 * Even though we can retrieve the upnpLib handler from the upnpControlPoint,
229 * we must pass it separetly at this point, because the class CUPnPControlPoint
230 * must be declared after.
232 * CUPnPLib can only be removed from the constructor once we agree to link to
233 * UPnPLib explicitly, making this dlopen() stuff unnecessary.
235 template <typename T
, char const *XML_ELEMENT_NAME
, char const *XML_LIST_NAME
>
236 class CXML_List
: public std::map
<const std::string
, T
*>
240 const CUPnPControlPoint
&upnpControlPoint
,
242 IXML_Element
*parent
,
243 const std::string
&url
);
248 template <typename T
, char const *XML_ELEMENT_NAME
, char const *XML_LIST_NAME
>
249 CXML_List
<T
, XML_ELEMENT_NAME
, XML_LIST_NAME
>::CXML_List(
250 const CUPnPControlPoint
&upnpControlPoint
,
252 IXML_Element
*parent
,
253 const std::string
&url
)
255 IXML_Element
*elementList
=
256 upnpLib
.Element_GetFirstChildByTag(parent
, XML_LIST_NAME
);
258 for ( IXML_Element
*element
= upnpLib
.Element_GetFirstChildByTag(elementList
, XML_ELEMENT_NAME
);
260 element
= upnpLib
.Element_GetNextSiblingByTag(element
, XML_ELEMENT_NAME
)) {
261 // Add a new element to the element list
262 T
*upnpElement
= new T(upnpControlPoint
, upnpLib
, element
, url
);
263 (*this)[upnpElement
->GetKey()] = upnpElement
;
266 std::ostringstream msg
;
267 msg
<< "\n " << XML_LIST_NAME
<< ": " <<
268 i
<< " " << XML_ELEMENT_NAME
<< "s.";
269 AddDebugLogLineM(false, logUPnP
, msg
);
273 template <typename T
, char const *XML_ELEMENT_NAME
, char const *XML_LIST_NAME
>
274 CXML_List
<T
, XML_ELEMENT_NAME
, XML_LIST_NAME
>::~CXML_List()
276 typename CXML_List
<T
, XML_ELEMENT_NAME
, XML_LIST_NAME
>::iterator it
;
277 for(it
= this->begin(); it
!= this->end(); ++it
) {
283 char s_argument
[] = "argument";
284 char s_argumentList
[] = "argumentList";
285 char s_action
[] = "action";
286 char s_actionList
[] = "actionList";
287 char s_allowedValue
[] = "allowedValue";
288 char s_allowedValueList
[] = "allowedValueList";
289 char s_stateVariable
[] = "stateVariable";
290 char s_serviceStateTable
[] = "serviceStateTable";
291 char s_service
[] = "service";
292 char s_serviceList
[] = "serviceList";
293 char s_device
[] = "device";
294 char s_deviceList
[] = "deviceList";
296 extern char s_argument
[];
297 extern char s_argumentList
[];
298 extern char s_action
[];
299 extern char s_actionList
[];
300 extern char s_allowedValue
[];
301 extern char s_allowedValueList
[];
302 extern char s_stateVariable
[];
303 extern char s_serviceStateTable
[];
304 extern char s_service
[];
305 extern char s_serviceList
[];
306 extern char s_device
[];
307 extern char s_deviceList
[];
312 typedef CXML_List
<CUPnPArgument
, s_argument
, s_argumentList
> ArgumentList
;
314 typedef CXML_List
<CUPnPAction
, s_action
, s_actionList
> ActionList
;
315 class CUPnPStateVariable
;
316 typedef CXML_List
<CUPnPStateVariable
, s_stateVariable
, s_serviceStateTable
> ServiceStateTable
;
317 class CUPnPAllowedValue
;
318 typedef CXML_List
<CUPnPAllowedValue
, s_allowedValue
, s_allowedValueList
> AllowedValueList
;
320 typedef CXML_List
<CUPnPService
, s_service
, s_serviceList
> ServiceList
;
322 typedef CXML_List
<CUPnPDevice
, s_device
, s_deviceList
> DeviceList
;
328 IXML_Element
*m_root
;
329 const std::string m_ErrorCode
;
330 const std::string m_ErrorDescription
;
333 const CUPnPLib
&upnpLib
,
334 IXML_Document
*errorDoc
);
336 const std::string
&getErrorCode() const
337 { return m_ErrorCode
; }
338 const std::string
&getErrorDescription() const
339 { return m_ErrorDescription
; }
346 const CUPnPControlPoint
&m_UPnPControlPoint
;
347 const std::string m_name
;
348 const std::string m_direction
;
350 const std::string m_relatedStateVariable
;
354 const CUPnPControlPoint
&upnpControlPoint
,
356 IXML_Element
*argument
,
357 const std::string
&SCPDURL
);
359 const std::string
&GetName() const
361 const std::string
&GetDirection() const
362 { return m_direction
; }
363 bool GetRetVal() const
365 const std::string
&GetRelatedStateVariable() const
366 { return m_relatedStateVariable
; }
367 const std::string
&GetKey() const
376 const CUPnPControlPoint
&m_UPnPControlPoint
;
377 ArgumentList m_ArgumentList
;
378 const std::string m_name
;
382 const CUPnPControlPoint
&upnpControlPoint
,
384 IXML_Element
*action
,
385 const std::string
&SCPDURL
);
387 const std::string
&GetName() const
389 const std::string
&GetKey() const
391 const ArgumentList
&GetArgumentList() const
392 { return m_ArgumentList
; }
396 class CUPnPAllowedValue
399 const CUPnPControlPoint
&m_UPnPControlPoint
;
400 const std::string m_allowedValue
;
404 const CUPnPControlPoint
&upnpControlPoint
,
406 IXML_Element
*allowedValue
,
407 const std::string
&SCPDURL
);
408 ~CUPnPAllowedValue() {}
409 const std::string
&GetAllowedValue() const
410 { return m_allowedValue
; }
411 const std::string
&GetKey() const
412 { return m_allowedValue
; }
416 class CUPnPStateVariable
419 const CUPnPControlPoint
&m_UPnPControlPoint
;
420 AllowedValueList m_AllowedValueList
;
421 const std::string m_name
;
422 const std::string m_dataType
;
423 const std::string m_defaultValue
;
424 const std::string m_sendEvents
;
428 const CUPnPControlPoint
&upnpControlPoint
,
430 IXML_Element
*stateVariable
,
431 const std::string
&URLBase
);
432 ~CUPnPStateVariable() {}
433 const std::string
&GetNname() const
435 const std::string
&GetDataType() const
436 { return m_dataType
; }
437 const std::string
&GetDefaultValue() const
438 { return m_defaultValue
; }
439 const std::string
&GetKey() const
441 const AllowedValueList
&GetAllowedValueList() const
442 { return m_AllowedValueList
; }
449 const CUPnPControlPoint
&m_UPnPControlPoint
;
450 ActionList m_ActionList
;
451 ServiceStateTable m_ServiceStateTable
;
452 const std::string m_SCPDURL
;
456 const CUPnPControlPoint
&upnpControlPoint
,
459 const std::string
&SCPDURL
);
461 const ActionList
&GetActionList() const
462 { return m_ActionList
; }
463 const ServiceStateTable
&GetServiceStateTable() const
464 { return m_ServiceStateTable
; }
468 class CUPnPArgumentValue
471 std::string m_argument
;
475 CUPnPArgumentValue();
476 CUPnPArgumentValue(const std::string
&argument
, const std::string
&value
);
477 ~CUPnPArgumentValue() {}
479 const std::string
&GetArgument() const { return m_argument
; }
480 const std::string
&GetValue() const { return m_value
; }
481 const std::string
&SetArgument(const std::string
& argument
) { return m_argument
= argument
; }
482 const std::string
&SetValue(const std::string
&value
) { return m_value
= value
; }
489 const CUPnPControlPoint
&m_UPnPControlPoint
;
491 const std::string m_serviceType
;
492 const std::string m_serviceId
;
493 const std::string m_SCPDURL
;
494 const std::string m_controlURL
;
495 const std::string m_eventSubURL
;
496 std::string m_absSCPDURL
;
497 std::string m_absControlURL
;
498 std::string m_absEventSubURL
;
501 std::auto_ptr
<CUPnPSCPD
> m_SCPD
;
505 const CUPnPControlPoint
&upnpControlPoint
,
507 IXML_Element
*service
,
508 const std::string
&URLBase
);
511 const std::string
&GetServiceType() const
512 { return m_serviceType
; }
513 const std::string
&GetServiceId() const
514 { return m_serviceId
; }
515 const std::string
&GetSCPDURL() const
516 { return m_SCPDURL
; }
517 const std::string
&GetAbsSCPDURL() const
518 { return m_absSCPDURL
; }
519 const std::string
&GetControlURL() const
520 { return m_controlURL
; }
521 const std::string
&GetEventSubURL() const
522 { return m_eventSubURL
; }
523 const std::string
&GetAbsControlURL() const
524 { return m_absControlURL
; }
525 const std::string
&GetAbsEventSubURL() const
526 { return m_absEventSubURL
; }
527 int GetTimeout() const
528 { return m_timeout
; }
529 void SetTimeout(int t
)
531 int *GetTimeoutAddr()
532 { return &m_timeout
; }
535 void SetSID(const char *s
)
536 { memcpy(m_SID
, s
, sizeof(Upnp_SID
)); }
537 const std::string
&GetKey() const
538 { return m_serviceId
; }
539 bool IsSubscribed() const
540 { return m_SCPD
.get() != NULL
; }
541 void SetSCPD(CUPnPSCPD
*SCPD
)
542 { m_SCPD
.reset(SCPD
); }
545 const std::string
&ActionName
,
546 const std::vector
<CUPnPArgumentValue
> &ArgValue
) const;
547 const std::string
GetStateVariable(
548 const std::string
&stateVariableName
) const;
555 const CUPnPControlPoint
&m_UPnPControlPoint
;
557 // Please, lock these lists before use
558 DeviceList m_DeviceList
;
559 ServiceList m_ServiceList
;
561 const std::string m_deviceType
;
562 const std::string m_friendlyName
;
563 const std::string m_manufacturer
;
564 const std::string m_manufacturerURL
;
565 const std::string m_modelDescription
;
566 const std::string m_modelName
;
567 const std::string m_modelNumber
;
568 const std::string m_modelURL
;
569 const std::string m_serialNumber
;
570 const std::string m_UDN
;
571 const std::string m_UPC
;
572 std::string m_presentationURL
;
576 const CUPnPControlPoint
&upnpControlPoint
,
578 IXML_Element
*device
,
579 const std::string
&URLBase
);
582 const std::string
&GetUDN() const
584 const std::string
&GetDeviceType() const
585 { return m_deviceType
; }
586 const std::string
&GetFriendlyName() const
587 { return m_friendlyName
; }
588 const std::string
&GetPresentationURL() const
589 { return m_presentationURL
; }
590 const std::string
&GetKey() const
595 class CUPnPRootDevice
: public CUPnPDevice
598 const CUPnPControlPoint
&m_UPnPControlPoint
;
599 const std::string m_URLBase
;
600 const std::string m_location
;
605 const CUPnPControlPoint
&upnpControlPoint
,
607 IXML_Element
*rootDevice
,
608 const std::string
&OriginalURLBase
,
609 const std::string
&FixedURLBase
,
610 const char *location
,
612 ~CUPnPRootDevice() {}
614 const std::string
&GetURLBase() const
615 { return m_URLBase
; }
616 const std::string
&GetLocation() const
617 { return m_location
; }
618 int GetExpires() const
619 { return m_expires
; }
620 void SetExpires(int expires
)
621 { m_expires
= expires
; }
625 typedef std::map
<const std::string
, CUPnPRootDevice
*> RootDeviceMap
;
626 typedef std::map
<const std::string
, CUPnPService
*> ServiceMap
;
627 typedef std::map
<const std::string
, CUPnPPortMapping
> PortMappingMap
;
630 class CUPnPControlPoint
633 static CUPnPControlPoint
*s_CtrlPoint
;
636 UpnpClient_Handle m_UPnPClientHandle
;
637 RootDeviceMap m_RootDeviceMap
;
638 ServiceMap m_ServiceMap
;
639 PortMappingMap m_ActivePortMappingsMap
;
640 CUPnPMutex m_RootDeviceListMutex
;
641 bool m_IGWDeviceDetected
;
642 //#warning This variable is for testing purposes only and should disappear on release.
643 CUPnPService
*m_WanService
;
644 CUPnPMutex m_WaitForSearchTimeoutMutex
;
647 CUPnPControlPoint(unsigned short udpPort
);
648 ~CUPnPControlPoint();
649 void Subscribe(CUPnPService
&service
);
650 void Unsubscribe(CUPnPService
&service
);
651 bool AddPortMappings(
652 std::vector
<CUPnPPortMapping
> &upnpPortMapping
);
653 bool DeletePortMappings(
654 std::vector
<CUPnPPortMapping
> &upnpPortMapping
);
656 UpnpClient_Handle
GetUPnPClientHandle() const
657 { return m_UPnPClientHandle
; }
659 bool GetIGWDeviceDetected() const
660 { return m_IGWDeviceDetected
; }
661 void SetIGWDeviceDetected(bool b
)
662 { m_IGWDeviceDetected
= b
; }
663 bool WanServiceDetected() const
664 { return !m_ServiceMap
.empty(); }
665 void SetWanService(CUPnPService
*service
)
666 { m_WanService
= service
; }
670 Upnp_EventType EventType
,
675 void OnEventReceived(
676 const std::string
&Sid
,
678 IXML_Document
*ChangedVariables
);
680 IXML_Element
*rootDevice
,
681 const std::string
&urlBase
,
682 const char *location
,
684 void RemoveRootDevice(
686 void RefreshPortMappings();
687 bool PrivateAddPortMapping(
688 CUPnPPortMapping
&upnpPortMapping
);
689 bool PrivateDeletePortMapping(
690 CUPnPPortMapping
&upnpPortMapping
);
694 #endif /* AMULE_UPNP_H */
696 // File_checked_for_headers