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

Hugo Beauzée-Luyssen hugo at beauzee.fr
Wed Jun 27 12:50:32 CEST 2018



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 :)

> + 
> *****************************************************************************
> + * Copyright © 2004-2018 VLC authors and VideoLAN
> + * $Id$

Feel free to remove the $Id$ svn relicate

> + *
> + * 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

> +
> +#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

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



More information about the vlc-devel mailing list