325e1251c0a245b86aaf660fb8ff9d5ce37d0dd6
[vlc.git] / modules / services_discovery / upnp.hpp
1 /*****************************************************************************
2  * upnp.hpp :  UPnP discovery module (libupnp) header
3  *****************************************************************************
4  * Copyright (C) 2004-2018 VLC authors and VideoLAN
5  *
6  * Authors: Rémi Denis-Courmont <rem # videolan.org> (original plugin)
7  *          Christian Henz <henz # c-lab.de>
8  *          Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
9  *          Hugo Beauzée-Luyssen <hugo@beauzee.fr>
10  *          Shaleen Jain <shaleen@jain.sh>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vector>
32 #include <string>
33 #include <memory>
34
35 #ifdef _WIN32
36 #include <windows.h>
37 #include <wincrypt.h>
38 #endif
39 #include <upnp/upnp.h>
40 #include <upnp/upnptools.h>
41
42 #include <vlc_common.h>
43 #include <vlc_url.h>
44
45 #if UPNP_VERSION < 10800
46 typedef void* UpnpEventPtr;
47 #else
48 typedef const void* UpnpEventPtr;
49 #endif
50
51 namespace SD
52 {
53     class MediaServerList;
54 }
55
56 /*
57  * libUpnp allows only one instance per process, so we have to share one for
58  * both SD & Access module
59  * Since the callback is bound to the UpnpClient_Handle, we have to register
60  * a wrapper callback, in order for the access module to be able to initialize
61  * libUpnp first.
62  * When a SD wishes to use libUpnp, it will provide its own callback, that the
63  * wrapper will forward.
64  * This way, we always have a register callback & a client handle.
65  */
66 class UpnpInstanceWrapper
67 {
68 public:
69     class Listener
70     {
71         public:
72         virtual ~Listener() {}
73         virtual int onEvent( Upnp_EventType event_type,
74                              UpnpEventPtr p_event,
75                              void* p_user_data ) = 0;
76     };
77
78 private:
79     static UpnpInstanceWrapper* s_instance;
80     static vlc_mutex_t s_lock;
81     UpnpClient_Handle m_handle;
82     int m_refcount;
83     typedef std::shared_ptr<Listener> ListenerPtr;
84     typedef std::vector<ListenerPtr> Listeners;
85     static Listeners s_listeners;
86
87 public:
88     // This increases the refcount before returning the instance
89     static UpnpInstanceWrapper* get( vlc_object_t* p_obj );
90     void release();
91     UpnpClient_Handle handle() const;
92     void addListener(ListenerPtr listener);
93     void removeListener(ListenerPtr listener);
94
95 private:
96     static int Callback( Upnp_EventType event_type, UpnpEventPtr p_event, void* p_user_data );
97
98     UpnpInstanceWrapper();
99     ~UpnpInstanceWrapper();
100 };
101
102 namespace SD
103 {
104
105 struct MediaServerDesc
106 {
107     MediaServerDesc( const std::string& udn, const std::string& fName,
108                     const std::string& loc, const std::string& iconUrl );
109     ~MediaServerDesc();
110     std::string UDN;
111     std::string friendlyName;
112     std::string location;
113     std::string iconUrl;
114     input_item_t* inputItem;
115     bool isSatIp;
116     std::string satIpHost;
117 };
118
119
120 class MediaServerList : public UpnpInstanceWrapper::Listener
121 {
122 public:
123
124     MediaServerList( services_discovery_t* p_sd );
125     ~MediaServerList();
126
127     bool addServer(MediaServerDesc *desc );
128     void removeServer(const std::string &udn );
129     MediaServerDesc* getServer( const std::string& udn );
130     int onEvent( Upnp_EventType event_type,
131                  UpnpEventPtr p_event,
132                  void* p_user_data ) override;
133
134 private:
135     void parseNewServer( IXML_Document* doc, const std::string& location );
136     std::string getIconURL( IXML_Element* p_device_elem , const char* psz_base_url );
137
138 private:
139     services_discovery_t* const m_sd;
140     std::vector<MediaServerDesc*> m_list;
141 };
142
143 }
144
145 namespace Access
146 {
147
148 class Upnp_i11e_cb
149 {
150 public:
151     Upnp_i11e_cb( Upnp_FunPtr callback, void *cookie );
152     ~Upnp_i11e_cb();
153     void waitAndRelease( void );
154     static int run( Upnp_EventType, UpnpEventPtr, void *);
155
156 private:
157     vlc_sem_t       m_sem;
158     vlc_mutex_t     m_lock;
159     int             m_refCount;
160     Upnp_FunPtr     m_callback;
161     void*           m_cookie;
162 };
163
164 class MediaServer
165 {
166 public:
167     MediaServer( stream_t* p_access, input_item_node_t* node );
168     ~MediaServer();
169     bool fetchContents();
170
171 private:
172     MediaServer(const MediaServer&);
173     MediaServer& operator=(const MediaServer&);
174
175     bool addContainer( IXML_Element* containerElement );
176     bool addItem( IXML_Element* itemElement );
177
178     IXML_Document* _browseAction(const char*, const char*,
179             const char*, const char*, const char* );
180     static int sendActionCb( Upnp_EventType, UpnpEventPtr, void *);
181
182 private:
183     char* m_psz_root;
184     char* m_psz_objectId;
185     stream_t* m_access;
186     input_item_node_t* m_node;
187 };
188
189 }