[vlc-devel] [PATCH 2/3] upnp: move UpnpInstanceWrapper to upnp-wrapper

Hugo Beauzée-Luyssen hugo at beauzee.fr
Wed Jun 27 13:58:42 CEST 2018


On Wed, Jun 27, 2018, at 4:51 AM, Shaleen Jain wrote:
> On Wed, 2018-06-27 at 16:57 +0530, Shaleen Jain wrote:
> > On Wed, 2018-06-27 at 03:50 -0700, Hugo Beauzée-Luyssen wrote:
> > > 
> > > On Mon, Jun 25, 2018, at 6:49 AM, Shaleen Jain wrote:
> > > > Move out UpnpInstanceWrapper into its own file
> > > > since it no longer has any dependencies on existing
> > > > modules and allow other modules to get references to it.
> > > > Move as well as the various helper functions that are
> > > > directly required by the UpnpInstanceWrapper class
> > > > and inline them for a small performance gain.
> > > > 
> > > > ---
> > > >  modules/services_discovery/Makefile.am      |   4 +-
> > > >  modules/services_discovery/upnp-wrapper.cpp | 156 ++++++++
> > > >  modules/services_discovery/upnp-wrapper.hpp | 349
> > > > ++++++++++++++++++
> > > >  modules/services_discovery/upnp.cpp         | 378 --------------
> > > > --
> > > > ----
> > > >  modules/services_discovery/upnp.hpp         |  66 +---
> > > >  5 files changed, 509 insertions(+), 444 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..e1f167a5a7
> > > > --- /dev/null
> > > > +++ b/modules/services_discovery/upnp-wrapper.cpp
> > > > @@ -0,0 +1,156 @@
> > > > +/
> > > > *****************************************************************
> > > > **
> > > > **********
> > > > + * 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( std::move(listener) );
> > > > +    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..e8952a152a
> > > > --- /dev/null
> > > > +++ b/modules/services_discovery/upnp-wrapper.hpp
> > > > @@ -0,0 +1,349 @@
> > > > +/
> > > > *****************************************************************
> > > > **
> > > > **********
> > > > + * upnp-wrapper.cpp :  UPnP Instance Wrapper class header
> > > 
> > > Copy paste mistake :)
> > 
> > Well spotted
> > > 
> > > > + 
> > > > *****************************************************************
> > > > **
> > > > **********
> > > > + * Copyright © 2004-2018 VLC authors and VideoLAN
> > > > + * $Id$
> > > 
> > > Feel free to remove the $Id$ svn relicate
> > 
> > Okay.
> > > 
> > > > + *
> > > > + * 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
> > > 
> > > Although it was previously included from upnp.h, config.h should be
> > > included from the source rather than the header.
> > > 
> > > It's also fine to fix this in a separated commit though, since
> > > you're
> > > just moving code around in this one
> > > 
> > 
> > Okay.
> Actually config.h is required by the various vlc headers like
> vlc_common.h and vlc_input.h which are included by both upnp-
> wrapper.hpp and upnp.c/hpp. And needs to at the top of the include
> hierarchy.
> > 
> > > > +
> > > > +#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 fc81a847a2..26d9206b5f 100644
> > > > --- a/modules/services_discovery/upnp.cpp
> > > > +++ b/modules/services_discovery/upnp.cpp
> > > > @@ -39,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
> > > >  */
> > > > @@ -94,10 +70,6 @@ struct access_sys_t
> > > >      UpnpInstanceWrapper* p_upnp;
> > > >  };
> > > >  
> > > > -UpnpInstanceWrapper* UpnpInstanceWrapper::s_instance;
> > > > -UpnpInstanceWrapper::Listeners UpnpInstanceWrapper::s_listeners;
> > > > -vlc_mutex_t UpnpInstanceWrapper::s_lock = VLC_STATIC_MUTEX;
> > > > -
> > > >  /*
> > > >   * VLC callback prototypes
> > > >   */
> > > > @@ -141,30 +113,6 @@ vlc_module_begin()
> > > >      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
> > > >   */
> > > > @@ -1309,329 +1257,3 @@ static void Close( vlc_object_t* p_this )
> > > >  }
> > > >  
> > > >  }
> > > > -
> > > > -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)
> > > > -{
> > > > -    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() )
> > > > -        return;
> > > > -    s_listeners.push_back( std::move(listener) );
> > > > -    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() )
> > > > -        return;
> > > > -
> > > > -    s_listeners.erase( iter );
> > > > -    vlc_mutex_unlock( &s_lock );
> > > > -}
> > > > diff --git a/modules/services_discovery/upnp.hpp b/modules/
> > > > services_discovery/upnp.hpp
> > > > index 8c13265fc8..164b1cbc69 100644
> > > > --- a/modules/services_discovery/upnp.hpp
> > > > +++ b/modules/services_discovery/upnp.hpp
> > > > @@ -24,82 +24,18 @@
> > > >   * 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>
> > > > -#include <memory>
> > > >  
> > > >  #ifdef _WIN32
> > > >  #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:
> > > > -    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();
> > > > -};
> > > > -
> > > >  namespace SD
> > > >  {
> > > >  
> > > > -- 
> > > > 2.18.0
> > > > _______________________________________________
> > > > vlc-devel mailing list
> > > > To unsubscribe or modify your subscription options:
> > > > https://mailman.videolan.org/listinfo/vlc-devel
> > > 
> > > Nitpick aside, LGTM
> > > 
> -- 
> Regards,
> Shaleen Jain
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

config.h should be the first included header, so it's usually included from the source file. As for vlc_common.h, it's quite often the 2nd header included, from the source file, right after config.h

Same results can be achieved by including config.h from the header, but it usually ends up breaking when a new file using that header gets added.

-- 
  Hugo Beauzée-Luyssen
  hugo at beauzee.fr



More information about the vlc-devel mailing list