Upstream tarball 20080603
[amule.git] / src / UPnP.h
blobdf8c8a41f07db9aa3118908cda2404c6efa6ced3
1 //
2 // This file is part of the aMule Project.
3 //
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 )
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.
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.
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
27 // This define must not conflict with the one in the standard header
28 #ifndef AMULE_UPNP_H
29 #define AMULE_UPNP_H
32 #include <map>
33 #include <string>
34 #include <sstream>
35 #include <memory>
37 #include "UPnPCompatibility.h"
40 #ifdef UPNP_C
41 std::string stdEmptyString;
42 #else // UPNP_C
43 extern std::string stdEmptyString;
44 #endif // UPNP_C
47 /**
48 * Case insensitive std::string comparison
50 bool stdStringIsEqualCI(
51 const std::string &s1,
52 const std::string &s2);
55 class CUPnPPortMapping
57 private:
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;
64 public:
65 CUPnPPortMapping(
66 int port = 0,
67 const std::string &protocol = stdEmptyString,
68 bool enabled = false,
69 const std::string &description = stdEmptyString);
70 ~CUPnPPortMapping() {}
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; }
85 class CDynamicLibHandle
87 private:
88 std::string m_libname;
89 void *const m_LibraryHandle;
90 CDynamicLibHandle(const CDynamicLibHandle &);
91 CDynamicLibHandle &operator=(const CDynamicLibHandle &);
93 public:
94 CDynamicLibHandle(const char *libname);
95 ~CDynamicLibHandle();
96 void *Get() const { return m_LibraryHandle; }
100 class CUPnPControlPoint;
103 class CUPnPLib
105 public:
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;
117 private:
118 // dlopen stuff
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);
129 public:
130 CUPnPLib(CUPnPControlPoint &ctrlPoint);
131 ~CUPnPLib() {}
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
138 // messages
139 std::string processUPnPErrorMessage(
140 const std::string &messsage,
141 int code,
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;
150 // IXML_Element
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;
174 // ixml api
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);
185 // upnp api
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);
194 // 2 - Discovery
195 int (*m_UpnpSearchAsync)(UpnpClient_Handle Hnd, int Mx,
196 const char *Target, const void *Cookie);
197 // 3 - Control
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);
206 // 4 - Eventing
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);
210 // 5 - HTTP
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 *>
238 public:
239 CXML_List(
240 const CUPnPControlPoint &upnpControlPoint,
241 CUPnPLib &upnpLib,
242 IXML_Element *parent,
243 const std::string &url);
244 ~CXML_List();
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,
251 CUPnPLib &upnpLib,
252 IXML_Element *parent,
253 const std::string &url)
255 IXML_Element *elementList =
256 upnpLib.Element_GetFirstChildByTag(parent, XML_LIST_NAME);
257 unsigned int i = 0;
258 for ( IXML_Element *element = upnpLib.Element_GetFirstChildByTag(elementList, XML_ELEMENT_NAME);
259 element;
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;
264 ++i;
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) {
278 delete (*it).second;
282 #ifdef UPNP_C
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";
295 #else // UPNP_C
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[];
308 #endif // UPNP_C
311 class CUPnPArgument;
312 typedef CXML_List<CUPnPArgument, s_argument, s_argumentList> ArgumentList;
313 class CUPnPAction;
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;
319 class CUPnPService;
320 typedef CXML_List<CUPnPService, s_service, s_serviceList> ServiceList;
321 class CUPnPDevice;
322 typedef CXML_List<CUPnPDevice, s_device, s_deviceList> DeviceList;
325 class CUPnPError
327 private:
328 IXML_Element *m_root;
329 const std::string m_ErrorCode;
330 const std::string m_ErrorDescription;
331 public:
332 CUPnPError(
333 const CUPnPLib &upnpLib,
334 IXML_Document *errorDoc);
335 ~CUPnPError() {}
336 const std::string &getErrorCode() const
337 { return m_ErrorCode; }
338 const std::string &getErrorDescription() const
339 { return m_ErrorDescription; }
343 class CUPnPArgument
345 private:
346 const CUPnPControlPoint &m_UPnPControlPoint;
347 const std::string m_name;
348 const std::string m_direction;
349 bool m_retval;
350 const std::string m_relatedStateVariable;
352 public:
353 CUPnPArgument(
354 const CUPnPControlPoint &upnpControlPoint,
355 CUPnPLib &upnpLib,
356 IXML_Element *argument,
357 const std::string &SCPDURL);
358 ~CUPnPArgument() {}
359 const std::string &GetName() const
360 { return m_name; }
361 const std::string &GetDirection() const
362 { return m_direction; }
363 bool GetRetVal() const
364 { return m_retval; }
365 const std::string &GetRelatedStateVariable() const
366 { return m_relatedStateVariable; }
367 const std::string &GetKey() const
368 { return m_name; }
373 class CUPnPAction
375 private:
376 const CUPnPControlPoint &m_UPnPControlPoint;
377 ArgumentList m_ArgumentList;
378 const std::string m_name;
380 public:
381 CUPnPAction(
382 const CUPnPControlPoint &upnpControlPoint,
383 CUPnPLib &upnpLib,
384 IXML_Element *action,
385 const std::string &SCPDURL);
386 ~CUPnPAction() {}
387 const std::string &GetName() const
388 { return m_name; }
389 const std::string &GetKey() const
390 { return m_name; }
391 const ArgumentList &GetArgumentList() const
392 { return m_ArgumentList; }
396 class CUPnPAllowedValue
398 private:
399 const CUPnPControlPoint &m_UPnPControlPoint;
400 const std::string m_allowedValue;
402 public:
403 CUPnPAllowedValue(
404 const CUPnPControlPoint &upnpControlPoint,
405 CUPnPLib &upnpLib,
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
418 private:
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;
426 public:
427 CUPnPStateVariable(
428 const CUPnPControlPoint &upnpControlPoint,
429 CUPnPLib &upnpLib,
430 IXML_Element *stateVariable,
431 const std::string &URLBase);
432 ~CUPnPStateVariable() {}
433 const std::string &GetNname() const
434 { return m_name; }
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
440 { return m_name; }
441 const AllowedValueList &GetAllowedValueList() const
442 { return m_AllowedValueList; }
446 class CUPnPSCPD
448 private:
449 const CUPnPControlPoint &m_UPnPControlPoint;
450 ActionList m_ActionList;
451 ServiceStateTable m_ServiceStateTable;
452 const std::string m_SCPDURL;
454 public:
455 CUPnPSCPD(
456 const CUPnPControlPoint &upnpControlPoint,
457 CUPnPLib &upnpLib,
458 IXML_Element *scpd,
459 const std::string &SCPDURL);
460 ~CUPnPSCPD() {}
461 const ActionList &GetActionList() const
462 { return m_ActionList; }
463 const ServiceStateTable &GetServiceStateTable() const
464 { return m_ServiceStateTable; }
468 class CUPnPArgumentValue
470 private:
471 std::string m_argument;
472 std::string m_value;
474 public:
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; }
486 class CUPnPService
488 private:
489 const CUPnPControlPoint &m_UPnPControlPoint;
490 CUPnPLib &m_upnpLib;
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;
499 int m_timeout;
500 Upnp_SID m_SID;
501 std::auto_ptr<CUPnPSCPD> m_SCPD;
503 public:
504 CUPnPService(
505 const CUPnPControlPoint &upnpControlPoint,
506 CUPnPLib &upnpLib,
507 IXML_Element *service,
508 const std::string &URLBase);
509 ~CUPnPService();
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)
530 { m_timeout = t; }
531 int *GetTimeoutAddr()
532 { return &m_timeout; }
533 char *GetSID()
534 { return m_SID; }
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); }
544 bool Execute(
545 const std::string &ActionName,
546 const std::vector<CUPnPArgumentValue> &ArgValue) const;
547 const std::string GetStateVariable(
548 const std::string &stateVariableName) const;
552 class CUPnPDevice
554 private:
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;
574 public:
575 CUPnPDevice(
576 const CUPnPControlPoint &upnpControlPoint,
577 CUPnPLib &upnpLib,
578 IXML_Element *device,
579 const std::string &URLBase);
580 ~CUPnPDevice() {}
582 const std::string &GetUDN() const
583 { return m_UDN; }
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
591 { return m_UDN; }
595 class CUPnPRootDevice : public CUPnPDevice
597 private:
598 const CUPnPControlPoint &m_UPnPControlPoint;
599 const std::string m_URLBase;
600 const std::string m_location;
601 int m_expires;
603 public:
604 CUPnPRootDevice(
605 const CUPnPControlPoint &upnpControlPoint,
606 CUPnPLib &upnpLib,
607 IXML_Element *rootDevice,
608 const std::string &OriginalURLBase,
609 const std::string &FixedURLBase,
610 const char *location,
611 int expires);
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
632 private:
633 static CUPnPControlPoint *s_CtrlPoint;
634 // upnp stuff
635 CUPnPLib m_upnpLib;
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;
646 public:
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; }
668 // Callback function
669 static int Callback(
670 Upnp_EventType EventType,
671 void* Event,
672 void* Cookie);
674 private:
675 void OnEventReceived(
676 const std::string &Sid,
677 int EventKey,
678 IXML_Document *ChangedVariables);
679 void AddRootDevice(
680 IXML_Element *rootDevice,
681 const std::string &urlBase,
682 const char *location,
683 int expires);
684 void RemoveRootDevice(
685 const char *udn);
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