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