[vlc-devel] [PATCH] upnp: lookup the best interface to use libupnp with
Steve Lhomme
robux4 at videolabs.io
Fri Jun 17 13:50:24 CEST 2016
libupnp cannot handle more than one interface/IP at a time, so we need to make
sure we use an appropriate one.
--
replaces https://patches.videolan.org/patch/13719/ with better lookup
---
modules/services_discovery/upnp.cpp | 115 +++++++++++++++++++++++++++++++++++-
1 file changed, 113 insertions(+), 2 deletions(-)
diff --git a/modules/services_discovery/upnp.cpp b/modules/services_discovery/upnp.cpp
index ff86868..a428333 100644
--- a/modules/services_discovery/upnp.cpp
+++ b/modules/services_discovery/upnp.cpp
@@ -32,6 +32,7 @@
#include <vlc_plugin.h>
#include <vlc_interrupt.h>
#include <vlc_services_discovery.h>
+#include <vlc_charset.h>
#include <assert.h>
#include <limits.h>
@@ -1253,6 +1254,114 @@ UpnpInstanceWrapper::~UpnpInstanceWrapper()
UpnpFinish();
}
+static char *getIpv4ForMulticast()
+{
+# ifdef _WIN32
+# if !VLC_WINSTORE_APP || _WIN32_WINNT >= 0x0A00
+ ULONG addrSize;
+ IP_ADAPTER_UNICAST_ADDRESS *p_best_ip = NULL;
+ wchar_t psz_uri[32];
+ DWORD strSize;
+ const ULONG queryFlags = GAA_FLAG_INCLUDE_GATEWAYS|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME;
+
+ ULONG erraddr = GetAdaptersAddresses( AF_INET, queryFlags, NULL, NULL, &addrSize );
+ if (erraddr != ERROR_BUFFER_OVERFLOW)
+ return NULL;
+ IP_ADAPTER_ADDRESSES *addresses = (IP_ADAPTER_ADDRESSES*) malloc(addrSize);
+ if (addresses == NULL)
+ return NULL;
+ erraddr = GetAdaptersAddresses( AF_INET, queryFlags, NULL, addresses, &addrSize );
+ if (erraddr != ERROR_SUCCESS)
+ goto err;
+
+ unsigned long i_broadcast_ip = inet_addr("239.255.255.250");
+ IP_ADAPTER_ADDRESSES *p_adapter = addresses;
+
+ /* find one with multicast capabilities */
+ while (p_adapter != NULL)
+ {
+ if (p_adapter->OperStatus == IfOperStatusUp && p_adapter->FirstGatewayAddress && p_adapter->Ipv4Enabled)
+ {
+ /* make sure it supports 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)
+ break;
+ p_multicast = p_multicast->Next;
+ }
+ 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;
+
+ p_adapter = addresses;
+ /* find any with IPv4 */
+ while (p_adapter != NULL)
+ {
+ if (p_adapter->OperStatus == IfOperStatusUp && p_adapter->FirstGatewayAddress && p_adapter->Ipv4Enabled)
+ {
+ /* 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 );
+ }
+
+err:
+ free(addresses);
+# endif /* GetAdaptersAddresses available */
+# endif /* _WIN32 */
+ return NULL;
+}
+
UpnpInstanceWrapper *UpnpInstanceWrapper::get(vlc_object_t *p_obj, services_discovery_t *p_sd)
{
SD::MediaServerList *p_server_list = NULL;
@@ -1280,8 +1389,10 @@ UpnpInstanceWrapper *UpnpInstanceWrapper::get(vlc_object_t *p_obj, services_disc
free( psz_miface );
#else
/* If UpnpInit2 isnt available, initialize on first IPv4-capable interface */
- int i_res = UpnpInit( 0, 0 );
- #endif
+ 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 ) );
--
2.7.2.windows.1
More information about the vlc-devel
mailing list