[vlc-devel] [PATCH] upnp: refactor out UpnpInstanceWrapper
Shaleen Jain
shaleen at jain.sh
Mon Jun 25 12:38:36 CEST 2018
Hi,
Thanks for your review.
On Mon, 2018-06-25 at 02:52 -0700, Hugo Beauzée-Luyssen wrote:
> Hi,
>
> I agree on the principle, however it seems there's a lot of code
> that's moved around without any specific reason (specifically all the
> function described as "Helper functions" which could stay in the .cpp
> file, with a declaration if you really need to use them from the
> header)
The reason is the same as the refactor, so that another module can
leverage these functions without including upnp.cpp which does cause
module conflicts. I will move this out into a separate patch with the
reason.
> A few other renaming (for instance the Open/Close functions) are
> superfluous and make the patch harder to review IMHO.
>
> TL;DR: The idea is nice, but please split this patch in smaller units
I did get a feeling I should do that and have been working on splitting
the patch in the mean time. I'll post the new shorter patches soon.
>
> Regards,
>
> On Fri, Jun 22, 2018, at 7:03 AM, Shaleen Jain wrote:
> > Refactor out the UpnpInstanceWrapper singleton
> > class so that it is decoupled from any specific module
> > and can be used by other modules without them all
> > having to be in a single file, by introducing a
> > Listener interface that can be used by
> > modules to get callbacks from libupnp.
> > ---
> > v2: add missing copyright headers
> > ---
> > modules/services_discovery/Makefile.am | 4 +-
> > modules/services_discovery/upnp-wrapper.cpp | 158 +++++++
> > modules/services_discovery/upnp-wrapper.hpp | 349 ++++++++++++++
> > modules/services_discovery/upnp.cpp | 496 ++------------
> > ------
> > modules/services_discovery/upnp.hpp | 62 +--
> > 5 files changed, 562 insertions(+), 507 deletions(-)
> > create mode 100644 modules/services_discovery/upnp-wrapper.cpp
> > create mode 100644 modules/services_discovery/upnp-wrapper.hpp
> >
> > diff --git a/modules/services_discovery/Makefile.am b/modules/
> > services_discovery/Makefile.am
> > index 41c7871a29..f63df23b32 100644
> > --- a/modules/services_discovery/Makefile.am
> > +++ b/modules/services_discovery/Makefile.am
> > @@ -26,7 +26,9 @@ libmtp_plugin_la_LIBADD = $(MTP_LIBS)
> > EXTRA_LTLIBRARIES += libmtp_plugin.la
> > sd_LTLIBRARIES += $(LTLIBmtp)
> >
> > -libupnp_plugin_la_SOURCES = services_discovery/upnp.cpp
> > services_discovery/upnp.hpp
> > +libupnp_plugin_la_SOURCES = services_discovery/upnp.cpp
> > services_discovery/upnp.hpp \
> > + services_discovery/upnp-wrapper.hpp \
> > + services_discovery/upnp-wrapper.cpp
> > libupnp_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(UPNP_CFLAGS)
> > libupnp_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
> > libupnp_plugin_la_LIBADD = $(UPNP_LIBS)
> > diff --git a/modules/services_discovery/upnp-wrapper.cpp b/modules/
> > services_discovery/upnp-wrapper.cpp
> > new file mode 100644
> > index 0000000000..e542c22837
> > --- /dev/null
> > +++ b/modules/services_discovery/upnp-wrapper.cpp
> > @@ -0,0 +1,158 @@
> > +/
> > *******************************************************************
> > **********
> > + * upnp-wrapper.cpp : UPnP Instance Wrapper class
> > +
> > *******************************************************************
> > **********
> > + * Copyright © 2004-2018 VLC authors and VideoLAN
> > + * $Id$
> > + *
> > + * Authors: Rémi Denis-Courmont <rem # videolan.org> (original
> > plugin)
> > + * Christian Henz <henz # c-lab.de>
> > + * Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
> > + * Hugo Beauzée-Luyssen <hugo at beauzee.fr>
> > + * Shaleen Jain <shaleen at jain.sh>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify
> > it
> > + * under the terms of the GNU Lesser General Public License as
> > published by
> > + * the Free Software Foundation; either version 2.1 of the
> > License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General
> > Public
> > License
> > + * along with this program; if not, write to the Free Software
> > Foundation,
> > + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301,
> > USA.
> > +
> > *******************************************************************
> > **********/
> > +
> > +#include "upnp-wrapper.hpp"
> > +
> > +UpnpInstanceWrapper* UpnpInstanceWrapper::s_instance;
> > +UpnpInstanceWrapper::Listeners UpnpInstanceWrapper::s_listeners;
> > +vlc_mutex_t UpnpInstanceWrapper::s_lock = VLC_STATIC_MUTEX;
> > +
> > +
> > +UpnpInstanceWrapper::UpnpInstanceWrapper()
> > + : m_handle( -1 )
> > + , m_refcount( 0 )
> > +{
> > +}
> > +
> > +UpnpInstanceWrapper::~UpnpInstanceWrapper()
> > +{
> > + UpnpUnRegisterClient( m_handle );
> > + UpnpFinish();
> > +}
> > +
> > +
> > +UpnpInstanceWrapper *UpnpInstanceWrapper::get(vlc_object_t *p_obj)
> > +{
> > + vlc_mutex_locker lock( &s_lock );
> > + if ( s_instance == NULL )
> > + {
> > + UpnpInstanceWrapper* instance = new(std::nothrow)
> > UpnpInstanceWrapper;
> > + if ( unlikely( !instance ) )
> > + {
> > + return NULL;
> > + }
> > +
> > + #ifdef UPNP_ENABLE_IPV6
> > + char* psz_miface = var_InheritString( p_obj, "miface" );
> > + if (psz_miface == NULL)
> > + psz_miface = getPreferedAdapter();
> > + msg_Info( p_obj, "Initializing libupnp on '%s'
> > interface",
> > psz_miface ? psz_miface : "default" );
> > + int i_res = UpnpInit2( psz_miface, 0 );
> > + free( psz_miface );
> > + #else
> > + /* If UpnpInit2 isnt available, initialize on first IPv4-
> > capable interface */
> > + char *psz_hostip = getIpv4ForMulticast();
> > + int i_res = UpnpInit( psz_hostip, 0 );
> > + free(psz_hostip);
> > + #endif /* UPNP_ENABLE_IPV6 */
> > + if( i_res != UPNP_E_SUCCESS )
> > + {
> > + msg_Err( p_obj, "Initialization failed: %s",
> > UpnpGetErrorMessage( i_res ) );
> > + delete instance;
> > + return NULL;
> > + }
> > +
> > + ixmlRelaxParser( 1 );
> > +
> > + /* Register a control point */
> > + i_res = UpnpRegisterClient( Callback, instance, &instance-
> > > m_handle );
> >
> > + if( i_res != UPNP_E_SUCCESS )
> > + {
> > + msg_Err( p_obj, "Client registration failed: %s",
> > UpnpGetErrorMessage( i_res ) );
> > + delete instance;
> > + return NULL;
> > + }
> > +
> > + /* libupnp does not treat a maximum content length of 0
> > as
> > unlimited
> > + * until 64dedf (~ pupnp v1.6.7) and provides no sane way
> > to
> > discriminate
> > + * between versions */
> > + if( (i_res = UpnpSetMaxContentLength( INT_MAX )) !=
> > UPNP_E_SUCCESS )
> > + {
> > + msg_Err( p_obj, "Failed to set maximum content length:
> > %s",
> > + UpnpGetErrorMessage( i_res ));
> > + delete instance;
> > + return NULL;
> > + }
> > + s_instance = instance;
> > + }
> > + s_instance->m_refcount++;
> > + return s_instance;
> > +}
> > +
> > +void UpnpInstanceWrapper::release()
> > +{
> > + UpnpInstanceWrapper *p_delete = NULL;
> > + vlc_mutex_lock( &s_lock );
> > + if (--s_instance->m_refcount == 0)
> > + {
> > + p_delete = s_instance;
> > + s_instance = NULL;
> > + }
> > + vlc_mutex_unlock( &s_lock );
> > + delete p_delete;
> > +}
> > +
> > +UpnpClient_Handle UpnpInstanceWrapper::handle() const
> > +{
> > + return m_handle;
> > +}
> > +
> > +int UpnpInstanceWrapper::Callback(Upnp_EventType event_type,
> > UpnpEventPtr p_event, void *p_user_data)
> > +{
> > + for (Listeners::iterator iter = s_listeners.begin(); iter !=
> > s_listeners.end(); ++iter)
> > + {
> > + (*iter)->onEvent(event_type, p_event, p_user_data);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +void UpnpInstanceWrapper::addListener(ListenerPtr listener)
> > +{
> > + vlc_mutex_lock( &s_lock );
> > + if ( std::find( s_listeners.begin(), s_listeners.end(),
> > listener) !
> > = s_listeners.end() )
> > + {
> > + vlc_mutex_unlock( &s_lock );
> > + return;
> > + }
> > + s_listeners.push_back( listener );
>
> You can use std::move to avoid a copy
Okay.
>
> > + vlc_mutex_unlock( &s_lock );
> > +}
> > +
> > +void UpnpInstanceWrapper::removeListener(ListenerPtr listener)
> > +{
> > + vlc_mutex_lock( &s_lock );
> > + Listeners::iterator iter = std::find( s_listeners.begin(),
> > s_listeners.end(), listener );
> > + if ( iter == s_listeners.end() )
> > + {
> > + vlc_mutex_unlock( &s_lock );
> > + return;
> > + }
> > +
> > + s_listeners.erase( iter );
> > + vlc_mutex_unlock( &s_lock );
> > +}
> > diff --git a/modules/services_discovery/upnp-wrapper.hpp b/modules/
> > services_discovery/upnp-wrapper.hpp
> > new file mode 100644
> > index 0000000000..af3e208dd3
> > --- /dev/null
> > +++ b/modules/services_discovery/upnp-wrapper.hpp
> > @@ -0,0 +1,349 @@
> > +/
> > *******************************************************************
> > **********
> > + * upnp-wrapper.cpp : UPnP Instance Wrapper class header
> > +
> > *******************************************************************
> > **********
> > + * Copyright © 2004-2018 VLC authors and VideoLAN
> > + * $Id$
> > + *
> > + * Authors: Rémi Denis-Courmont <rem # videolan.org> (original
> > plugin)
> > + * Christian Henz <henz # c-lab.de>
> > + * Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
> > + * Hugo Beauzée-Luyssen <hugo at beauzee.fr>
> > + * Shaleen Jain <shaleen at jain.sh>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > modify
> > it
> > + * under the terms of the GNU Lesser General Public License as
> > published by
> > + * the Free Software Foundation; either version 2.1 of the
> > License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General
> > Public
> > License
> > + * along with this program; if not, write to the Free Software
> > Foundation,
> > + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301,
> > USA.
> > +
> > *******************************************************************
> > **********/
> > +
> > +#ifdef HAVE_CONFIG_H
> > +# include "config.h"
> > +#endif
> > +
> > +#include <memory>
> > +#include <vector>
> > +#include <algorithm>
> > +#include <assert.h>
> > +
> > +#include <upnp/upnp.h>
> > +#include <upnp/upnptools.h>
> > +
> > +#include <vlc_common.h>
> > +
> > +#if UPNP_VERSION < 10800
> > +typedef void* UpnpEventPtr;
> > +#else
> > +typedef const void* UpnpEventPtr;
> > +#endif
> > +
> > +/**
> > + * libUpnp allows only one instance per process, so we create a
> > wrapper
> > + * class around it that acts and behaves as a singleton. Letting
> > us get
> > + * multiple references to it but only ever having a single
> > instance in
> > memory.
> > + * At the same time we let any module wishing to get a callback
> > from
> > the library
> > + * to register a UpnpInstanceWrapper::Listener to get the
> > Listener#onEvent()
> > + * callback without having any hard dependencies.
> > + */
> > +class UpnpInstanceWrapper
> > +{
> > +public:
> > + class Listener
> > + {
> > + public:
> > + virtual ~Listener() {}
> > + virtual int onEvent( Upnp_EventType event_type,
> > + UpnpEventPtr p_event,
> > + void* p_user_data ) = 0;
> > + };
> > +
> > +private:
> > + static UpnpInstanceWrapper* s_instance;
> > + static vlc_mutex_t s_lock;
> > + UpnpClient_Handle m_handle;
> > + int m_refcount;
> > + typedef std::shared_ptr<Listener> ListenerPtr;
> > + typedef std::vector<ListenerPtr> Listeners;
> > + static Listeners s_listeners;
> > +
> > +public:
> > + // This increases the refcount before returning the instance
> > + static UpnpInstanceWrapper* get( vlc_object_t* p_obj );
> > + void release();
> > + UpnpClient_Handle handle() const;
> > + void addListener(ListenerPtr listener);
> > + void removeListener(ListenerPtr listener);
> > +
> > +private:
> > + static int Callback( Upnp_EventType event_type, UpnpEventPtr
> > p_event, void* p_user_data );
> > +
> > + UpnpInstanceWrapper();
> > + ~UpnpInstanceWrapper();
> > +};
> > +
> > +// **************************
> > +// Helper functions
> > +// **************************
> > +
> > +#if UPNP_VERSION < 10623
> > +/*
> > + * Compat functions and typedefs for libupnp prior to 1.8
> > + */
> > +
> > +typedef Upnp_Discovery UpnpDiscovery;
> > +typedef Upnp_Action_Complete UpnpActionComplete;
> > +
> > +inline const char* UpnpDiscovery_get_Location_cstr( const
> > UpnpDiscovery* p_discovery )
> > +{
> > + return p_discovery->Location;
> > +}
> > +
> > +inline const char* UpnpDiscovery_get_DeviceID_cstr( const
> > UpnpDiscovery* p_discovery )
> > +{
> > + return p_discovery->DeviceId;
> > +}
> > +
> > +inline static IXML_Document* UpnpActionComplete_get_ActionResult(
> > const
> > UpnpActionComplete* p_result )
> > +{
> > + return p_result->ActionResult;
> > +}
> > +#endif
> > +
> > +/*
> > + * Returns the value of a child element, or NULL on error
> > + */
> > +inline const char* xml_getChildElementValue( IXML_Element*
> > p_parent,
> > + const char* psz_tag_name )
> > +{
> > + assert( p_parent );
> > + assert( psz_tag_name );
> > +
> > + IXML_NodeList* p_node_list;
> > + p_node_list = ixmlElement_getElementsByTagName( p_parent,
> > psz_tag_name );
> > + if ( !p_node_list ) return NULL;
> > +
> > + IXML_Node* p_element = ixmlNodeList_item( p_node_list, 0 );
> > + ixmlNodeList_free( p_node_list );
> > + if ( !p_element ) return NULL;
> > +
> > + IXML_Node* p_text_node = ixmlNode_getFirstChild( p_element );
> > + if ( !p_text_node ) return NULL;
> > +
> > + return ixmlNode_getNodeValue( p_text_node );
> > +}
> > +
> > +#ifdef _WIN32
> > +
> > +inline IP_ADAPTER_MULTICAST_ADDRESS*
> > getMulticastAddress(IP_ADAPTER_ADDRESSES* p_adapter)
> > +{
> > + const unsigned long i_broadcast_ip =
> > inet_addr("239.255.255.250");
> > +
> > + IP_ADAPTER_MULTICAST_ADDRESS *p_multicast = p_adapter-
> > > FirstMulticastAddress;
> >
> > + while (p_multicast != NULL)
> > + {
> > + if (((struct sockaddr_in *)p_multicast-
> > >Address.lpSockaddr)-
> > > sin_addr.S_un.S_addr == i_broadcast_ip)
> >
> > + return p_multicast;
> > + p_multicast = p_multicast->Next;
> > + }
> > + return NULL;
> > +}
> > +
> > +inline bool isAdapterSuitable(IP_ADAPTER_ADDRESSES* p_adapter,
> > bool
> > ipv6)
> > +{
> > + if ( p_adapter->OperStatus != IfOperStatusUp )
> > + return false;
> > + if (p_adapter->Length == sizeof(IP_ADAPTER_ADDRESSES_XP))
> > + {
> > + IP_ADAPTER_ADDRESSES_XP* p_adapter_xp =
> > reinterpret_cast<IP_ADAPTER_ADDRESSES_XP*>( p_adapter );
> > + // On Windows Server 2003 and Windows XP, this member is
> > zero
> > if IPv4 is not available on the interface.
> > + if (ipv6)
> > + return p_adapter_xp->Ipv6IfIndex != 0;
> > + return p_adapter_xp->IfIndex != 0;
> > + }
> > + IP_ADAPTER_ADDRESSES_LH* p_adapter_lh =
> > reinterpret_cast<IP_ADAPTER_ADDRESSES_LH*>( p_adapter );
> > + if (p_adapter_lh->FirstGatewayAddress == NULL)
> > + return false;
> > + if (ipv6)
> > + return p_adapter_lh->Ipv6Enabled;
> > + return p_adapter_lh->Ipv4Enabled;
> > +}
> > +
> > +inline IP_ADAPTER_ADDRESSES* ListAdapters()
> > +{
> > + ULONG addrSize;
> > + const ULONG queryFlags = GAA_FLAG_INCLUDE_GATEWAYS|
> > GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER;
> > + IP_ADAPTER_ADDRESSES* addresses = NULL;
> > + HRESULT hr;
> > +
> > + /**
> > + * https://msdn.microsoft.com/en-us/library/aa365915.aspx
> > + *
> > + * The recommended method of calling the GetAdaptersAddresses
> > function is to pre-allocate a
> > + * 15KB working buffer pointed to by the AdapterAddresses
> > parameter. On typical computers,
> > + * this dramatically reduces the chances that the
> > GetAdaptersAddresses function returns
> > + * ERROR_BUFFER_OVERFLOW, which would require calling
> > GetAdaptersAddresses function multiple
> > + * times. The example code illustrates this method of use.
> > + */
> > + addrSize = 15 * 1024;
> > + do
> > + {
> > + free(addresses);
> > + addresses = (IP_ADAPTER_ADDRESSES*)malloc( addrSize );
> > + if (addresses == NULL)
> > + return NULL;
> > + hr = GetAdaptersAddresses(AF_UNSPEC, queryFlags, NULL,
> > addresses, &addrSize);
> > + } while (hr == ERROR_BUFFER_OVERFLOW);
> > + if (hr != NO_ERROR) {
> > + free(addresses);
> > + return NULL;
> > + }
> > + return addresses;
> > +}
> > +
> > +#ifdef UPNP_ENABLE_IPV6
> > +
> > +inline char* getPreferedAdapter()
> > +{
> > + IP_ADAPTER_ADDRESSES *p_adapter, *addresses;
> > +
> > + addresses = ListAdapters();
> > + if (addresses == NULL)
> > + return NULL;
> > +
> > + /* find one with multicast capabilities */
> > + p_adapter = addresses;
> > + while (p_adapter != NULL)
> > + {
> > + if (isAdapterSuitable( p_adapter, true ))
> > + {
> > + /* make sure it supports 239.255.255.250 */
> > + IP_ADAPTER_MULTICAST_ADDRESS *p_multicast =
> > getMulticastAddress( p_adapter );
> > + if (p_multicast != NULL)
> > + {
> > + char* res = FromWide( p_adapter->FriendlyName );
> > + free( addresses );
> > + return res;
> > + }
> > + }
> > + p_adapter = p_adapter->Next;
> > + }
> > + free(addresses);
> > + return NULL;
> > +}
> > +
> > +#else
> > +
> > +inline char *getIpv4ForMulticast()
> > +{
> > + IP_ADAPTER_UNICAST_ADDRESS *p_best_ip = NULL;
> > + wchar_t psz_uri[32];
> > + DWORD strSize;
> > + IP_ADAPTER_ADDRESSES *p_adapter, *addresses;
> > +
> > + addresses = ListAdapters();
> > + if (addresses == NULL)
> > + return NULL;
> > +
> > + /* find one with multicast capabilities */
> > + p_adapter = addresses;
> > + while (p_adapter != NULL)
> > + {
> > + if (isAdapterSuitable( p_adapter, false ))
> > + {
> > + /* make sure it supports 239.255.255.250 */
> > + IP_ADAPTER_MULTICAST_ADDRESS *p_multicast =
> > getMulticastAddress( p_adapter );
> > + if (p_multicast != NULL)
> > + {
> > + /* get an IPv4 address */
> > + IP_ADAPTER_UNICAST_ADDRESS *p_unicast = p_adapter-
> > > FirstUnicastAddress;
> >
> > + while (p_unicast != NULL)
> > + {
> > + strSize = sizeof( psz_uri ) / sizeof( wchar_t
> > );
> > + if( WSAAddressToString( p_unicast-
> > > Address.lpSockaddr,
> >
> > + p_unicast-
> > > Address.iSockaddrLength,
> >
> > + NULL, psz_uri,
> > &strSize )
> > == 0 )
> > + {
> > + if ( p_best_ip == NULL ||
> > + p_best_ip->ValidLifetime > p_unicast-
> > > ValidLifetime )
> >
> > + {
> > + p_best_ip = p_unicast;
> > + }
> > + }
> > + p_unicast = p_unicast->Next;
> > + }
> > + }
> > + }
> > + p_adapter = p_adapter->Next;
> > + }
> > +
> > + if ( p_best_ip != NULL )
> > + goto done;
> > +
> > + /* find any with IPv4 */
> > + p_adapter = addresses;
> > + while (p_adapter != NULL)
> > + {
> > + if (isAdapterSuitable(p_adapter, false))
> > + {
> > + /* get an IPv4 address */
> > + IP_ADAPTER_UNICAST_ADDRESS *p_unicast = p_adapter-
> > > FirstUnicastAddress;
> >
> > + while (p_unicast != NULL)
> > + {
> > + strSize = sizeof( psz_uri ) / sizeof( wchar_t );
> > + if( WSAAddressToString( p_unicast-
> > >Address.lpSockaddr,
> > + p_unicast-
> > > Address.iSockaddrLength,
> >
> > + NULL, psz_uri, &strSize )
> > ==
> > 0 )
> > + {
> > + if ( p_best_ip == NULL ||
> > + p_best_ip->ValidLifetime > p_unicast-
> > > ValidLifetime )
> >
> > + {
> > + p_best_ip = p_unicast;
> > + }
> > + }
> > + p_unicast = p_unicast->Next;
> > + }
> > + }
> > + p_adapter = p_adapter->Next;
> > + }
> > +
> > +done:
> > + if (p_best_ip != NULL)
> > + {
> > + strSize = sizeof( psz_uri ) / sizeof( wchar_t );
> > + WSAAddressToString( p_best_ip->Address.lpSockaddr,
> > + p_best_ip->Address.iSockaddrLength,
> > + NULL, psz_uri, &strSize );
> > + free(addresses);
> > + return FromWide( psz_uri );
> > + }
> > + free(addresses);
> > + return NULL;
> > +}
> > +#endif /* UPNP_ENABLE_IPV6 */
> > +#else /* _WIN32 */
> > +
> > +#ifdef UPNP_ENABLE_IPV6
> > +
> > +inline char *getPreferedAdapter()
> > +{
> > + return NULL;
> > +}
> > +
> > +#else
> > +
> > +inline char *getIpv4ForMulticast()
> > +{
> > + return NULL;
> > +}
> > +
> > +#endif
> > +
> > +#endif /* _WIN32 */
> > diff --git a/modules/services_discovery/upnp.cpp b/modules/
> > services_discovery/upnp.cpp
> > index 7455ceb299..f4085293ee 100644
> > --- a/modules/services_discovery/upnp.cpp
> > +++ b/modules/services_discovery/upnp.cpp
> > @@ -1,13 +1,14 @@
> > /
> > *******************************************************************
> > **********
> > * upnp.cpp : UPnP discovery module (libupnp)
> >
> > *******************************************************************
> > **********
> > - * Copyright (C) 2004-2016 VLC authors and VideoLAN
> > + * Copyright (C) 2004-2018 VLC authors and VideoLAN
> > * $Id$
> > *
> > * Authors: Rémi Denis-Courmont <rem # videolan.org> (original
> > plugin)
> > * Christian Henz <henz # c-lab.de>
> > * Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
> > * Hugo Beauzée-Luyssen <hugo at beauzee.fr>
> > + * Shaleen Jain <shaleen at jain.sh>
> > *
> > * This program is free software; you can redistribute it and/or
> > modify
> > it
> > * under the terms of the GNU Lesser General Public License as
> > published by
> > @@ -38,30 +39,6 @@
> > #include <set>
> > #include <string>
> >
> > -#if UPNP_VERSION < 10623
> > -/*
> > - * Compat functions and typedefs for libupnp prior to 1.8
> > - */
> > -
> > -typedef Upnp_Discovery UpnpDiscovery;
> > -typedef Upnp_Action_Complete UpnpActionComplete;
> > -
> > -static const char* UpnpDiscovery_get_Location_cstr( const
> > UpnpDiscovery* p_discovery )
> > -{
> > - return p_discovery->Location;
> > -}
> > -
> > -static const char* UpnpDiscovery_get_DeviceID_cstr( const
> > UpnpDiscovery* p_discovery )
> > -{
> > - return p_discovery->DeviceId;
> > -}
> > -
> > -static IXML_Document* UpnpActionComplete_get_ActionResult( const
> > UpnpActionComplete* p_result )
> > -{
> > - return p_result->ActionResult;
> > -}
> > -#endif
> > -
> > /*
> > * Constants
> > */
> > @@ -81,34 +58,31 @@ static const char *const
> > ppsz_readible_satip_channel_lists[] = {
> > /*
> > * VLC handle
> > */
> > -struct services_discovery_sys_t
> > +struct access_sys_t
> > {
> > UpnpInstanceWrapper* p_upnp;
> > - vlc_thread_t thread;
> > };
> >
> > -struct access_sys_t
> > +struct services_discovery_sys_t
> > {
> > - UpnpInstanceWrapper* p_upnp;
> > + UpnpInstanceWrapper* p_upnp;
> > + vlc_thread_t thread;
> > + std::shared_ptr<UpnpInstanceWrapper::Listener> p_server_list;
> > };
> >
> > -UpnpInstanceWrapper* UpnpInstanceWrapper::s_instance;
> > -vlc_mutex_t UpnpInstanceWrapper::s_lock = VLC_STATIC_MUTEX;
> > -SD::MediaServerList *UpnpInstanceWrapper::p_server_list = NULL;
> > -
> > /*
> > * VLC callback prototypes
> > */
> > namespace SD
> > {
> > - static int Open( vlc_object_t* );
> > - static void Close( vlc_object_t* );
> > + static int OpenSD( vlc_object_t* );
> > + static void CloseSD( vlc_object_t* );
> > }
> >
> > namespace Access
> > {
> > - static int Open( vlc_object_t* );
> > - static void Close( vlc_object_t* );
> > + static int OpenAccess( vlc_object_t* );
> > + static void CloseAccess( vlc_object_t* );
> > }
> >
> > VLC_SD_PROBE_HELPER( "upnp", N_("Universal Plug'n'Play"),
> > SD_CAT_LAN )
> > @@ -122,7 +96,7 @@ vlc_module_begin()
> > set_category( CAT_PLAYLIST );
> > set_subcategory( SUBCAT_PLAYLIST_SD );
> > set_capability( "services_discovery", 0 );
> > - set_callbacks( SD::Open, SD::Close );
> > + set_callbacks( SD::OpenSD, SD::CloseSD );
> >
> > add_string( "satip-channelist", "ASTRA_19_2E",
> > SATIP_CHANNEL_LIST,
> > SATIP_CHANNEL_LIST, false )
> > @@ -133,36 +107,12 @@ vlc_module_begin()
> > add_submodule()
> > set_category( CAT_INPUT )
> > set_subcategory( SUBCAT_INPUT_ACCESS )
> > - set_callbacks( Access::Open, Access::Close )
> > + set_callbacks( Access::OpenAccess, Access::CloseAccess )
> > set_capability( "access", 0 )
> >
> > VLC_SD_PROBE_SUBMODULE
> > vlc_module_end()
> >
> > -
> > -/*
> > - * Returns the value of a child element, or NULL on error
> > - */
> > -const char* xml_getChildElementValue( IXML_Element* p_parent,
> > - const char* psz_tag_name )
> > -{
> > - assert( p_parent );
> > - assert( psz_tag_name );
> > -
> > - IXML_NodeList* p_node_list;
> > - p_node_list = ixmlElement_getElementsByTagName( p_parent,
> > psz_tag_name );
> > - if ( !p_node_list ) return NULL;
> > -
> > - IXML_Node* p_element = ixmlNodeList_item( p_node_list, 0 );
> > - ixmlNodeList_free( p_node_list );
> > - if ( !p_element ) return NULL;
> > -
> > - IXML_Node* p_text_node = ixmlNode_getFirstChild( p_element );
> > - if ( !p_text_node ) return NULL;
> > -
> > - return ixmlNode_getNodeValue( p_text_node );
> > -}
> > -
> > /*
> > * Extracts the result document from a SOAP response
> > */
> > @@ -227,7 +177,7 @@ SearchThread( void *p_data )
> >
> > /* Search for media servers */
> > int i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
> > - MEDIA_SERVER_DEVICE_TYPE, p_sys->p_upnp );
> > + MEDIA_SERVER_DEVICE_TYPE, MEDIA_SERVER_DEVICE_TYPE );
> > if( i_res != UPNP_E_SUCCESS )
> > {
> > msg_Err( p_sd, "Error sending search request: %s",
> > UpnpGetErrorMessage( i_res ) );
> > @@ -236,7 +186,7 @@ SearchThread( void *p_data )
> >
> > /* Search for Sat Ip servers*/
> > i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
> > - SATIP_SERVER_DEVICE_TYPE, p_sys->p_upnp );
> > + SATIP_SERVER_DEVICE_TYPE, MEDIA_SERVER_DEVICE_TYPE );
> > if( i_res != UPNP_E_SUCCESS )
> > msg_Err( p_sd, "Error sending search request: %s",
> > UpnpGetErrorMessage( i_res ) );
> > return NULL;
> > @@ -245,7 +195,7 @@ SearchThread( void *p_data )
> > /*
> > * Initializes UPNP instance.
> > */
> > -static int Open( vlc_object_t *p_this )
> > +static int OpenSD( vlc_object_t *p_this )
> > {
> > services_discovery_t *p_sd = ( services_discovery_t* )p_this;
> > services_discovery_sys_t *p_sys = ( services_discovery_sys_t
> > * )
> > @@ -256,20 +206,30 @@ static int Open( vlc_object_t *p_this )
> >
> > p_sd->description = _("Universal Plug'n'Play");
> >
> > - p_sys->p_upnp = UpnpInstanceWrapper::get( p_this, p_sd );
> > + p_sys->p_upnp = UpnpInstanceWrapper::get( p_this );
> > if ( !p_sys->p_upnp )
> > {
> > free(p_sys);
> > return VLC_EGENERIC;
> > }
> >
> > + p_sys->p_server_list =
> > std::shared_ptr<UpnpInstanceWrapper::Listener>
> > + ( new(std::nothrow)
>
> I'd rather use std::make_shared here
Thanks for the reference. I'll make the change.
>
> > SD::MediaServerList( p_sd ));
> > + if ( unlikely( p_sys->p_server_list == NULL ) )
> > + {
> > + msg_Err( p_sd, "Failed to create a MediaServerList");
> > + return VLC_EGENERIC;
> > + }
> > + p_sys->p_upnp->addListener( p_sys->p_server_list );
> > +
> > /* XXX: Contrary to what the libupnp doc states,
> > UpnpSearchAsync is
> > * blocking (select() and send() are called). Therefore, Call
> > * UpnpSearchAsync from an other thread. */
> > if ( vlc_clone( &p_sys->thread, SearchThread, p_this,
> > VLC_THREAD_PRIORITY_LOW ) )
> > {
> > - p_sys->p_upnp->release( true );
> > + p_sys->p_upnp->removeListener( p_sys->p_server_list );
> > + p_sys->p_upnp->release();
> > free(p_sys);
> > return VLC_EGENERIC;
> > }
> > @@ -280,13 +240,14 @@ static int Open( vlc_object_t *p_this )
> > /*
> > * Releases resources.
> > */
> > -static void Close( vlc_object_t *p_this )
> > +static void CloseSD( vlc_object_t *p_this )
> > {
> > services_discovery_t *p_sd = ( services_discovery_t* )p_this;
> > services_discovery_sys_t *p_sys =
> > reinterpret_cast<services_discovery_sys_t *>( p_sd->p_sys );
> >
> > vlc_join( p_sys->thread, NULL );
> > - p_sys->p_upnp->release( true );
> > + p_sys->p_upnp->removeListener( p_sys->p_server_list );
> > + p_sys->p_upnp->release();
> > free( p_sys );
> > }
> >
> > @@ -702,8 +663,11 @@ void MediaServerList::removeServer( const
> > std::string& udn )
> > /*
> > * Handles servers listing UPnP events
> > */
> > -int MediaServerList::Callback( Upnp_EventType event_type,
> > UpnpEventPtr
> > p_event )
> > +int MediaServerList::onEvent( Upnp_EventType event_type,
> > UpnpEventPtr
> > p_event, void* p_user_data )
> > {
> > + if (p_user_data != MEDIA_SERVER_DEVICE_TYPE)
> > + return 0;
> > +
> > switch( event_type )
> > {
> > case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
> > @@ -716,23 +680,14 @@ int MediaServerList::Callback(
> > Upnp_EventType
> > event_type, UpnpEventPtr p_event )
> > int i_res;
> > i_res =
> > UpnpDownloadXmlDoc( UpnpDiscovery_get_Location_cstr( p_discovery
> > ),
> > &p_description_doc );
> >
> > - MediaServerList *self =
> > UpnpInstanceWrapper::lockMediaServerList();
> > - if ( !self )
> > - {
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > - return UPNP_E_CANCELED;
> > - }
> > -
> > if ( i_res != UPNP_E_SUCCESS )
> > {
> > - msg_Warn( self->m_sd, "Could not download device
> > description! "
> > + msg_Warn( m_sd, "Could not download device
> > description! "
> > "Fetching data from %s failed: %s",
> >
> > UpnpDiscovery_get_Location_cstr( p_discovery ),
> > UpnpGetErrorMessage( i_res ) );
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > return i_res;
> > }
> > - self->parseNewServer( p_description_doc,
> > UpnpDiscovery_get_Location_cstr( p_discovery ) );
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > + parseNewServer( p_description_doc,
> > UpnpDiscovery_get_Location_cstr( p_discovery ) );
> > ixmlDocument_free( p_description_doc );
> > }
> > break;
> > @@ -740,29 +695,19 @@ int MediaServerList::Callback(
> > Upnp_EventType
> > event_type, UpnpEventPtr p_event )
> > case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
> > {
> > const UpnpDiscovery* p_discovery = ( const
> > UpnpDiscovery* )p_event;
> > -
> > - MediaServerList *self =
> > UpnpInstanceWrapper::lockMediaServerList();
> > - if ( self )
> > - self-
> > > removeServer( UpnpDiscovery_get_DeviceID_cstr( p_discovery ) );
> >
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > + removeServer( UpnpDiscovery_get_DeviceID_cstr( p_discovery
> > ) );
> > }
> > break;
> >
> > case UPNP_EVENT_SUBSCRIBE_COMPLETE:
> > {
> > - MediaServerList *self =
> > UpnpInstanceWrapper::lockMediaServerList();
> > - if ( self )
> > - msg_Warn( self->m_sd, "subscription complete" );
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > + msg_Warn( m_sd, "subscription complete" );
> > }
> > break;
> >
> > case UPNP_DISCOVERY_SEARCH_TIMEOUT:
> > {
> > - MediaServerList *self =
> > UpnpInstanceWrapper::lockMediaServerList();
> > - if ( self )
> > - msg_Warn( self->m_sd, "search timeout" );
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > + msg_Warn( m_sd, "search timeout" );
> > }
> > break;
> >
> > @@ -774,10 +719,7 @@ int MediaServerList::Callback( Upnp_EventType
> > event_type, UpnpEventPtr p_event )
> >
> > default:
> > {
> > - MediaServerList *self =
> > UpnpInstanceWrapper::lockMediaServerList();
> > - if ( self )
> > - msg_Err( self->m_sd, "Unhandled event, please report
> > ( type=%d )", event_type );
> > - UpnpInstanceWrapper::unlockMediaServerList();
> > + msg_Err( m_sd, "Unhandled event, please report ( type=%d
> > )",
> > event_type );
> > }
> > break;
> > }
> > @@ -1285,7 +1227,7 @@ static int ReadDirectory( stream_t
> > *p_access,
> > input_item_node_t* p_node )
> > return VLC_SUCCESS;
> > }
> >
> > -static int Open( vlc_object_t *p_this )
> > +static int OpenAccess( vlc_object_t *p_this )
> > {
> > stream_t* p_access = (stream_t*)p_this;
> > access_sys_t* p_sys = new(std::nothrow) access_sys_t;
> > @@ -1293,7 +1235,7 @@ static int Open( vlc_object_t *p_this )
> > return VLC_ENOMEM;
> >
> > p_access->p_sys = p_sys;
> > - p_sys->p_upnp = UpnpInstanceWrapper::get( p_this, NULL );
> > + p_sys->p_upnp = UpnpInstanceWrapper::get( p_this);
> > if ( !p_sys->p_upnp )
> > {
> > delete p_sys;
> > @@ -1306,361 +1248,13 @@ static int Open( vlc_object_t *p_this )
> > return VLC_SUCCESS;
> > }
> >
> > -static void Close( vlc_object_t* p_this )
> > +static void CloseAccess( vlc_object_t* p_this )
> > {
> > stream_t* p_access = (stream_t*)p_this;
> > access_sys_t *sys = (access_sys_t *)p_access->p_sys;
> >
> > - sys->p_upnp->release( false );
> > + sys->p_upnp->release();
> > delete sys;
> > }
> >
> > }
> > -
> > -UpnpInstanceWrapper::UpnpInstanceWrapper()
> > - : m_handle( -1 )
> > - , m_refcount( 0 )
> > -{
> > -}
> > -
> > -UpnpInstanceWrapper::~UpnpInstanceWrapper()
> > -{
> > - UpnpUnRegisterClient( m_handle );
> > - UpnpFinish();
> > -}
> > -
> > -#ifdef _WIN32
> > -
> > -static IP_ADAPTER_MULTICAST_ADDRESS*
> > getMulticastAddress(IP_ADAPTER_ADDRESSES* p_adapter)
> > -{
> > - const unsigned long i_broadcast_ip =
> > inet_addr("239.255.255.250");
> > -
> > - IP_ADAPTER_MULTICAST_ADDRESS *p_multicast = p_adapter-
> > > FirstMulticastAddress;
> >
> > - while (p_multicast != NULL)
> > - {
> > - if (((struct sockaddr_in *)p_multicast-
> > >Address.lpSockaddr)-
> > > sin_addr.S_un.S_addr == i_broadcast_ip)
> >
> > - return p_multicast;
> > - p_multicast = p_multicast->Next;
> > - }
> > - return NULL;
> > -}
> > -
> > -static bool isAdapterSuitable(IP_ADAPTER_ADDRESSES* p_adapter,
> > bool
> > ipv6)
> > -{
> > - if ( p_adapter->OperStatus != IfOperStatusUp )
> > - return false;
> > - if (p_adapter->Length == sizeof(IP_ADAPTER_ADDRESSES_XP))
> > - {
> > - IP_ADAPTER_ADDRESSES_XP* p_adapter_xp =
> > reinterpret_cast<IP_ADAPTER_ADDRESSES_XP*>( p_adapter );
> > - // On Windows Server 2003 and Windows XP, this member is
> > zero
> > if IPv4 is not available on the interface.
> > - if (ipv6)
> > - return p_adapter_xp->Ipv6IfIndex != 0;
> > - return p_adapter_xp->IfIndex != 0;
> > - }
> > - IP_ADAPTER_ADDRESSES_LH* p_adapter_lh =
> > reinterpret_cast<IP_ADAPTER_ADDRESSES_LH*>( p_adapter );
> > - if (p_adapter_lh->FirstGatewayAddress == NULL)
> > - return false;
> > - if (ipv6)
> > - return p_adapter_lh->Ipv6Enabled;
> > - return p_adapter_lh->Ipv4Enabled;
> > -}
> > -
> > -static IP_ADAPTER_ADDRESSES* ListAdapters()
> > -{
> > - ULONG addrSize;
> > - const ULONG queryFlags = GAA_FLAG_INCLUDE_GATEWAYS|
> > GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER;
> > - IP_ADAPTER_ADDRESSES* addresses = NULL;
> > - HRESULT hr;
> > -
> > - /**
> > - * https://msdn.microsoft.com/en-us/library/aa365915.aspx
> > - *
> > - * The recommended method of calling the GetAdaptersAddresses
> > function is to pre-allocate a
> > - * 15KB working buffer pointed to by the AdapterAddresses
> > parameter. On typical computers,
> > - * this dramatically reduces the chances that the
> > GetAdaptersAddresses function returns
> > - * ERROR_BUFFER_OVERFLOW, which would require calling
> > GetAdaptersAddresses function multiple
> > - * times. The example code illustrates this method of use.
> > - */
> > - addrSize = 15 * 1024;
> > - do
> > - {
> > - free(addresses);
> > - addresses = (IP_ADAPTER_ADDRESSES*)malloc( addrSize );
> > - if (addresses == NULL)
> > - return NULL;
> > - hr = GetAdaptersAddresses(AF_UNSPEC, queryFlags, NULL,
> > addresses, &addrSize);
> > - } while (hr == ERROR_BUFFER_OVERFLOW);
> > - if (hr != NO_ERROR) {
> > - free(addresses);
> > - return NULL;
> > - }
> > - return addresses;
> > -}
> > -
> > -#ifdef UPNP_ENABLE_IPV6
> > -
> > -static char* getPreferedAdapter()
> > -{
> > - IP_ADAPTER_ADDRESSES *p_adapter, *addresses;
> > -
> > - addresses = ListAdapters();
> > - if (addresses == NULL)
> > - return NULL;
> > -
> > - /* find one with multicast capabilities */
> > - p_adapter = addresses;
> > - while (p_adapter != NULL)
> > - {
> > - if (isAdapterSuitable( p_adapter, true ))
> > - {
> > - /* make sure it supports 239.255.255.250 */
> > - IP_ADAPTER_MULTICAST_ADDRESS *p_multicast =
> > getMulticastAddress( p_adapter );
> > - if (p_multicast != NULL)
> > - {
> > - char* res = FromWide( p_adapter->FriendlyName );
> > - free( addresses );
> > - return res;
> > - }
> > - }
> > - p_adapter = p_adapter->Next;
> > - }
> > - free(addresses);
> > - return NULL;
> > -}
> > -
> > -#else
> > -
> > -static char *getIpv4ForMulticast()
> > -{
> > - IP_ADAPTER_UNICAST_ADDRESS *p_best_ip = NULL;
> > - wchar_t psz_uri[32];
> > - DWORD strSize;
> > - IP_ADAPTER_ADDRESSES *p_adapter, *addresses;
> > -
> > - addresses = ListAdapters();
> > - if (addresses == NULL)
> > - return NULL;
> > -
> > - /* find one with multicast capabilities */
> > - p_adapter = addresses;
> > - while (p_adapter != NULL)
> > - {
> > - if (isAdapterSuitable( p_adapter, false ))
> > - {
> > - /* make sure it supports 239.255.255.250 */
> > - IP_ADAPTER_MULTICAST_ADDRESS *p_multicast =
> > getMulticastAddress( p_adapter );
> > - if (p_multicast != NULL)
> > - {
> > - /* get an IPv4 address */
> > - IP_ADAPTER_UNICAST_ADDRESS *p_unicast = p_adapter-
> > > FirstUnicastAddress;
> >
> > - while (p_unicast != NULL)
> > - {
> > - strSize = sizeof( psz_uri ) / sizeof( wchar_t
> > );
> > - if( WSAAddressToString( p_unicast-
> > > Address.lpSockaddr,
> >
> > - p_unicast-
> > > Address.iSockaddrLength,
> >
> > - NULL, psz_uri,
> > &strSize )
> > == 0 )
> > - {
> > - if ( p_best_ip == NULL ||
> > - p_best_ip->ValidLifetime > p_unicast-
> > > ValidLifetime )
> >
> > - {
> > - p_best_ip = p_unicast;
> > - }
> > - }
> > - p_unicast = p_unicast->Next;
> > - }
> > - }
> > - }
> > - p_adapter = p_adapter->Next;
> > - }
> > -
> > - if ( p_best_ip != NULL )
> > - goto done;
> > -
> > - /* find any with IPv4 */
> > - p_adapter = addresses;
> > - while (p_adapter != NULL)
> > - {
> > - if (isAdapterSuitable(p_adapter, false))
> > - {
> > - /* get an IPv4 address */
> > - IP_ADAPTER_UNICAST_ADDRESS *p_unicast = p_adapter-
> > > FirstUnicastAddress;
> >
> > - while (p_unicast != NULL)
> > - {
> > - strSize = sizeof( psz_uri ) / sizeof( wchar_t );
> > - if( WSAAddressToString( p_unicast-
> > >Address.lpSockaddr,
> > - p_unicast-
> > > Address.iSockaddrLength,
> >
> > - NULL, psz_uri, &strSize )
> > ==
> > 0 )
> > - {
> > - if ( p_best_ip == NULL ||
> > - p_best_ip->ValidLifetime > p_unicast-
> > > ValidLifetime )
> >
> > - {
> > - p_best_ip = p_unicast;
> > - }
> > - }
> > - p_unicast = p_unicast->Next;
> > - }
> > - }
> > - p_adapter = p_adapter->Next;
> > - }
> > -
> > -done:
> > - if (p_best_ip != NULL)
> > - {
> > - strSize = sizeof( psz_uri ) / sizeof( wchar_t );
> > - WSAAddressToString( p_best_ip->Address.lpSockaddr,
> > - p_best_ip->Address.iSockaddrLength,
> > - NULL, psz_uri, &strSize );
> > - free(addresses);
> > - return FromWide( psz_uri );
> > - }
> > - free(addresses);
> > - return NULL;
> > -}
> > -#endif /* UPNP_ENABLE_IPV6 */
> > -#else /* _WIN32 */
> > -
> > -#ifdef UPNP_ENABLE_IPV6
> > -
> > -static char *getPreferedAdapter()
> > -{
> > - return NULL;
> > -}
> > -
> > -#else
> > -
> > -static char *getIpv4ForMulticast()
> > -{
> > - return NULL;
> > -}
> > -
> > -#endif
> > -
> > -#endif /* _WIN32 */
> > -
> > -UpnpInstanceWrapper *UpnpInstanceWrapper::get(vlc_object_t
> > *p_obj,
> > services_discovery_t *p_sd)
> > -{
> > - SD::MediaServerList *p_server_list = NULL;
> > - if (p_sd)
> > - {
> > - p_server_list = new(std::nothrow) SD::MediaServerList(
> > p_sd );
> > - if ( unlikely( p_server_list == NULL ) )
> > - {
> > - msg_Err( p_sd, "Failed to create a MediaServerList");
> > - return NULL;
> > - }
> > - }
> > -
> > - vlc_mutex_locker lock( &s_lock );
> > - if ( s_instance == NULL )
> > - {
> > - UpnpInstanceWrapper* instance = new(std::nothrow)
> > UpnpInstanceWrapper;
> > - if ( unlikely( !instance ) )
> > - {
> > - delete p_server_list;
> > - return NULL;
> > - }
> > -
> > - #ifdef UPNP_ENABLE_IPV6
> > - char* psz_miface = var_InheritString( p_obj, "miface" );
> > - if (psz_miface == NULL)
> > - psz_miface = getPreferedAdapter();
> > - msg_Info( p_obj, "Initializing libupnp on '%s'
> > interface",
> > psz_miface ? psz_miface : "default" );
> > - int i_res = UpnpInit2( psz_miface, 0 );
> > - free( psz_miface );
> > - #else
> > - /* If UpnpInit2 isnt available, initialize on first IPv4-
> > capable interface */
> > - char *psz_hostip = getIpv4ForMulticast();
> > - int i_res = UpnpInit( psz_hostip, 0 );
> > - free(psz_hostip);
> > - #endif /* UPNP_ENABLE_IPV6 */
> > - if( i_res != UPNP_E_SUCCESS )
> > - {
> > - msg_Err( p_obj, "Initialization failed: %s",
> > UpnpGetErrorMessage( i_res ) );
> > - delete instance;
> > - delete p_server_list;
> > - return NULL;
> > - }
> > -
> > - ixmlRelaxParser( 1 );
> > -
> > - /* Register a control point */
> > - i_res = UpnpRegisterClient( Callback, instance, &instance-
> > > m_handle );
> >
> > - if( i_res != UPNP_E_SUCCESS )
> > - {
> > - msg_Err( p_obj, "Client registration failed: %s",
> > UpnpGetErrorMessage( i_res ) );
> > - delete instance;
> > - delete p_server_list;
> > - return NULL;
> > - }
> > -
> > - /* libupnp does not treat a maximum content length of 0
> > as
> > unlimited
> > - * until 64dedf (~ pupnp v1.6.7) and provides no sane way
> > to
> > discriminate
> > - * between versions */
> > - if( (i_res = UpnpSetMaxContentLength( INT_MAX )) !=
> > UPNP_E_SUCCESS )
> > - {
> > - msg_Err( p_obj, "Failed to set maximum content length:
> > %s",
> > - UpnpGetErrorMessage( i_res ));
> > - delete instance;
> > - delete p_server_list;
> > - return NULL;
> > - }
> > - s_instance = instance;
> > - }
> > - s_instance->m_refcount++;
> > - // This assumes a single UPNP SD instance
> > - if (p_server_list != NULL)
> > - {
> > - assert(!UpnpInstanceWrapper::p_server_list);
> > - UpnpInstanceWrapper::p_server_list = p_server_list;
> > - }
> > - return s_instance;
> > -}
> > -
> > -void UpnpInstanceWrapper::release(bool isSd)
> > -{
> > - UpnpInstanceWrapper *p_delete = NULL;
> > - vlc_mutex_lock( &s_lock );
> > - if ( isSd )
> > - {
> > - delete UpnpInstanceWrapper::p_server_list;
> > - UpnpInstanceWrapper::p_server_list = NULL;
> > - }
> > - if (--s_instance->m_refcount == 0)
> > - {
> > - p_delete = s_instance;
> > - s_instance = NULL;
> > - }
> > - vlc_mutex_unlock( &s_lock );
> > - delete p_delete;
> > -}
> > -
> > -UpnpClient_Handle UpnpInstanceWrapper::handle() const
> > -{
> > - return m_handle;
> > -}
> > -
> > -int UpnpInstanceWrapper::Callback(Upnp_EventType event_type,
> > UpnpEventPtr p_event, void *p_user_data)
> > -{
> > - VLC_UNUSED(p_user_data);
> > - vlc_mutex_lock( &s_lock );
> > - if ( !UpnpInstanceWrapper::p_server_list )
> > - {
> > - vlc_mutex_unlock( &s_lock );
> > - /* no MediaServerList available (anymore), do nothing */
> > - return 0;
> > - }
> > - vlc_mutex_unlock( &s_lock );
> > - SD::MediaServerList::Callback( event_type, p_event );
> > - return 0;
> > -}
> > -
> > -SD::MediaServerList *UpnpInstanceWrapper::lockMediaServerList()
> > -{
> > - vlc_mutex_lock( &s_lock ); /* do not allow deleting the
> > p_server_list while using it */
> > - return UpnpInstanceWrapper::p_server_list;
> > -}
> > -
> > -void UpnpInstanceWrapper::unlockMediaServerList()
> > -{
> > - vlc_mutex_unlock( &s_lock );
> > -}
> > diff --git a/modules/services_discovery/upnp.hpp b/modules/
> > services_discovery/upnp.hpp
> > index 14286276db..a75c754879 100644
> > --- a/modules/services_discovery/upnp.hpp
> > +++ b/modules/services_discovery/upnp.hpp
> > @@ -1,13 +1,14 @@
> > /
> > *******************************************************************
> > **********
> > * upnp.hpp : UPnP discovery module (libupnp) header
> >
> > *******************************************************************
> > **********
> > - * Copyright (C) 2004-2016 VLC authors and VideoLAN
> > + * Copyright (C) 2004-2018 VLC authors and VideoLAN
> > * $Id$
> > *
> > * Authors: Rémi Denis-Courmont <rem # videolan.org> (original
> > plugin)
> > * Christian Henz <henz # c-lab.de>
> > * Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
> > * Hugo Beauzée-Luyssen <hugo at beauzee.fr>
> > + * Shaleen Jain <shaleen at jain.sh>
> > *
> > * This program is free software; you can redistribute it and/or
> > modify
> > it
> > * under the terms of the GNU Lesser General Public License as
> > published by
> > @@ -23,10 +24,7 @@
> > * along with this program; if not, write to the Free Software
> > Foundation,
> > * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301,
> > USA.
> >
> > *******************************************************************
> > **********/
> > -
> > -#ifdef HAVE_CONFIG_H
> > -# include "config.h"
> > -#endif
> > +#include "upnp-wrapper.hpp"
> >
> > #include <vector>
> > #include <string>
> > @@ -35,57 +33,9 @@
> > #include <windows.h>
> > #include <wincrypt.h>
> > #endif
> > -#include <upnp/upnp.h>
> > -#include <upnp/upnptools.h>
> >
> > -#include <vlc_common.h>
> > #include <vlc_url.h>
> >
> > -#if UPNP_VERSION < 10800
> > -typedef void* UpnpEventPtr;
> > -#else
> > -typedef const void* UpnpEventPtr;
> > -#endif
> > -
> > -namespace SD
> > -{
> > - class MediaServerList;
> > -}
> > -
> > -/*
> > - * libUpnp allows only one instance per process, so we have to
> > share
> > one for
> > - * both SD & Access module
> > - * Since the callback is bound to the UpnpClient_Handle, we have
> > to
> > register
> > - * a wrapper callback, in order for the access module to be able
> > to
> > initialize
> > - * libUpnp first.
> > - * When a SD wishes to use libUpnp, it will provide its own
> > callback,
> > that the
> > - * wrapper will forward.
> > - * This way, we always have a register callback & a client handle.
> > - */
> > -class UpnpInstanceWrapper
> > -{
> > -public:
> > - // This increases the refcount before returning the instance
> > - static UpnpInstanceWrapper* get(vlc_object_t* p_obj,
> > services_discovery_t *p_sd);
> > - void release(bool isSd);
> > - UpnpClient_Handle handle() const;
> > - static SD::MediaServerList *lockMediaServerList();
> > - static void unlockMediaServerList();
> > -
> > -private:
> > - static int Callback( Upnp_EventType event_type, UpnpEventPtr
> > p_event, void* p_user_data );
> > -
> > - UpnpInstanceWrapper();
> > - ~UpnpInstanceWrapper();
> > -
> > -private:
> > - static UpnpInstanceWrapper* s_instance;
> > - static vlc_mutex_t s_lock;
> > - UpnpClient_Handle m_handle;
> > - static SD::MediaServerList* p_server_list;
> > - int m_refcount;
> > -};
> > -
> > namespace SD
> > {
> >
> > @@ -104,7 +54,7 @@ struct MediaServerDesc
> > };
> >
> >
> > -class MediaServerList
> > +class MediaServerList : public UpnpInstanceWrapper::Listener
> > {
> > public:
> >
> > @@ -114,7 +64,9 @@ public:
> > bool addServer(MediaServerDesc *desc );
> > void removeServer(const std::string &udn );
> > MediaServerDesc* getServer( const std::string& udn );
> > - static int Callback( Upnp_EventType event_type, UpnpEventPtr
> > p_event );
> > + int onEvent(Upnp_EventType event_type,
> > + UpnpEventPtr p_event,
> > + void* p_user_data) override;
> >
> > private:
> > void parseNewServer( IXML_Document* doc, const std::string&
> > location );
> > --
> > 2.17.1
> >
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
>
>
--
Regards,
Shaleen Jain
More information about the vlc-devel
mailing list