Commit c6e34683 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Implement IPv6 multicast output interface selection (closes #491)

parent 069e052f
...@@ -343,11 +343,11 @@ static int OpenUDP( vlc_object_t * p_this ) ...@@ -343,11 +343,11 @@ static int OpenUDP( vlc_object_t * p_this )
#if defined (WIN32) || defined (UNDER_CE) #if defined (WIN32) || defined (UNDER_CE)
else else
{ {
typedef DWORD (CALLBACK * GETBESTINTERFACE) ( IPAddr, PDWORD ); typedef DWORD (CALLBACK * GETBESTINTERFACE) ( IPAddr, PDWORD );
typedef DWORD (CALLBACK * GETIPADDRTABLE) ( PMIB_IPADDRTABLE, PULONG, BOOL ); typedef DWORD (CALLBACK * GETIPADDRTABLE) ( PMIB_IPADDRTABLE, PULONG, BOOL );
GETBESTINTERFACE OurGetBestInterface; GETBESTINTERFACE OurGetBestInterface;
GETIPADDRTABLE OurGetIpAddrTable; GETIPADDRTABLE OurGetIpAddrTable;
HINSTANCE hiphlpapi = LoadLibrary(_T("Iphlpapi.dll")); HINSTANCE hiphlpapi = LoadLibrary(_T("Iphlpapi.dll"));
DWORD i_index; DWORD i_index;
......
...@@ -34,23 +34,17 @@ ...@@ -34,23 +34,17 @@
#include <errno.h> #include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef WIN32 #ifdef WIN32
# include <winsock2.h> # include <winsock2.h>
# include <ws2tcpip.h> # include <ws2tcpip.h>
#elif !defined( SYS_BEOS ) && !defined( SYS_NTO ) # define if_nametoindex( str ) atoi( str )
#else
# include <sys/types.h>
# include <unistd.h>
# include <netdb.h> /* hostent ... */ # include <netdb.h> /* hostent ... */
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <net/if.h>
#endif #endif
#include "network.h" #include "network.h"
...@@ -312,9 +306,7 @@ static int OpenUDP( vlc_object_t * p_this ) ...@@ -312,9 +306,7 @@ static int OpenUDP( vlc_object_t * p_this )
if( *psz_server_addr ) if( *psz_server_addr )
{ {
int ttl = p_socket->i_ttl; int ttl;
if( ttl <= 0 )
ttl = config_GetInt( p_this, "ttl" );
/* Build socket for remote connection */ /* Build socket for remote connection */
if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 ) if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
...@@ -334,9 +326,12 @@ static int OpenUDP( vlc_object_t * p_this ) ...@@ -334,9 +326,12 @@ static int OpenUDP( vlc_object_t * p_this )
} }
/* Set the time-to-live */ /* Set the time-to-live */
ttl = p_socket->i_ttl;
if( ttl <= 0 )
ttl = config_GetInt( p_this, "ttl" );
if( ttl > 0 ) if( ttl > 0 )
{ {
#if defined( WIN32 ) || defined( HAVE_IF_NAMETOINDEX )
if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) ) if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
{ {
if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
...@@ -347,7 +342,6 @@ static int OpenUDP( vlc_object_t * p_this ) ...@@ -347,7 +342,6 @@ static int OpenUDP( vlc_object_t * p_this )
} }
} }
else else
#endif
{ {
if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_UNICAST_HOPS, if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
(void *)&ttl, sizeof( ttl ) ) < 0 ) (void *)&ttl, sizeof( ttl ) ) < 0 )
...@@ -357,6 +351,36 @@ static int OpenUDP( vlc_object_t * p_this ) ...@@ -357,6 +351,36 @@ static int OpenUDP( vlc_object_t * p_this )
} }
} }
} }
/* Set multicast output interface */
if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
{
char *psz_mif = config_GetPsz( p_this, "miface" );
if( psz_mif != NULL )
{
int intf = if_nametoindex( psz_mif );
free( psz_mif );
if( intf != 0 )
{
if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&intf, sizeof( intf ) ) < 0 )
{
msg_Err( p_this, "%s as multicast interface: %s",
psz_mif, strerror(errno) );
close( i_handle );
return 0;
}
}
else
{
msg_Err( p_this, "%s: bad IPv6 interface spefication",
psz_mif );
close( i_handle );
return 0;
}
}
}
} }
p_socket->i_handle = i_handle; p_socket->i_handle = i_handle;
......
/***************************************************************************** /*****************************************************************************
* libvlc.h: main libvlc header * libvlc.h: main libvlc header
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2005 VideoLAN (Centrale Réseaux) and its contributors * Copyright (C) 1998-2006 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Vincent Seguin <seguin@via.ecp.fr> * Authors: Vincent Seguin <seguin@via.ecp.fr>
...@@ -366,7 +366,7 @@ static char *ppsz_clock_descriptions[] = ...@@ -366,7 +366,7 @@ static char *ppsz_clock_descriptions[] =
#define SERVER_PORT_TEXT N_("UDP port") #define SERVER_PORT_TEXT N_("UDP port")
#define SERVER_PORT_LONGTEXT N_( \ #define SERVER_PORT_LONGTEXT N_( \
"This is the port used for UDP streams. By default, we chose 1234.") "This is the port used for UDP streams. 1234 by default.")
#define MTU_TEXT N_("MTU of the network interface") #define MTU_TEXT N_("MTU of the network interface")
#define MTU_LONGTEXT N_( \ #define MTU_LONGTEXT N_( \
...@@ -378,11 +378,16 @@ static char *ppsz_clock_descriptions[] = ...@@ -378,11 +378,16 @@ static char *ppsz_clock_descriptions[] =
"Specify the hop limit (TTL) of the multicast packets sent by " \ "Specify the hop limit (TTL) of the multicast packets sent by " \
"the stream output.") "the stream output.")
#define MIFACE_TEXT N_("Multicast output interface") #define MIFACE_TEXT N_("IPv6 multicast output interface")
#define MIFACE_LONGTEXT N_( \ #define MIFACE_LONGTEXT N_( \
"Indicate here the multicast output interface. " \ "Indicate here the multicast output interface. " \
"This overrides the routing table.") "This overrides the routing table.")
#define MIFACE_ADDR_TEXT N_("IPv4 multicast output interface address")
#define MIFACE_ADDR_LONGTEXT N_( \
"Specify the IPv4 address of the networking interface. " \
"This overrides the routing table.")
#define INPUT_PROGRAM_TEXT N_("Program to select") #define INPUT_PROGRAM_TEXT N_("Program to select")
#define INPUT_PROGRAM_LONGTEXT N_( \ #define INPUT_PROGRAM_LONGTEXT N_( \
"Choose the program to select by giving its Service ID.\n" \ "Choose the program to select by giving its Service ID.\n" \
...@@ -1328,7 +1333,8 @@ vlc_module_begin(); ...@@ -1328,7 +1333,8 @@ vlc_module_begin();
add_module( "access_output", "sout access", NULL, NULL, add_module( "access_output", "sout access", NULL, NULL,
ACCESS_OUTPUT_TEXT, ACCESS_OUTPUT_LONGTEXT, VLC_TRUE ); ACCESS_OUTPUT_TEXT, ACCESS_OUTPUT_LONGTEXT, VLC_TRUE );
add_integer( "ttl", 1, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_TRUE ); add_integer( "ttl", 1, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_TRUE );
add_string( "miface-addr", NULL, NULL, MIFACE_TEXT, MIFACE_LONGTEXT, VLC_TRUE ); add_string( "miface", NULL, NULL, MIFACE_TEXT, MIFACE_LONGTEXT, VLC_TRUE );
add_string( "miface-addr", NULL, NULL, MIFACE_ADDR_TEXT, MIFACE_ADDR_LONGTEXT, VLC_TRUE );
set_subcategory( SUBCAT_SOUT_PACKETIZER ); set_subcategory( SUBCAT_SOUT_PACKETIZER );
add_module( "packetizer","packetizer", NULL, NULL, add_module( "packetizer","packetizer", NULL, NULL,
......
/***************************************************************************** /*****************************************************************************
* udp.c: * udp.c:
***************************************************************************** *****************************************************************************
* Copyright (C) 2004-2005 the VideoLAN team * Copyright (C) 2004-2006 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Laurent Aimar <fenrir@videolan.org> * Authors: Laurent Aimar <fenrir@videolan.org>
...@@ -30,15 +30,9 @@ ...@@ -30,15 +30,9 @@
#include <errno.h> #include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>
#endif #endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "network.h" #include "network.h"
...@@ -50,6 +44,10 @@ ...@@ -50,6 +44,10 @@
# define IP_ADD_MEMBERSHIP 5 # define IP_ADD_MEMBERSHIP 5
# endif # endif
# define EAFNOSUPPORT WSAEAFNOSUPPORT # define EAFNOSUPPORT WSAEAFNOSUPPORT
# define if_nametoindex( str ) atoi( str )
#else
# include <unistd.h>
# include <net/if.h>
#endif #endif
#ifndef SOL_IP #ifndef SOL_IP
...@@ -109,42 +107,60 @@ static int net_SetMcastHopLimit( vlc_object_t *p_this, ...@@ -109,42 +107,60 @@ static int net_SetMcastHopLimit( vlc_object_t *p_this,
} }
static int net_SetMcastSource( vlc_object_t *p_this, static int net_SetMcastIface( vlc_object_t *p_this,
int fd, int family, const char *str ) int fd, int family, const char *str )
{ {
#ifndef SYS_BEOS
switch( family ) switch( family )
{ {
#ifndef SYS_BEOS
case AF_INET: case AF_INET:
{ {
struct in_addr addr; struct in_addr addr;
if( inet_pton( AF_INET, str, &addr) <= 0 ) if( inet_pton( AF_INET, str, &addr) <= 0 )
{ {
msg_Err( p_this, "Invalid multicast interface %s", msg_Err( p_this, "Invalid multicast interface %s", str );
str );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_IF, &addr, if( setsockopt( fd, SOL_IP, IP_MULTICAST_IF, &addr,
sizeof( addr ) ) < 0 ) sizeof( addr ) ) < 0 )
{ {
msg_Dbg( p_this, "Cannot set multicast interface (%s)", msg_Err( p_this, "Cannot use %s as multicast interface: %s",
strerror(errno) ); strerror(errno) );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
break; break;
} }
#endif /* SYS_BEOS */
#ifdef IPV6_MULTICAST_IF #ifdef IPV6_MULTICAST_IF
/* FIXME: TODO */ case AF_INET6:
{
int scope = if_nametoindex( str );
if( scope == 0 )
{
msg_Err( p_this, "Invalid multicast interface %s", str );
return VLC_EGENERIC;
}
if( setsockopt( fd, SOL_IPV6, IPV6_MULTICAST_IF,
&scope, sizeof( scope ) ) < 0 )
{
msg_Err( p_this, "Cannot use %s as multicast interface: %s",
str, strerror( errno ) );
return VLC_EGENERIC;
}
break;
}
#endif #endif
default: default:
msg_Warn( p_this, "%s", strerror( EAFNOSUPPORT ) ); msg_Warn( p_this, "%s", strerror( EAFNOSUPPORT ) );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
#endif
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -183,7 +199,7 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, ...@@ -183,7 +199,7 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
{ {
int fd; int fd;
char *psz_mif_addr; char *psz_mif;
fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype, fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol ); ptr->ai_protocol );
...@@ -212,11 +228,12 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, ...@@ -212,11 +228,12 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
if( i_hlim > 0 ) if( i_hlim > 0 )
net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim ); net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim );
psz_mif_addr = config_GetPsz( p_this, "miface-addr" ); psz_mif = config_GetPsz( p_this, (ptr->ai_family != AF_INET)
if( psz_mif_addr != NULL ) ? "miface" : "miface-addr" );
if( psz_mif != NULL )
{ {
net_SetMcastSource( p_this, fd, ptr->ai_family, psz_mif_addr ); net_SetMcastIface( p_this, fd, ptr->ai_family, psz_mif );
free( psz_mif_addr ); free( psz_mif );
} }
if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 ) if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment