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 
36 #include "UPnPCompatibility.h"
37 
38 #include <common/SmartPtr.h>		// Needed for CSmartPtr
39 
40 
41 extern std::string stdEmptyString;
42 
43 
44 class CUPnPPortMapping
45 {
46 private:
47 	std::string m_port;
48 	std::string m_protocol;
49 	std::string m_enabled;
50 	std::string m_description;
51 	std::string m_key;
52 
53 public:
54 	CUPnPPortMapping(
55 		int port = 0,
56 		const std::string &protocol = stdEmptyString,
57 		bool enabled = false,
58 		const std::string &description = stdEmptyString);
59 	~CUPnPPortMapping() {}
60 
61 	const std::string &getPort() const
62 		{ return m_port; }
63 	const std::string &getProtocol() const
64 		{ return m_protocol; }
65 	const std::string &getEnabled() const
66 		{ return m_enabled; }
67 	const std::string &getDescription() const
68 		{ return m_description; }
69 	const std::string &getKey() const
70 		{ return m_key; }
71 };
72 
73 
74 namespace IXML
75 {
76 	namespace Document {
77 		IXML_Element *GetRootElement(IXML_Document *doc);
78 		void Free(IXML_Document *doc);
79 	}
80 
81 	namespace Element {
82 		IXML_Element *GetFirstChild(IXML_Element *parent);
83 		IXML_Element *GetNextSibling(IXML_Element *child);
84 		const DOMString GetTag(IXML_Element *element);
85 		const std::string GetTextValue(IXML_Element *element);
86 		const std::string GetChildValueByTag(IXML_Element *element, const DOMString tag);
87 		IXML_Element *GetFirstChildByTag(IXML_Element *element, const DOMString tag);
88 		IXML_Element *GetNextSiblingByTag(IXML_Element *element, const DOMString tag);
89 		const std::string GetAttributeByTag(IXML_Element *element, const DOMString tag);
90 	}
91 }
92 
93 
94 class CUPnPControlPoint;
95 
96 template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME>
97 class CXML_List : public std::map<const std::string, T *>
98 {
99 public:
100 	CXML_List(
101 		const CUPnPControlPoint &upnpControlPoint,
102 		IXML_Element *parent,
103 		const std::string &url);
104 	~CXML_List();
105 };
106 
107 
108 template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME>
109 CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::CXML_List(
110 	const CUPnPControlPoint &upnpControlPoint,
111 	IXML_Element *parent,
112 	const std::string &url)
113 {
114 	IXML_Element *elementList = IXML::Element::GetFirstChildByTag(parent, XML_LIST_NAME);
115 	unsigned int i = 0;
116 	for (   IXML_Element *element = IXML::Element::GetFirstChildByTag(elementList, XML_ELEMENT_NAME);
117 		element;
118 		element = IXML::Element::GetNextSiblingByTag(element, XML_ELEMENT_NAME)) {
119 		// Add a new element to the element list
120 		T *upnpElement = new T(upnpControlPoint, element, url);
121 		(*this)[upnpElement->GetKey()] = upnpElement;
122 		++i;
123 	}
124 	std::ostringstream msg;
125 	msg << "\n    " << XML_LIST_NAME << ": " <<
126 		i << " " << XML_ELEMENT_NAME << "s.";
127 	AddDebugLogLineN(logUPnP, msg);
128 }
129 
130 
131 template <typename T, char const *XML_ELEMENT_NAME, char const *XML_LIST_NAME>
132 CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::~CXML_List()
133 {
134 	typename CXML_List<T, XML_ELEMENT_NAME, XML_LIST_NAME>::iterator it;
135 	for(it = this->begin(); it != this->end(); ++it) {
136 		delete (*it).second;
137 	}
138 }
139 
140 extern const char s_argument[];
141 extern const char s_argumentList[];
142 extern const char s_action[];
143 extern const char s_actionList[];
144 extern const char s_allowedValue[];
145 extern const char s_allowedValueList[];
146 extern const char s_stateVariable[];
147 extern const char s_serviceStateTable[];
148 extern const char s_service[];
149 extern const char s_serviceList[];
150 extern const char s_device[];
151 extern const char s_deviceList[];
152 
153 
154 
155 class CUPnPArgument;
156 typedef CXML_List<CUPnPArgument, s_argument, s_argumentList> ArgumentList;
157 class CUPnPAction;
158 typedef CXML_List<CUPnPAction, s_action, s_actionList> ActionList;
159 class CUPnPStateVariable;
160 typedef CXML_List<CUPnPStateVariable, s_stateVariable, s_serviceStateTable> ServiceStateTable;
161 class CUPnPAllowedValue;
162 typedef CXML_List<CUPnPAllowedValue, s_allowedValue, s_allowedValueList> AllowedValueList;
163 class CUPnPService;
164 typedef CXML_List<CUPnPService, s_service, s_serviceList> ServiceList;
165 class CUPnPDevice;
166 typedef CXML_List<CUPnPDevice, s_device, s_deviceList> DeviceList;
167 
168 
169 class CUPnPError
170 {
171 private:
172 	IXML_Element *m_root;
173 	const std::string m_ErrorCode;
174 	const std::string m_ErrorDescription;
175 public:
176 	CUPnPError(IXML_Document *errorDoc);
177 	~CUPnPError() {}
178 	const std::string &getErrorCode() const
179 		{ return m_ErrorCode; }
180 	const std::string &getErrorDescription() const
181 		{ return m_ErrorDescription; }
182 };
183 
184 
185 class CUPnPArgument
186 {
187 private:
188 	const std::string m_name;
189 	const std::string m_direction;
190 	bool m_retval;
191 	const std::string m_relatedStateVariable;
192 
193 public:
194 	CUPnPArgument(
195 		const CUPnPControlPoint &upnpControlPoint,
196 		IXML_Element *argument,
197 		const std::string &SCPDURL);
198 	~CUPnPArgument() {}
199 	const std::string &GetName() const
200 		{ return m_name; }
201 	const std::string &GetDirection() const
202 		{ return m_direction; }
203 	bool GetRetVal() const
204 		{ return m_retval; }
205 	const std::string &GetRelatedStateVariable() const
206 		{ return m_relatedStateVariable; }
207 	const std::string &GetKey() const
208 		{ return m_name; }
209 };
210 
211 
212 
213 class CUPnPAction
214 {
215 private:
216 	ArgumentList m_ArgumentList;
217 	const std::string m_name;
218 
219 public:
220 	CUPnPAction(
221 		const CUPnPControlPoint &upnpControlPoint,
222 		IXML_Element *action,
223 		const std::string &SCPDURL);
224 	~CUPnPAction() {}
225 	const std::string &GetName() const
226 		{ return m_name; }
227 	const std::string &GetKey() const
228 		{ return m_name; }
229 	const ArgumentList &GetArgumentList() const
230 		{ return m_ArgumentList; }
231 };
232 
233 
234 class CUPnPAllowedValue
235 {
236 private:
237 	const std::string m_allowedValue;
238 
239 public:
240 	CUPnPAllowedValue(
241 		const CUPnPControlPoint &upnpControlPoint,
242 		IXML_Element *allowedValue,
243 		const std::string &SCPDURL);
244 	~CUPnPAllowedValue() {}
245 	const std::string &GetAllowedValue() const
246 		{ return m_allowedValue; }
247 	const std::string &GetKey() const
248 		{ return m_allowedValue; }
249 };
250 
251 
252 class CUPnPStateVariable
253 {
254 private:
255 	AllowedValueList m_AllowedValueList;
256 	const std::string m_name;
257 	const std::string m_dataType;
258 	const std::string m_defaultValue;
259 	const std::string m_sendEvents;
260 
261 public:
262 	CUPnPStateVariable(
263 		const CUPnPControlPoint &upnpControlPoint,
264 		IXML_Element *stateVariable,
265 		const std::string &URLBase);
266 	~CUPnPStateVariable() {}
267 	const std::string &GetNname() const
268 		{ return m_name; }
269 	const std::string &GetDataType() const
270 		{ return m_dataType; }
271 	const std::string &GetDefaultValue() const
272 		{ return m_defaultValue; }
273 	const std::string &GetKey() const
274 		{ return m_name; }
275 	const AllowedValueList &GetAllowedValueList() const
276 		{ return m_AllowedValueList; }
277 };
278 
279 
280 class CUPnPSCPD
281 {
282 private:
283 	ActionList m_ActionList;
284 	ServiceStateTable m_ServiceStateTable;
285 	const std::string m_SCPDURL;
286 
287 public:
288 	CUPnPSCPD(
289 		const CUPnPControlPoint &upnpControlPoint,
290 		IXML_Element *scpd,
291 		const std::string &SCPDURL);
292 	~CUPnPSCPD() {}
293 	const ActionList &GetActionList() const
294 		{ return m_ActionList; }
295 	const ServiceStateTable &GetServiceStateTable() const
296 		{ return m_ServiceStateTable; }
297 };
298 
299 
300 class CUPnPArgumentValue
301 {
302 private:
303 	std::string m_argument;
304 	std::string m_value;
305 
306 public:
307 	CUPnPArgumentValue();
308 	CUPnPArgumentValue(const std::string &argument, const std::string &value);
309 	~CUPnPArgumentValue() {}
310 
311 	const std::string &GetArgument() const	{ return m_argument; }
312 	const std::string &GetValue() const	{ return m_value; }
313 	const std::string &SetArgument(const std::string& argument)	{ return m_argument = argument; }
314 	const std::string &SetValue(const std::string &value)		{ return m_value = value; }
315 };
316 
317 
318 class CUPnPService
319 {
320 private:
321 	const CUPnPControlPoint &m_UPnPControlPoint;
322 	const std::string m_serviceType;
323 	const std::string m_serviceId;
324 	const std::string m_SCPDURL;
325 	const std::string m_controlURL;
326 	const std::string m_eventSubURL;
327 	std::string m_absSCPDURL;
328 	std::string m_absControlURL;
329 	std::string m_absEventSubURL;
330 	int m_timeout;
331 	Upnp_SID m_SID;
332 	CSmartPtr<CUPnPSCPD> m_SCPD;
333 
334 public:
335 	CUPnPService(
336 		const CUPnPControlPoint &upnpControlPoint,
337 		IXML_Element *service,
338 		const std::string &URLBase);
339 	~CUPnPService();
340 
341 	const std::string &GetServiceType() const
342 		{ return m_serviceType; }
343 	const std::string &GetServiceId() const
344 		{ return m_serviceId; }
345 	const std::string &GetSCPDURL() const
346 		{ return m_SCPDURL; }
347 	const std::string &GetAbsSCPDURL() const
348 		{ return m_absSCPDURL; }
349 	const std::string &GetControlURL() const
350 		{ return m_controlURL; }
351 	const std::string &GetEventSubURL() const
352 		{ return m_eventSubURL; }
353 	const std::string &GetAbsControlURL() const
354 		{ return m_absControlURL; }
355 	const std::string &GetAbsEventSubURL() const
356 		{ return m_absEventSubURL; }
357 	int GetTimeout() const
358 		{ return m_timeout; }
359 	void SetTimeout(int t)
360 		{ m_timeout = t; }
361 	int *GetTimeoutAddr()
362 		{ return &m_timeout; }
363 	char *GetSID()
364 		{ return m_SID; }
365 	void SetSID(const char *s)
366 		{ memcpy(m_SID, s, sizeof(Upnp_SID)); }
367 	const std::string &GetKey() const
368 		{ return m_serviceId; }
369 	bool IsSubscribed() const
370 		{ return m_SCPD.get() != NULL; }
371 	void SetSCPD(CUPnPSCPD *SCPD)
372 		{ m_SCPD.reset(SCPD); }
373 
374 	bool Execute(
375 		const std::string &ActionName,
376 		const std::vector<CUPnPArgumentValue> &ArgValue) const;
377 	const std::string GetStateVariable(
378 		const std::string &stateVariableName) const;
379 };
380 
381 
382 class CUPnPDevice
383 {
384 private:
385 	// Please, lock these lists before use
386 	DeviceList m_DeviceList;
387 	ServiceList m_ServiceList;
388 
389 	const std::string m_deviceType;
390 	const std::string m_friendlyName;
391 	const std::string m_manufacturer;
392 	const std::string m_manufacturerURL;
393 	const std::string m_modelDescription;
394 	const std::string m_modelName;
395 	const std::string m_modelNumber;
396 	const std::string m_modelURL;
397 	const std::string m_serialNumber;
398 	const std::string m_UDN;
399 	const std::string m_UPC;
400 	std::string m_presentationURL;
401 
402 public:
403 	CUPnPDevice(
404 		const CUPnPControlPoint &upnpControlPoint,
405 		IXML_Element *device,
406 		const std::string &URLBase);
407 	~CUPnPDevice() {}
408 
409 	const std::string &GetUDN() const
410 		{ return m_UDN; }
411 	const std::string &GetDeviceType() const
412 		{ return m_deviceType; }
413 	const std::string &GetFriendlyName() const
414 		{ return m_friendlyName; }
415 	const std::string &GetPresentationURL() const
416 		{ return m_presentationURL; }
417 	const std::string &GetKey() const
418 		{ return m_UDN; }
419 };
420 
421 
422 class CUPnPRootDevice : public CUPnPDevice
423 {
424 private:
425 	const std::string m_URLBase;
426 	const std::string m_location;
427 	int m_expires;
428 
429 public:
430 	CUPnPRootDevice(
431 		const CUPnPControlPoint &upnpControlPoint,
432 		IXML_Element *rootDevice,
433 		const std::string &OriginalURLBase,
434 		const std::string &FixedURLBase,
435 		const char *location,
436 		int expires);
437 	~CUPnPRootDevice() {}
438 
439 	const std::string &GetURLBase() const
440 		{ return m_URLBase; }
441 	const std::string &GetLocation() const
442 		{ return m_location; }
443 	int GetExpires() const
444 		{ return m_expires; }
445 	void SetExpires(int expires)
446 		{ m_expires = expires; }
447 };
448 
449 
450 typedef std::map<const std::string, CUPnPRootDevice *> RootDeviceMap;
451 typedef std::map<const std::string, CUPnPService *> ServiceMap;
452 typedef std::map<const std::string, CUPnPPortMapping> PortMappingMap;
453 
454 
455 class CUPnPControlPoint
456 {
457 private:
458 	static CUPnPControlPoint *s_CtrlPoint;
459 	// upnp stuff
460 	UpnpClient_Handle m_UPnPClientHandle;
461 	RootDeviceMap m_RootDeviceMap;
462 	ServiceMap m_ServiceMap;
463 	PortMappingMap m_ActivePortMappingsMap;
464 	CUPnPMutex m_RootDeviceListMutex;
465 	bool m_IGWDeviceDetected;
466 //#warning This variable is for testing purposes only and should disappear on release.
467 	CUPnPService *m_WanService;
468 	CUPnPMutex m_WaitForSearchTimeoutMutex;
469 
470 public:
471 	CUPnPControlPoint(unsigned short udpPort);
472 	~CUPnPControlPoint();
473 	void Subscribe(CUPnPService &service);
474 	void Unsubscribe(CUPnPService &service);
475 	bool AddPortMappings(
476 		std::vector<CUPnPPortMapping> &upnpPortMapping);
477 	bool DeletePortMappings(
478 		std::vector<CUPnPPortMapping> &upnpPortMapping);
479 
480 	UpnpClient_Handle GetUPnPClientHandle()	const
481 		{ return m_UPnPClientHandle; }
482 
483 	bool GetIGWDeviceDetected() const
484 		{ return m_IGWDeviceDetected; }
485 	void SetIGWDeviceDetected(bool b)
486 		{ m_IGWDeviceDetected = b; }
487 	bool WanServiceDetected() const
488 		{ return !m_ServiceMap.empty(); }
489 	void SetWanService(CUPnPService *service)
490 		{ m_WanService = service; }
491 
492 	// Callback function
493 	static int Callback(
494 #if UPNP_VERSION >= 10800
495 		Upnp_EventType_e EventType,
496 		const void *Event,
497 		void *Cookie);
498 #else
499 		Upnp_EventType EventType,
500 		void* Event,
501 		void* Cookie);
502 #endif
503 
504 private:
505 	void OnEventReceived(
506 		const std::string &Sid,
507 		int EventKey,
508 		IXML_Document *ChangedVariables);
509 	void AddRootDevice(
510 		IXML_Element *rootDevice,
511 		const std::string &urlBase,
512 		const char *location,
513 		int expires);
514 	void RemoveRootDevice(
515 		const char *udn);
516 	void RefreshPortMappings();
517 	bool PrivateAddPortMapping(
518 		CUPnPPortMapping &upnpPortMapping);
519 	bool PrivateDeletePortMapping(
520 		CUPnPPortMapping &upnpPortMapping);
521 };
522 
523 
524 #endif /* AMULE_UPNP_H */
525 
526 // File_checked_for_headers
527