2 // This file is part of the aMule Project.
4 // Copyright (c) 2004-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
31 #include <dlfcn.h> // For dlopen(), dlsym(), dlclose()
32 #include <algorithm> // For transform()
37 #define REINTERPRET_CAST(x) reinterpret_cast<x>
40 #ifndef REINTERPRET_CAST
41 // Let's hope that function pointers are equal in size to data pointers
42 #define REINTERPRET_CAST(x) (x)
47 * Case insensitive std::string comparison
49 bool stdStringIsEqualCI(const std::string
&s1
, const std::string
&s2
)
53 std::transform(ns1
.begin(), ns1
.end(), ns1
.begin(), tolower
);
54 std::transform(ns2
.begin(), ns2
.end(), ns2
.begin(), tolower
);
59 CUPnPPortMapping::CUPnPPortMapping(
61 const std::string
&protocol
,
63 const std::string
&description
)
67 m_enabled(enabled
? "1" : "0"),
68 m_description(description
),
71 std::ostringstream oss
;
74 m_key
= m_protocol
+ m_port
;
78 const std::string
&CUPnPLib::UPNP_ROOT_DEVICE
=
81 const std::string
&CUPnPLib::UPNP_DEVICE_IGW
=
82 "urn:schemas-upnp-org:device:InternetGatewayDevice:1";
83 const std::string
&CUPnPLib::UPNP_DEVICE_WAN
=
84 "urn:schemas-upnp-org:device:WANDevice:1";
85 const std::string
&CUPnPLib::UPNP_DEVICE_WAN_CONNECTION
=
86 "urn:schemas-upnp-org:device:WANConnectionDevice:1";
87 const std::string
&CUPnPLib::UPNP_DEVICE_LAN
=
88 "urn:schemas-upnp-org:device:LANDevice:1";
90 const std::string
&CUPnPLib::UPNP_SERVICE_LAYER3_FORWARDING
=
91 "urn:schemas-upnp-org:service:Layer3Forwarding:1";
92 const std::string
&CUPnPLib::UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG
=
93 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1";
94 const std::string
&CUPnPLib::UPNP_SERVICE_WAN_IP_CONNECTION
=
95 "urn:schemas-upnp-org:service:WANIPConnection:1";
96 const std::string
&CUPnPLib::UPNP_SERVICE_WAN_PPP_CONNECTION
=
97 "urn:schemas-upnp-org:service:WANPPPConnection:1";
100 CUPnPLib::CUPnPLib(CUPnPControlPoint
&ctrlPoint
)
102 m_ctrlPoint(ctrlPoint
)
107 std::string
CUPnPLib::GetUPnPErrorMessage(int code
) const
109 return UpnpGetErrorMessage(code
);
113 std::string
CUPnPLib::processUPnPErrorMessage(
114 const std::string
&messsage
,
116 const DOMString errorString
,
117 IXML_Document
*doc
) const
119 std::ostringstream msg
;
120 if (errorString
== NULL
|| *errorString
== 0) {
121 errorString
= "Not available";
128 CUPnPError
e(*this, doc
);
129 msg
<< e
.getErrorCode() <<
130 "', Error description :'" <<
131 e
.getErrorDescription() <<
135 "', Error description :'" <<
139 AddLogLineM(false, logUPnP
, msg
);
143 ": UPnP SDK error: " <<
144 GetUPnPErrorMessage(errorCode
) <<
145 " (" << errorCode
<< ").";
146 AddLogLineM(false, logUPnP
, msg
);
153 void CUPnPLib::ProcessActionResponse(
154 IXML_Document
*RespDoc
,
155 const std::string
&actionName
) const
157 std::ostringstream msg
;
159 IXML_Element
*root
= Element_GetRootElement(RespDoc
);
160 IXML_Element
*child
= Element_GetFirstChild(root
);
163 const DOMString childTag
= Element_GetTag(child
);
164 std::string childValue
= Element_GetTextValue(child
);
168 child
= Element_GetNextSibling(child
);
171 msg
<< "\n Empty response for action '" <<
174 AddDebugLogLineM(false, logUPnP
, msg
);
179 * \brief Returns the root node of a given document.
181 IXML_Element
*CUPnPLib::Element_GetRootElement(
182 IXML_Document
*doc
) const
184 IXML_Element
*root
= REINTERPRET_CAST(IXML_Element
*)(
185 ixmlNode_getFirstChild(
186 REINTERPRET_CAST(IXML_Node
*)(doc
)));
193 * \brief Returns the first child of a given element.
195 IXML_Element
*CUPnPLib::Element_GetFirstChild(
196 IXML_Element
*parent
) const
198 IXML_Node
*node
= REINTERPRET_CAST(IXML_Node
*)(parent
);
199 IXML_Node
*child
= ixmlNode_getFirstChild(node
);
201 return REINTERPRET_CAST(IXML_Element
*)(child
);
206 * \brief Returns the next sibling of a given child.
208 IXML_Element
*CUPnPLib::Element_GetNextSibling(
209 IXML_Element
*child
) const
211 IXML_Node
*node
= REINTERPRET_CAST(IXML_Node
*)(child
);
212 IXML_Node
*sibling
= ixmlNode_getNextSibling(node
);
214 return REINTERPRET_CAST(IXML_Element
*)(sibling
);
219 * \brief Returns the element tag (name)
221 const DOMString
CUPnPLib::Element_GetTag(
222 IXML_Element
*element
) const
224 IXML_Node
*node
= REINTERPRET_CAST(IXML_Node
*)(element
);
225 const DOMString tag
= ixmlNode_getNodeName(node
);
232 * \brief Returns the TEXT node value of the current node.
234 const std::string
CUPnPLib::Element_GetTextValue(
235 IXML_Element
*element
) const
238 return stdEmptyString
;
240 IXML_Node
*text
= ixmlNode_getFirstChild(
241 REINTERPRET_CAST(IXML_Node
*)(element
));
242 const DOMString s
= ixmlNode_getNodeValue(text
);
253 * \brief Returns the TEXT node value of the first child matching tag.
255 const std::string
CUPnPLib::Element_GetChildValueByTag(
256 IXML_Element
*element
,
257 const DOMString tag
) const
259 IXML_Element
*child
=
260 Element_GetFirstChildByTag(element
, tag
);
262 return Element_GetTextValue(child
);
267 * \brief Returns the first child element that matches the requested tag or
270 IXML_Element
*CUPnPLib::Element_GetFirstChildByTag(
271 IXML_Element
*element
,
272 const DOMString tag
) const
274 if (!element
|| !tag
) {
278 IXML_Node
*node
= REINTERPRET_CAST(IXML_Node
*)(element
);
279 IXML_Node
*child
= ixmlNode_getFirstChild(node
);
280 const DOMString childTag
= ixmlNode_getNodeName(child
);
281 while(child
&& childTag
&& strcmp(tag
, childTag
)) {
282 child
= ixmlNode_getNextSibling(child
);
283 childTag
= ixmlNode_getNodeName(child
);
286 return REINTERPRET_CAST(IXML_Element
*)(child
);
291 * \brief Returns the next sibling element that matches the requested tag. Should be
292 * used with the return value of Element_GetFirstChildByTag().
294 IXML_Element
*CUPnPLib::Element_GetNextSiblingByTag(
295 IXML_Element
*element
, const DOMString tag
) const
297 if (!element
|| !tag
) {
301 IXML_Node
*child
= REINTERPRET_CAST(IXML_Node
*)(element
);
302 const DOMString childTag
= NULL
;
304 child
= ixmlNode_getNextSibling(child
);
305 childTag
= ixmlNode_getNodeName(child
);
306 } while(child
&& childTag
&& strcmp(tag
, childTag
));
308 return REINTERPRET_CAST(IXML_Element
*)(child
);
312 const std::string
CUPnPLib::Element_GetAttributeByTag(
313 IXML_Element
*element
, const DOMString tag
) const
315 IXML_NamedNodeMap
*NamedNodeMap
= ixmlNode_getAttributes(
316 REINTERPRET_CAST(IXML_Node
*)(element
));
317 IXML_Node
*attribute
= ixmlNamedNodeMap_getNamedItem(NamedNodeMap
, tag
);
318 const DOMString s
= ixmlNode_getNodeValue(attribute
);
323 ixmlNamedNodeMap_free(NamedNodeMap
);
329 CUPnPError::CUPnPError(
330 const CUPnPLib
&upnpLib
,
331 IXML_Document
*errorDoc
)
333 m_root (upnpLib
.Element_GetRootElement(errorDoc
)),
334 m_ErrorCode (upnpLib
.Element_GetChildValueByTag(m_root
, "errorCode")),
335 m_ErrorDescription(upnpLib
.Element_GetChildValueByTag(m_root
, "errorDescription"))
340 CUPnPArgument::CUPnPArgument(
341 const CUPnPControlPoint
&upnpControlPoint
,
343 IXML_Element
*argument
,
344 const std::string
&WXUNUSED(SCPDURL
))
346 m_UPnPControlPoint(upnpControlPoint
),
347 m_name (upnpLib
.Element_GetChildValueByTag(argument
, "name")),
348 m_direction (upnpLib
.Element_GetChildValueByTag(argument
, "direction")),
349 m_retval (upnpLib
.Element_GetFirstChildByTag(argument
, "retval")),
350 m_relatedStateVariable(upnpLib
.Element_GetChildValueByTag(argument
, "relatedStateVariable"))
352 std::ostringstream msg
;
353 msg
<< "\n Argument:" <<
354 "\n name: " << m_name
<<
355 "\n direction: " << m_direction
<<
356 "\n retval: " << m_retval
<<
357 "\n relatedStateVariable: " << m_relatedStateVariable
;
358 AddDebugLogLineM(false, logUPnP
, msg
);
362 CUPnPAction::CUPnPAction(
363 const CUPnPControlPoint
&upnpControlPoint
,
365 IXML_Element
*action
,
366 const std::string
&SCPDURL
)
368 m_UPnPControlPoint(upnpControlPoint
),
369 m_ArgumentList(upnpControlPoint
, upnpLib
, action
, SCPDURL
),
370 m_name(upnpLib
.Element_GetChildValueByTag(action
, "name"))
372 std::ostringstream msg
;
373 msg
<< "\n Action:" <<
374 "\n name: " << m_name
;
375 AddDebugLogLineM(false, logUPnP
, msg
);
379 CUPnPAllowedValue::CUPnPAllowedValue(
380 const CUPnPControlPoint
&upnpControlPoint
,
382 IXML_Element
*allowedValue
,
383 const std::string
&WXUNUSED(SCPDURL
))
385 m_UPnPControlPoint(upnpControlPoint
),
386 m_allowedValue(upnpLib
.Element_GetTextValue(allowedValue
))
388 std::ostringstream msg
;
389 msg
<< "\n AllowedValue:" <<
390 "\n allowedValue: " << m_allowedValue
;
391 AddDebugLogLineM(false, logUPnP
, msg
);
395 CUPnPStateVariable::CUPnPStateVariable(
396 const CUPnPControlPoint
&upnpControlPoint
,
398 IXML_Element
*stateVariable
,
399 const std::string
&SCPDURL
)
401 m_UPnPControlPoint(upnpControlPoint
),
402 m_AllowedValueList(upnpControlPoint
, upnpLib
, stateVariable
, SCPDURL
),
403 m_name (upnpLib
.Element_GetChildValueByTag(stateVariable
, "name")),
404 m_dataType (upnpLib
.Element_GetChildValueByTag(stateVariable
, "dataType")),
405 m_defaultValue(upnpLib
.Element_GetChildValueByTag(stateVariable
, "defaultValue")),
406 m_sendEvents (upnpLib
.Element_GetAttributeByTag (stateVariable
, "sendEvents"))
408 std::ostringstream msg
;
409 msg
<< "\n StateVariable:" <<
410 "\n name: " << m_name
<<
411 "\n dataType: " << m_dataType
<<
412 "\n defaultValue: " << m_defaultValue
<<
413 "\n sendEvents: " << m_sendEvents
;
414 AddDebugLogLineM(false, logUPnP
, msg
);
418 CUPnPSCPD::CUPnPSCPD(
419 const CUPnPControlPoint
&upnpControlPoint
,
422 const std::string
&SCPDURL
)
424 m_UPnPControlPoint(upnpControlPoint
),
425 m_ActionList(upnpControlPoint
, upnpLib
, scpd
, SCPDURL
),
426 m_ServiceStateTable(upnpControlPoint
, upnpLib
, scpd
, SCPDURL
),
432 CUPnPArgumentValue::CUPnPArgumentValue()
440 CUPnPArgumentValue::CUPnPArgumentValue(
441 const std::string
&argument
, const std::string
&value
)
443 m_argument(argument
),
449 CUPnPService::CUPnPService(
450 const CUPnPControlPoint
&upnpControlPoint
,
452 IXML_Element
*service
,
453 const std::string
&URLBase
)
455 m_UPnPControlPoint(upnpControlPoint
),
457 m_serviceType(upnpLib
.Element_GetChildValueByTag(service
, "serviceType")),
458 m_serviceId (upnpLib
.Element_GetChildValueByTag(service
, "serviceId")),
459 m_SCPDURL (upnpLib
.Element_GetChildValueByTag(service
, "SCPDURL")),
460 m_controlURL (upnpLib
.Element_GetChildValueByTag(service
, "controlURL")),
461 m_eventSubURL(upnpLib
.Element_GetChildValueByTag(service
, "eventSubURL")),
465 std::ostringstream msg
;
468 std::vector
<char> vscpdURL(URLBase
.length() + m_SCPDURL
.length() + 1);
469 char *scpdURL
= &vscpdURL
[0];
470 errcode
= UpnpResolveURL(
474 if( errcode
!= UPNP_E_SUCCESS
) {
475 msg
<< "Error generating scpdURL from " <<
476 "|" << URLBase
<< "|" <<
478 AddDebugLogLineM(false, logUPnP
, msg
);
480 m_absSCPDURL
= scpdURL
;
483 std::vector
<char> vcontrolURL(
484 URLBase
.length() + m_controlURL
.length() + 1);
485 char *controlURL
= &vcontrolURL
[0];
486 errcode
= UpnpResolveURL(
488 m_controlURL
.c_str(),
490 if( errcode
!= UPNP_E_SUCCESS
) {
491 msg
<< "Error generating controlURL from " <<
492 "|" << URLBase
<< "|" <<
493 m_controlURL
<< "|.";
494 AddDebugLogLineM(false, logUPnP
, msg
);
496 m_absControlURL
= controlURL
;
499 std::vector
<char> veventURL(
500 URLBase
.length() + m_eventSubURL
.length() + 1);
501 char *eventURL
= &veventURL
[0];
502 errcode
= UpnpResolveURL(
504 m_eventSubURL
.c_str(),
506 if( errcode
!= UPNP_E_SUCCESS
) {
507 msg
<< "Error generating eventURL from " <<
508 "|" << URLBase
<< "|" <<
509 m_eventSubURL
<< "|.";
510 AddDebugLogLineM(false, logUPnP
, msg
);
512 m_absEventSubURL
= eventURL
;
515 msg
<< "\n Service:" <<
516 "\n serviceType: " << m_serviceType
<<
517 "\n serviceId: " << m_serviceId
<<
518 "\n SCPDURL: " << m_SCPDURL
<<
519 "\n absSCPDURL: " << m_absSCPDURL
<<
520 "\n controlURL: " << m_controlURL
<<
521 "\n absControlURL: " << m_absControlURL
<<
522 "\n eventSubURL: " << m_eventSubURL
<<
523 "\n absEventSubURL: " << m_absEventSubURL
;
524 AddDebugLogLineM(false, logUPnP
, msg
);
526 if (m_serviceType
== upnpLib
.UPNP_SERVICE_WAN_IP_CONNECTION
||
527 m_serviceType
== upnpLib
.UPNP_SERVICE_WAN_PPP_CONNECTION
||
528 m_serviceType
== upnpLib
.UPNP_SERVICE_WAN_COMMON_INTERFACE_CONFIG
||
529 m_serviceType
== upnpLib
.UPNP_SERVICE_LAYER3_FORWARDING
) {
530 //#warning Delete this code on release.
531 //if (!upnpLib.m_ctrlPoint.WanServiceDetected()) {
532 // This condition can be used to suspend the parse
534 //#warning Delete this code when m_WanService is no longer used.
535 upnpLib
.m_ctrlPoint
.SetWanService(this);
538 msg
<< "WAN Service Detected: '" <<
539 m_serviceType
<< "'.";
540 AddDebugLogLineM(true, logUPnP
, msg
);
542 upnpLib
.m_ctrlPoint
.Subscribe(*this);
543 //#warning Delete this code on release.
547 msg
<< "WAN service detected again: '" <<
549 "'. Will only use the first instance.";
550 AddDebugLogLineM(true, logUPnP
, msg
);
555 msg
<< "Uninteresting service detected: '" <<
556 m_serviceType
<< "'. Ignoring.";
557 AddDebugLogLineM(true, logUPnP
, msg
);
562 CUPnPService::~CUPnPService()
567 bool CUPnPService::Execute(
568 const std::string
&ActionName
,
569 const std::vector
<CUPnPArgumentValue
> &ArgValue
) const
571 std::ostringstream msg
;
572 std::ostringstream
msgAction("Sending action ");
573 // Check for correct action name
574 ActionList::const_iterator itAction
=
575 m_SCPD
->GetActionList().find(ActionName
);
576 if (itAction
== m_SCPD
->GetActionList().end()) {
577 msg
<< "Invalid action name '" << ActionName
<<
578 "' for service '" << GetServiceType() << "'.";
579 AddDebugLogLineM(false, logUPnP
, msg
);
582 msgAction
<< ActionName
<< "(";
583 bool firstTime
= true;
584 // Check for correct Argument/Value pairs
585 const CUPnPAction
&action
= *(itAction
->second
);
586 for (unsigned int i
= 0; i
< ArgValue
.size(); ++i
) {
587 ArgumentList::const_iterator itArg
=
588 action
.GetArgumentList().find(ArgValue
[i
].GetArgument());
589 if (itArg
== action
.GetArgumentList().end()) {
590 msg
<< "Invalid argument name '" << ArgValue
[i
].GetArgument() <<
591 "' for action '" << action
.GetName() <<
592 "' for service '" << GetServiceType() << "'.";
593 AddDebugLogLineM(false, logUPnP
, msg
);
596 const CUPnPArgument
&argument
= *(itArg
->second
);
597 if (tolower(argument
.GetDirection()[0]) != 'i' ||
598 tolower(argument
.GetDirection()[1]) != 'n') {
599 msg
<< "Invalid direction for argument '" <<
600 ArgValue
[i
].GetArgument() <<
601 "' for action '" << action
.GetName() <<
602 "' for service '" << GetServiceType() << "'.";
603 AddDebugLogLineM(false, logUPnP
, msg
);
606 const std::string relatedStateVariableName
=
607 argument
.GetRelatedStateVariable();
608 if (!relatedStateVariableName
.empty()) {
609 ServiceStateTable::const_iterator itSVT
=
610 m_SCPD
->GetServiceStateTable().
611 find(relatedStateVariableName
);
612 if (itSVT
== m_SCPD
->GetServiceStateTable().end()) {
613 msg
<< "Inconsistent Service State Table, did not find '" <<
614 relatedStateVariableName
<<
615 "' for argument '" << argument
.GetName() <<
616 "' for action '" << action
.GetName() <<
617 "' for service '" << GetServiceType() << "'.";
618 AddDebugLogLineM(false, logUPnP
, msg
);
621 const CUPnPStateVariable
&stateVariable
= *(itSVT
->second
);
622 if ( !stateVariable
.GetAllowedValueList().empty() &&
623 stateVariable
.GetAllowedValueList().find(ArgValue
[i
].GetValue()) ==
624 stateVariable
.GetAllowedValueList().end()) {
625 msg
<< "Value not allowed '" << ArgValue
[i
].GetValue() <<
626 "' for state variable '" << relatedStateVariableName
<<
627 "' for argument '" << argument
.GetName() <<
628 "' for action '" << action
.GetName() <<
629 "' for service '" << GetServiceType() << "'.";
630 AddDebugLogLineM(false, logUPnP
, msg
);
640 ArgValue
[i
].GetArgument() <<
642 ArgValue
[i
].GetValue() <<
646 AddDebugLogLineM(false, logUPnP
, msgAction
);
647 // Everything is ok, make the action
648 IXML_Document
*ActionDoc
= NULL
;
649 if (ArgValue
.size()) {
650 for (unsigned int i
= 0; i
< ArgValue
.size(); ++i
) {
651 int ret
= UpnpAddToAction(
653 action
.GetName().c_str(),
654 GetServiceType().c_str(),
655 ArgValue
[i
].GetArgument().c_str(),
656 ArgValue
[i
].GetValue().c_str());
657 if (ret
!= UPNP_E_SUCCESS
) {
658 m_upnpLib
.processUPnPErrorMessage(
659 "UpnpAddToAction", ret
, NULL
, NULL
);
664 ActionDoc
= UpnpMakeAction(
665 action
.GetName().c_str(),
666 GetServiceType().c_str(),
669 msg
<< "Error: UpnpMakeAction returned NULL.";
670 AddLogLineM(false, logUPnP
, msg
);
675 // Send the action asynchronously
677 m_UPnPControlPoint
.GetUPnPClientHandle(),
678 GetAbsControlURL().c_str(),
679 GetServiceType().c_str(),
681 static_cast<Upnp_FunPtr
>(&CUPnPControlPoint::Callback
),
686 // Send the action synchronously
687 IXML_Document
*RespDoc
= NULL
;
688 int ret
= UpnpSendAction(
689 m_UPnPControlPoint
.GetUPnPClientHandle(),
690 GetAbsControlURL().c_str(),
691 GetServiceType().c_str(),
692 NULL
, ActionDoc
, &RespDoc
);
693 if (ret
!= UPNP_E_SUCCESS
) {
694 m_upnpLib
.processUPnPErrorMessage(
695 "UpnpSendAction", ret
, NULL
, RespDoc
);
696 ixmlDocument_free(ActionDoc
);
697 ixmlDocument_free(RespDoc
);
700 ixmlDocument_free(ActionDoc
);
702 // Check the response document
703 m_upnpLib
.ProcessActionResponse(
704 RespDoc
, action
.GetName());
706 // Free the response document
707 ixmlDocument_free(RespDoc
);
713 const std::string
CUPnPService::GetStateVariable(
714 const std::string
&stateVariableName
) const
716 std::ostringstream msg
;
718 int ret
= UpnpGetServiceVarStatus(
719 m_UPnPControlPoint
.GetUPnPClientHandle(),
720 GetAbsControlURL().c_str(),
721 stateVariableName
.c_str(),
723 if (ret
!= UPNP_E_SUCCESS
) {
724 msg
<< "GetStateVariable(\"" <<
726 "\"): in a call to UpnpGetServiceVarStatus";
727 m_upnpLib
.processUPnPErrorMessage(
728 msg
.str(), ret
, StVarVal
, NULL
);
729 return stdEmptyString
;
731 msg
<< "GetStateVariable: " <<
736 AddDebugLogLineM(false, logUPnP
, msg
);
737 return stdEmptyString
;
741 CUPnPDevice::CUPnPDevice(
742 const CUPnPControlPoint
&upnpControlPoint
,
744 IXML_Element
*device
,
745 const std::string
&URLBase
)
747 m_UPnPControlPoint(upnpControlPoint
),
748 m_DeviceList(upnpControlPoint
, upnpLib
, device
, URLBase
),
749 m_ServiceList(upnpControlPoint
, upnpLib
, device
, URLBase
),
750 m_deviceType (upnpLib
.Element_GetChildValueByTag(device
, "deviceType")),
751 m_friendlyName (upnpLib
.Element_GetChildValueByTag(device
, "friendlyName")),
752 m_manufacturer (upnpLib
.Element_GetChildValueByTag(device
, "manufacturer")),
753 m_manufacturerURL (upnpLib
.Element_GetChildValueByTag(device
, "manufacturerURL")),
754 m_modelDescription (upnpLib
.Element_GetChildValueByTag(device
, "modelDescription")),
755 m_modelName (upnpLib
.Element_GetChildValueByTag(device
, "modelName")),
756 m_modelNumber (upnpLib
.Element_GetChildValueByTag(device
, "modelNumber")),
757 m_modelURL (upnpLib
.Element_GetChildValueByTag(device
, "modelURL")),
758 m_serialNumber (upnpLib
.Element_GetChildValueByTag(device
, "serialNumber")),
759 m_UDN (upnpLib
.Element_GetChildValueByTag(device
, "UDN")),
760 m_UPC (upnpLib
.Element_GetChildValueByTag(device
, "UPC")),
761 m_presentationURL (upnpLib
.Element_GetChildValueByTag(device
, "presentationURL"))
763 std::ostringstream msg
;
764 int presURLlen
= strlen(URLBase
.c_str()) +
765 strlen(m_presentationURL
.c_str()) + 2;
766 std::vector
<char> vpresURL(presURLlen
);
767 char* presURL
= &vpresURL
[0];
768 int errcode
= UpnpResolveURL(
770 m_presentationURL
.c_str(),
772 if (errcode
!= UPNP_E_SUCCESS
) {
773 msg
<< "Error generating presentationURL from " <<
774 "|" << URLBase
<< "|" <<
775 m_presentationURL
<< "|.";
776 AddDebugLogLineM(false, logUPnP
, msg
);
778 m_presentationURL
= presURL
;
782 msg
<< "\n Device: " <<
783 "\n friendlyName: " << m_friendlyName
<<
784 "\n deviceType: " << m_deviceType
<<
785 "\n manufacturer: " << m_manufacturer
<<
786 "\n manufacturerURL: " << m_manufacturerURL
<<
787 "\n modelDescription: " << m_modelDescription
<<
788 "\n modelName: " << m_modelName
<<
789 "\n modelNumber: " << m_modelNumber
<<
790 "\n modelURL: " << m_modelURL
<<
791 "\n serialNumber: " << m_serialNumber
<<
792 "\n UDN: " << m_UDN
<<
793 "\n UPC: " << m_UPC
<<
794 "\n presentationURL: " << m_presentationURL
;
795 AddDebugLogLineM(false, logUPnP
, msg
);
799 CUPnPRootDevice::CUPnPRootDevice(
800 const CUPnPControlPoint
&upnpControlPoint
,
802 IXML_Element
*rootDevice
,
803 const std::string
&OriginalURLBase
,
804 const std::string
&FixedURLBase
,
805 const char *location
,
808 CUPnPDevice(upnpControlPoint
, upnpLib
, rootDevice
, FixedURLBase
),
809 m_UPnPControlPoint(upnpControlPoint
),
810 m_URLBase(OriginalURLBase
),
811 m_location(location
),
814 std::ostringstream msg
;
816 "\n Root Device: " <<
817 "\n URLBase: " << m_URLBase
<<
818 "\n Fixed URLBase: " << FixedURLBase
<<
819 "\n location: " << m_location
<<
820 "\n expires: " << m_expires
;
821 AddDebugLogLineM(false, logUPnP
, msg
);
825 CUPnPControlPoint
*CUPnPControlPoint::s_CtrlPoint
= NULL
;
828 CUPnPControlPoint::CUPnPControlPoint(unsigned short udpPort
)
831 m_UPnPClientHandle(),
834 m_ActivePortMappingsMap(),
835 m_RootDeviceListMutex(),
836 m_IGWDeviceDetected(false),
841 // Null string at first
842 std::ostringstream msg
;
846 char *ipAddress
= NULL
;
847 unsigned short port
= 0;
848 ret
= UpnpInit(ipAddress
, udpPort
);
849 if (ret
!= UPNP_E_SUCCESS
) {
850 msg
<< "error(UpnpInit): Error code ";
853 port
= UpnpGetServerPort();
854 ipAddress
= UpnpGetServerIpAddress();
855 msg
<< "bound to " << ipAddress
<< ":" <<
857 AddLogLineM(false, logUPnP
, msg
);
859 ret
= UpnpRegisterClient(
860 static_cast<Upnp_FunPtr
>(&CUPnPControlPoint::Callback
),
862 &m_UPnPClientHandle
);
863 if (ret
!= UPNP_E_SUCCESS
) {
864 msg
<< "error(UpnpRegisterClient): Error registering callback: ";
868 // We could ask for just the right device here. If the root device
869 // contains the device we want, it will respond with the full XML doc,
870 // including the root device and every sub-device it has.
872 // But lets find out what we have in our network by calling UPNP_ROOT_DEVICE.
874 // We should not search twice, because this will produce two
875 // UPNP_DISCOVERY_SEARCH_TIMEOUT events, and we might end with problems
877 ret
= UpnpSearchAsync(m_UPnPClientHandle
, 3, m_upnpLib
.UPNP_ROOT_DEVICE
.c_str(), NULL
);
878 //ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_IGW.c_str(), this);
879 //ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_LAN.c_str(), this);
880 //ret = UpnpSearchAsync(m_UPnPClientHandle, 3, m_upnpLib.UPNP_DEVICE_WAN_CONNECTION.c_str(), this);
881 if (ret
!= UPNP_E_SUCCESS
) {
882 msg
<< "error(UpnpSearchAsync): Error sending search request: ";
886 // Wait for the UPnP initialization to complete.
888 // Lock the search timeout mutex
889 m_WaitForSearchTimeoutMutex
.Lock();
891 // Lock it again, so that we block. Unlocking will only happen
892 // when the UPNP_DISCOVERY_SEARCH_TIMEOUT event occurs at the
894 CUPnPMutexLocker
lock(m_WaitForSearchTimeoutMutex
);
901 msg
<< ret
<< ": " << m_upnpLib
.GetUPnPErrorMessage(ret
) << ".";
902 throw CUPnPException(msg
);
906 CUPnPControlPoint::~CUPnPControlPoint()
908 for( RootDeviceMap::iterator it
= m_RootDeviceMap
.begin();
909 it
!= m_RootDeviceMap
.end();
915 UpnpUnRegisterClient(m_UPnPClientHandle
);
920 bool CUPnPControlPoint::AddPortMappings(
921 std::vector
<CUPnPPortMapping
> &upnpPortMapping
)
923 std::ostringstream msg
;
924 if (!WanServiceDetected()) {
925 msg
<< "UPnP Error: "
926 "CUPnPControlPoint::AddPortMapping: "
927 "Wan Service not detected.";
928 AddLogLineM(true, logUPnP
, msg
);
932 int n
= upnpPortMapping
.size();
935 // Check the number of port mappings before
936 std::istringstream
PortMappingNumberOfEntries(
937 m_WanService
->GetStateVariable(
938 "PortMappingNumberOfEntries"));
939 unsigned long oldNumberOfEntries
;
940 PortMappingNumberOfEntries
>> oldNumberOfEntries
;
942 // Add the enabled port mappings
943 for (int i
= 0; i
< n
; ++i
) {
944 if (upnpPortMapping
[i
].getEnabled() == "1") {
945 // Add the mapping to the control point
946 // active mappings list
947 m_ActivePortMappingsMap
[upnpPortMapping
[i
].getKey()] =
950 // Add the port mapping
951 PrivateAddPortMapping(upnpPortMapping
[i
]);
955 // Test some variables, this is deprecated, might not work
957 m_WanService
->GetStateVariable("ConnectionType");
958 m_WanService
->GetStateVariable("PossibleConnectionTypes");
959 m_WanService
->GetStateVariable("ConnectionStatus");
960 m_WanService
->GetStateVariable("Uptime");
961 m_WanService
->GetStateVariable("LastConnectionError");
962 m_WanService
->GetStateVariable("RSIPAvailable");
963 m_WanService
->GetStateVariable("NATEnabled");
964 m_WanService
->GetStateVariable("ExternalIPAddress");
965 m_WanService
->GetStateVariable("PortMappingNumberOfEntries");
966 m_WanService
->GetStateVariable("PortMappingLeaseDuration");
969 std::vector
<CUPnPArgumentValue
> argval
;
971 m_WanService
->Execute("GetStatusInfo", argval
);
974 // These do not work. Their value must be requested for a
975 // specific port mapping.
976 m_WanService
->GetStateVariable("PortMappingEnabled");
977 m_WanService
->GetStateVariable("RemoteHost");
978 m_WanService
->GetStateVariable("ExternalPort");
979 m_WanService
->GetStateVariable("InternalPort");
980 m_WanService
->GetStateVariable("PortMappingProtocol");
981 m_WanService
->GetStateVariable("InternalClient");
982 m_WanService
->GetStateVariable("PortMappingDescription");
987 msg
<< "CUPnPControlPoint::DeletePortMappings: "
988 "m_ActivePortMappingsMap.size() == " <<
989 m_ActivePortMappingsMap
.size();
990 AddDebugLogLineM(false, logUPnP
, msg
);
992 // Not very good, must find a better test
993 PortMappingNumberOfEntries
.str(
994 m_WanService
->GetStateVariable(
995 "PortMappingNumberOfEntries"));
996 unsigned long newNumberOfEntries
;
997 PortMappingNumberOfEntries
>> newNumberOfEntries
;
998 ok
= newNumberOfEntries
- oldNumberOfEntries
== 4;
1004 void CUPnPControlPoint::RefreshPortMappings()
1006 for ( PortMappingMap::iterator it
= m_ActivePortMappingsMap
.begin();
1007 it
!= m_ActivePortMappingsMap
.end();
1009 PrivateAddPortMapping(it
->second
);
1013 m_WanService
->GetStateVariable("PortMappingNumberOfEntries");
1017 bool CUPnPControlPoint::PrivateAddPortMapping(
1018 CUPnPPortMapping
&upnpPortMapping
)
1020 // Get an IP address. The UPnP server one must do.
1021 std::string
ipAddress(UpnpGetServerIpAddress());
1023 // Start building the action
1024 std::string
actionName("AddPortMapping");
1025 std::vector
<CUPnPArgumentValue
> argval(8);
1027 // Action parameters
1028 argval
[0].SetArgument("NewRemoteHost");
1029 argval
[0].SetValue("");
1030 argval
[1].SetArgument("NewExternalPort");
1031 argval
[1].SetValue(upnpPortMapping
.getPort());
1032 argval
[2].SetArgument("NewProtocol");
1033 argval
[2].SetValue(upnpPortMapping
.getProtocol());
1034 argval
[3].SetArgument("NewInternalPort");
1035 argval
[3].SetValue(upnpPortMapping
.getPort());
1036 argval
[4].SetArgument("NewInternalClient");
1037 argval
[4].SetValue(ipAddress
);
1038 argval
[5].SetArgument("NewEnabled");
1039 argval
[5].SetValue("1");
1040 argval
[6].SetArgument("NewPortMappingDescription");
1041 argval
[6].SetValue(upnpPortMapping
.getDescription());
1042 argval
[7].SetArgument("NewLeaseDuration");
1043 argval
[7].SetValue("0");
1047 for (ServiceMap::iterator it
= m_ServiceMap
.begin();
1048 it
!= m_ServiceMap
.end(); ++it
) {
1049 ret
&= it
->second
->Execute(actionName
, argval
);
1056 bool CUPnPControlPoint::DeletePortMappings(
1057 std::vector
<CUPnPPortMapping
> &upnpPortMapping
)
1059 std::ostringstream msg
;
1060 if (!WanServiceDetected()) {
1061 msg
<< "UPnP Error: "
1062 "CUPnPControlPoint::DeletePortMapping: "
1063 "Wan Service not detected.";
1064 AddLogLineM(true, logUPnP
, msg
);
1068 int n
= upnpPortMapping
.size();
1071 // Check the number of port mappings before
1072 std::istringstream
PortMappingNumberOfEntries(
1073 m_WanService
->GetStateVariable(
1074 "PortMappingNumberOfEntries"));
1075 unsigned long oldNumberOfEntries
;
1076 PortMappingNumberOfEntries
>> oldNumberOfEntries
;
1078 // Delete the enabled port mappings
1079 for (int i
= 0; i
< n
; ++i
) {
1080 if (upnpPortMapping
[i
].getEnabled() == "1") {
1081 // Delete the mapping from the control point
1082 // active mappings list
1083 PortMappingMap::iterator it
=
1084 m_ActivePortMappingsMap
.find(
1085 upnpPortMapping
[i
].getKey());
1086 if (it
!= m_ActivePortMappingsMap
.end()) {
1087 m_ActivePortMappingsMap
.erase(it
);
1089 msg
<< "UPnP Error: "
1090 "CUPnPControlPoint::DeletePortMapping: "
1091 "Mapping was not found in the active "
1093 AddLogLineM(true, logUPnP
, msg
);
1096 // Delete the port mapping
1097 PrivateDeletePortMapping(upnpPortMapping
[i
]);
1103 msg
<< "CUPnPControlPoint::DeletePortMappings: "
1104 "m_ActivePortMappingsMap.size() == " <<
1105 m_ActivePortMappingsMap
.size();
1106 AddDebugLogLineM(false, logUPnP
, msg
);
1108 // Not very good, must find a better test
1109 PortMappingNumberOfEntries
.str(
1110 m_WanService
->GetStateVariable(
1111 "PortMappingNumberOfEntries"));
1112 unsigned long newNumberOfEntries
;
1113 PortMappingNumberOfEntries
>> newNumberOfEntries
;
1114 ok
= oldNumberOfEntries
- newNumberOfEntries
== 4;
1120 bool CUPnPControlPoint::PrivateDeletePortMapping(
1121 CUPnPPortMapping
&upnpPortMapping
)
1123 // Start building the action
1124 std::string
actionName("DeletePortMapping");
1125 std::vector
<CUPnPArgumentValue
> argval(3);
1127 // Action parameters
1128 argval
[0].SetArgument("NewRemoteHost");
1129 argval
[0].SetValue("");
1130 argval
[1].SetArgument("NewExternalPort");
1131 argval
[1].SetValue(upnpPortMapping
.getPort());
1132 argval
[2].SetArgument("NewProtocol");
1133 argval
[2].SetValue(upnpPortMapping
.getProtocol());
1137 for (ServiceMap::iterator it
= m_ServiceMap
.begin();
1138 it
!= m_ServiceMap
.end(); ++it
) {
1139 ret
&= it
->second
->Execute(actionName
, argval
);
1146 // This function is static
1147 int CUPnPControlPoint::Callback(Upnp_EventType EventType
, void *Event
, void * /*Cookie*/)
1149 std::ostringstream msg
;
1150 std::ostringstream msg2
;
1151 // Somehow, this is unreliable. UPNP_DISCOVERY_ADVERTISEMENT_ALIVE events
1152 // happen with a wrong cookie and... boom!
1153 // CUPnPControlPoint *upnpCP = static_cast<CUPnPControlPoint *>(Cookie);
1154 CUPnPControlPoint
*upnpCP
= CUPnPControlPoint::s_CtrlPoint
;
1156 //fprintf(stderr, "Callback: %d, Cookie: %p\n", EventType, Cookie);
1157 switch (EventType
) {
1158 case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE
:
1159 //fprintf(stderr, "Callback: UPNP_DISCOVERY_ADVERTISEMENT_ALIVE\n");
1160 msg
<< "error(UPNP_DISCOVERY_ADVERTISEMENT_ALIVE): ";
1161 msg2
<< "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: ";
1163 case UPNP_DISCOVERY_SEARCH_RESULT
: {
1164 //fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_RESULT\n");
1165 msg
<< "error(UPNP_DISCOVERY_SEARCH_RESULT): ";
1166 msg2
<< "UPNP_DISCOVERY_SEARCH_RESULT: ";
1169 struct Upnp_Discovery
*d_event
= (struct Upnp_Discovery
*)Event
;
1170 IXML_Document
*doc
= NULL
;
1172 if (d_event
->ErrCode
!= UPNP_E_SUCCESS
) {
1173 msg
<< upnpCP
->m_upnpLib
.GetUPnPErrorMessage(d_event
->ErrCode
) << ".";
1174 AddDebugLogLineM(true, logUPnP
, msg
);
1176 // Get the XML tree device description in doc
1177 ret
= UpnpDownloadXmlDoc(d_event
->Location
, &doc
);
1178 if (ret
!= UPNP_E_SUCCESS
) {
1179 msg
<< "Error retrieving device description from " <<
1180 d_event
->Location
<< ": " <<
1181 upnpCP
->m_upnpLib
.GetUPnPErrorMessage(ret
) << ".";
1182 AddDebugLogLineM(true, logUPnP
, msg
);
1184 msg2
<< "Retrieving device description from " <<
1185 d_event
->Location
<< ".";
1186 AddDebugLogLineM(false, logUPnP
, msg2
);
1189 // Get the root node
1190 IXML_Element
*root
=
1191 upnpCP
->m_upnpLib
.Element_GetRootElement(doc
);
1192 // Extract the URLBase
1193 const std::string urlBase
= upnpCP
->m_upnpLib
.
1194 Element_GetChildValueByTag(root
, "URLBase");
1195 // Get the root device
1196 IXML_Element
*rootDevice
= upnpCP
->m_upnpLib
.
1197 Element_GetFirstChildByTag(root
, "device");
1198 // Extract the deviceType
1199 std::string
devType(upnpCP
->m_upnpLib
.
1200 Element_GetChildValueByTag(rootDevice
, "deviceType"));
1201 // Only add device if it is an InternetGatewayDevice
1202 if (stdStringIsEqualCI(devType
, upnpCP
->m_upnpLib
.UPNP_DEVICE_IGW
)) {
1203 // This condition can be used to auto-detect
1204 // the UPnP device we are interested in.
1205 // Obs.: Don't block the entry here on this
1206 // condition! There may be more than one device,
1207 // and the first that enters may not be the one
1208 // we are interested in!
1209 upnpCP
->SetIGWDeviceDetected(true);
1210 // Log it if not UPNP_DISCOVERY_ADVERTISEMENT_ALIVE,
1211 // we don't want to spam our logs.
1212 if (EventType
!= UPNP_DISCOVERY_ADVERTISEMENT_ALIVE
) {
1213 msg
.str("Internet Gateway Device Detected.");
1214 AddLogLineM(true, logUPnP
, msg
);
1216 // Add the root device to our list
1217 upnpCP
->AddRootDevice(rootDevice
, urlBase
,
1218 d_event
->Location
, d_event
->Expires
);
1220 // Free the XML doc tree
1221 ixmlDocument_free(doc
);
1225 case UPNP_DISCOVERY_SEARCH_TIMEOUT
: {
1226 //fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_TIMEOUT\n");
1228 msg
<< "UPNP_DISCOVERY_SEARCH_TIMEOUT.";
1229 AddDebugLogLineM(false, logUPnP
, msg
);
1231 // Unlock the search timeout mutex
1232 upnpCP
->m_WaitForSearchTimeoutMutex
.Unlock();
1236 case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE
: {
1237 //fprintf(stderr, "Callback: UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n");
1238 // UPnP Device Removed
1239 struct Upnp_Discovery
*dab_event
= (struct Upnp_Discovery
*)Event
;
1240 if (dab_event
->ErrCode
!= UPNP_E_SUCCESS
) {
1241 msg
<< "error(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE): " <<
1242 upnpCP
->m_upnpLib
.GetUPnPErrorMessage(dab_event
->ErrCode
) <<
1244 AddDebugLogLineM(true, logUPnP
, msg
);
1246 std::string devType
= dab_event
->DeviceType
;
1247 // Check for an InternetGatewayDevice and removes it from the list
1248 std::transform(devType
.begin(), devType
.end(), devType
.begin(), tolower
);
1249 if (stdStringIsEqualCI(devType
, upnpCP
->m_upnpLib
.UPNP_DEVICE_IGW
)) {
1250 upnpCP
->RemoveRootDevice(dab_event
->DeviceId
);
1254 case UPNP_EVENT_RECEIVED
: {
1255 //fprintf(stderr, "Callback: UPNP_EVENT_RECEIVED\n");
1257 struct Upnp_Event
*e_event
= (struct Upnp_Event
*)Event
;
1258 const std::string Sid
= e_event
->Sid
;
1260 upnpCP
->OnEventReceived(Sid
, e_event
->EventKey
, e_event
->ChangedVariables
);
1263 case UPNP_EVENT_SUBSCRIBE_COMPLETE
:
1264 //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIBE_COMPLETE\n");
1265 msg
<< "error(UPNP_EVENT_SUBSCRIBE_COMPLETE): ";
1266 goto upnpEventRenewalComplete
;
1267 case UPNP_EVENT_UNSUBSCRIBE_COMPLETE
:
1268 //fprintf(stderr, "Callback: UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n");
1269 msg
<< "error(UPNP_EVENT_UNSUBSCRIBE_COMPLETE): ";
1270 goto upnpEventRenewalComplete
;
1271 case UPNP_EVENT_RENEWAL_COMPLETE
: {
1272 //fprintf(stderr, "Callback: UPNP_EVENT_RENEWAL_COMPLETE\n");
1273 msg
<< "error(UPNP_EVENT_RENEWAL_COMPLETE): ";
1274 upnpEventRenewalComplete
:
1275 struct Upnp_Event_Subscribe
*es_event
=
1276 (struct Upnp_Event_Subscribe
*)Event
;
1277 if (es_event
->ErrCode
!= UPNP_E_SUCCESS
) {
1278 msg
<< "Error in Event Subscribe Callback";
1279 upnpCP
->m_upnpLib
.processUPnPErrorMessage(
1280 msg
.str(), es_event
->ErrCode
, NULL
, NULL
);
1283 TvCtrlPointHandleSubscribeUpdate(
1284 es_event
->PublisherUrl
,
1286 es_event
->TimeOut
);
1293 case UPNP_EVENT_AUTORENEWAL_FAILED
:
1294 //fprintf(stderr, "Callback: UPNP_EVENT_AUTORENEWAL_FAILED\n");
1295 msg
<< "error(UPNP_EVENT_AUTORENEWAL_FAILED): ";
1296 msg2
<< "UPNP_EVENT_AUTORENEWAL_FAILED: ";
1297 goto upnpEventSubscriptionExpired
;
1298 case UPNP_EVENT_SUBSCRIPTION_EXPIRED
: {
1299 //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_EXPIRED\n");
1300 msg
<< "error(UPNP_EVENT_SUBSCRIPTION_EXPIRED): ";
1301 msg2
<< "UPNP_EVENT_SUBSCRIPTION_EXPIRED: ";
1302 upnpEventSubscriptionExpired
:
1303 struct Upnp_Event_Subscribe
*es_event
=
1304 (struct Upnp_Event_Subscribe
*)Event
;
1307 int ret
= UpnpSubscribe(
1308 upnpCP
->m_UPnPClientHandle
,
1309 es_event
->PublisherUrl
,
1312 if (ret
!= UPNP_E_SUCCESS
) {
1313 msg
<< "Error Subscribing to EventURL";
1314 upnpCP
->m_upnpLib
.processUPnPErrorMessage(
1315 msg
.str(), es_event
->ErrCode
, NULL
, NULL
);
1317 ServiceMap::iterator it
=
1318 upnpCP
->m_ServiceMap
.find(es_event
->PublisherUrl
);
1319 if (it
!= upnpCP
->m_ServiceMap
.end()) {
1320 CUPnPService
&service
= *(it
->second
);
1321 service
.SetTimeout(TimeOut
);
1322 service
.SetSID(newSID
);
1323 msg2
<< "Re-subscribed to EventURL '" <<
1324 es_event
->PublisherUrl
<<
1325 "' with SID == '" <<
1327 AddDebugLogLineM(true, logUPnP
, msg2
);
1328 // In principle, we should test to see if the
1329 // service is the same. But here we only have one
1331 upnpCP
->RefreshPortMappings();
1333 msg
<< "Error: did not find service " <<
1334 newSID
<< " in the service map.";
1335 AddDebugLogLineM(true, logUPnP
, msg
);
1340 case UPNP_CONTROL_ACTION_COMPLETE
: {
1341 //fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_COMPLETE\n");
1342 // This is here if we choose to do this asynchronously
1343 struct Upnp_Action_Complete
*a_event
=
1344 (struct Upnp_Action_Complete
*)Event
;
1345 if (a_event
->ErrCode
!= UPNP_E_SUCCESS
) {
1346 upnpCP
->m_upnpLib
.processUPnPErrorMessage(
1347 "UpnpSendActionAsync",
1348 a_event
->ErrCode
, NULL
,
1349 a_event
->ActionResult
);
1351 // Check the response document
1352 upnpCP
->m_upnpLib
.ProcessActionResponse(
1353 a_event
->ActionResult
,
1354 "<UpnpSendActionAsync>");
1356 /* No need for any processing here, just print out results.
1357 * Service state table updates are handled by events.
1361 case UPNP_CONTROL_GET_VAR_COMPLETE
: {
1362 //fprintf(stderr, "Callback: UPNP_CONTROL_GET_VAR_COMPLETE\n");
1363 msg
<< "error(UPNP_CONTROL_GET_VAR_COMPLETE): ";
1364 struct Upnp_State_Var_Complete
*sv_event
=
1365 (struct Upnp_State_Var_Complete
*)Event
;
1366 if (sv_event
->ErrCode
!= UPNP_E_SUCCESS
) {
1367 msg
<< "m_UpnpGetServiceVarStatusAsync";
1368 upnpCP
->m_upnpLib
.processUPnPErrorMessage(
1369 msg
.str(), sv_event
->ErrCode
, NULL
, NULL
);
1372 // Warning: The use of UpnpGetServiceVarStatus and
1373 // UpnpGetServiceVarStatusAsync is deprecated by the
1375 TvCtrlPointHandleGetVar(
1377 sv_event
->StateVarName
,
1378 sv_event
->CurrentVal
);
1383 // ignore these cases, since this is not a device
1384 case UPNP_CONTROL_GET_VAR_REQUEST
:
1385 //fprintf(stderr, "Callback: UPNP_CONTROL_GET_VAR_REQUEST\n");
1386 msg
<< "error(UPNP_CONTROL_GET_VAR_REQUEST): ";
1387 goto eventSubscriptionRequest
;
1388 case UPNP_CONTROL_ACTION_REQUEST
:
1389 //fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_REQUEST\n");
1390 msg
<< "error(UPNP_CONTROL_ACTION_REQUEST): ";
1391 goto eventSubscriptionRequest
;
1392 case UPNP_EVENT_SUBSCRIPTION_REQUEST
:
1393 //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_REQUEST\n");
1394 msg
<< "error(UPNP_EVENT_SUBSCRIPTION_REQUEST): ";
1395 eventSubscriptionRequest
:
1396 msg
<< "This is not a UPnP Device, this is a UPnP Control Point, event ignored.";
1397 AddDebugLogLineM(true, logUPnP
, msg
);
1400 // Humm, this is not good, we forgot to handle something...
1402 "Callback: default... Unknown event:'%d', not good.\n",
1404 msg
<< "error(UPnP::Callback): Event not handled:'" <<
1406 fprintf(stderr
, "%s\n", msg
.str().c_str());
1407 AddDebugLogLineM(true, logUPnP
, msg
);
1408 // Better not throw in the callback. Who would catch it?
1409 //throw CUPnPException(msg);
1417 void CUPnPControlPoint::OnEventReceived(
1418 const std::string
&Sid
,
1420 IXML_Document
*ChangedVariablesDoc
)
1422 std::ostringstream msg
;
1423 msg
<< "UPNP_EVENT_RECEIVED:" <<
1424 "\n SID: " << Sid
<<
1425 "\n Key: " << EventKey
<<
1426 "\n Property list:";
1427 IXML_Element
*root
=
1428 m_upnpLib
.Element_GetRootElement(ChangedVariablesDoc
);
1429 IXML_Element
*child
=
1430 m_upnpLib
.Element_GetFirstChild(root
);
1433 IXML_Element
*child2
=
1434 m_upnpLib
.Element_GetFirstChild(child
);
1435 const DOMString childTag
=
1436 m_upnpLib
.Element_GetTag(child2
);
1437 std::string childValue
=
1438 m_upnpLib
.Element_GetTextValue(child2
);
1442 child
= m_upnpLib
.Element_GetNextSibling(child
);
1445 msg
<< "\n Empty property list.";
1447 AddDebugLogLineM(true, logUPnP
, msg
);
1448 // Freeing that doc segfaults. Probably should not be freed.
1449 //ixmlDocument_free(ChangedVariablesDoc);
1453 void CUPnPControlPoint::AddRootDevice(
1454 IXML_Element
*rootDevice
, const std::string
&urlBase
,
1455 const char *location
, int expires
)
1457 // Lock the Root Device List
1458 CUPnPMutexLocker
lock(m_RootDeviceListMutex
);
1460 // Root node's URLBase
1461 std::string
OriginalURLBase(urlBase
);
1462 std::string
FixedURLBase(OriginalURLBase
.empty() ?
1466 // Get the UDN (Unique Device Name)
1468 m_upnpLib
.Element_GetChildValueByTag(rootDevice
, "UDN"));
1469 RootDeviceMap::iterator it
= m_RootDeviceMap
.find(UDN
);
1470 bool alreadyAdded
= it
!= m_RootDeviceMap
.end();
1472 // Just set the expires field
1473 it
->second
->SetExpires(expires
);
1475 // Add a new root device to the root device list
1476 CUPnPRootDevice
*upnpRootDevice
= new CUPnPRootDevice(
1477 *this, m_upnpLib
, rootDevice
,
1478 OriginalURLBase
, FixedURLBase
,
1480 m_RootDeviceMap
[upnpRootDevice
->GetUDN()] = upnpRootDevice
;
1485 void CUPnPControlPoint::RemoveRootDevice(const char *udn
)
1487 // Lock the Root Device List
1488 CUPnPMutexLocker
lock(m_RootDeviceListMutex
);
1491 std::string
UDN(udn
);
1492 RootDeviceMap::iterator it
= m_RootDeviceMap
.find(UDN
);
1493 if (it
!= m_RootDeviceMap
.end()) {
1495 m_RootDeviceMap
.erase(UDN
);
1500 void CUPnPControlPoint::Subscribe(CUPnPService
&service
)
1502 std::ostringstream msg
;
1503 int errcode
= UpnpSubscribe(m_UPnPClientHandle
,
1504 service
.GetAbsEventSubURL().c_str(),
1505 service
.GetTimeoutAddr(),
1507 if (errcode
== UPNP_E_SUCCESS
) {
1508 m_ServiceMap
[service
.GetAbsEventSubURL()] = &service
;
1509 msg
<< "Successfully subscribed to service " <<
1510 service
.GetServiceType() << ", absEventSubURL: " <<
1511 service
.GetAbsEventSubURL() << ".";
1512 AddLogLineM(true, logUPnP
, msg
);
1514 IXML_Document
*scpdDoc
= NULL
;
1515 errcode
= UpnpDownloadXmlDoc(
1516 service
.GetAbsSCPDURL().c_str(), &scpdDoc
);
1517 if (errcode
== UPNP_E_SUCCESS
) {
1518 // Get the root node
1519 IXML_Element
*scpdRoot
=
1520 m_upnpLib
.Element_GetRootElement(scpdDoc
);
1521 CUPnPSCPD
*scpd
= new CUPnPSCPD(*this, m_upnpLib
,
1522 scpdRoot
, service
.GetAbsSCPDURL());
1523 service
.SetSCPD(scpd
);
1526 msg
<< "Error getting SCPD Document from " <<
1527 service
.GetAbsSCPDURL() << ".";
1528 AddLogLineM(true, logUPnP
, msg
);
1531 msg
<< "Error subscribing to service " <<
1532 service
.GetServiceType() << ", absEventSubURL: " <<
1533 service
.GetAbsEventSubURL() << ", error: " <<
1534 m_upnpLib
.GetUPnPErrorMessage(errcode
) << ".";
1542 AddLogLineM(true, logUPnP
, msg
);
1546 void CUPnPControlPoint::Unsubscribe(CUPnPService
&service
)
1548 ServiceMap::iterator it
= m_ServiceMap
.find(service
.GetAbsEventSubURL());
1549 m_ServiceMap
.erase(it
);
1550 UpnpUnSubscribe(m_UPnPClientHandle
, service
.GetSID());
1554 // File_checked_for_headers