*****************************************************************************/
#include <stdlib.h>
#include <string.h>
+
#include <vlc/vlc.h>
+#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
-#ifdef HAVE_ERRNO_H
-# include <errno.h>
-#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
# include <unistd.h>
#endif
-#if defined( UNDER_CE )
-# include <winsock.h>
-#elif defined( WIN32 )
+#if defined(WIN32) || defined(UNDER_CE)
+# if defined(UNDER_CE) && defined(sockaddr_storage)
+# undef sockaddr_storage
+# endif
# include <winsock2.h>
# include <ws2tcpip.h>
# define close closesocket
+# if defined(UNDER_CE)
+# undef IP_MULTICAST_TTL
+# define IP_MULTICAST_TTL 3
+# undef IP_ADD_MEMBERSHIP
+# define IP_ADD_MEMBERSHIP 5
+# endif
#else
# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
"Allows you to modify the default TCP connection timeout. This " \
"value should be set in millisecond units." )
+#define MIFACE_TEXT N_("Multicast output interface")
+#define MIFACE_LONGTEXT N_( \
+ "Indicate here the multicast output interface. " \
+ "This overrides the routing table.")
+
vlc_module_begin();
set_description( _("IPv4 network abstraction layer") );
set_capability( "network", 50 );
+ set_category( CAT_INPUT );
+ set_subcategory( SUBCAT_INPUT_ADVANCED );
set_callbacks( NetOpen, NULL );
add_integer( "ipv4-timeout", 5 * 1000, NULL, TIMEOUT_TEXT,
TIMEOUT_LONGTEXT, VLC_TRUE );
+ add_string( "miface-addr", NULL, NULL, MIFACE_TEXT, MIFACE_LONGTEXT, VLC_TRUE );
vlc_module_end();
/*****************************************************************************
* protocol */
if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 )
{
-#ifdef HAVE_ERRNO_H
- msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );
#else
- msg_Warn( p_this, "cannot create socket" );
+ msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
#endif
return( -1 );
}
if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %i)",
+ WSAGetLastError() );
+#else
msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
strerror(errno));
-#else
- msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
#endif
close( i_handle );
return( -1 );
}
+#ifdef SO_REUSEPORT
+ i_opt = 1;
+ if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEPORT,
+ (void *) &i_opt, sizeof( i_opt ) ) == -1 )
+ {
+ msg_Warn( p_this, "cannot configure socket (SO_REUSEPORT)" );
+ }
+#endif
+
/* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
* packet loss caused by scheduling problems */
i_opt = 0x80000;
#if !defined( SYS_BEOS )
if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Dbg( p_this, "cannot configure socket (SO_RCVBUF: %i)",
+ WSAGetLastError() );
+#else
msg_Dbg( p_this, "cannot configure socket (SO_RCVBUF: %s)",
strerror(errno));
-#else
- msg_Warn( p_this, "cannot configure socket (SO_RCVBUF)" );
#endif
}
#endif
i_opt_size = sizeof( i_opt );
if( getsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void*) &i_opt, &i_opt_size ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %i)",
+ WSAGetLastError() );
+#else
msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %s)",
strerror(errno) );
-#else
- msg_Warn( p_this, "cannot query socket (SO_RCVBUF)" );
#endif
}
else if( i_opt < 0x80000 )
/* Build the local socket */
-#if defined( WIN32 ) && !defined( UNDER_CE )
+#if defined( WIN32 ) || defined( UNDER_CE )
/* Under Win32 and for multicasting, we bind to INADDR_ANY,
* so let's call BuildAddr with "" instead of psz_bind_addr */
if( BuildAddr( &sock, IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) ?
/* Bind it */
if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
{
-#ifdef HAVE_ERRNO_H
- msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError() );
#else
- msg_Warn( p_this, "cannot bind socket" );
+ msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
#endif
close( i_handle );
return( -1 );
}
-#if defined( WIN32 ) && !defined( UNDER_CE )
+#if defined( WIN32 ) || defined( UNDER_CE )
/* Restore the sock struct so we can spare a few #ifdef WIN32 later on */
if( IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) )
{
i_opt = 1;
if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, (void*) &i_opt, sizeof( i_opt ) ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %i)",
+ WSAGetLastError() );
+#else
msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %s)",
strerror(errno) );
-#else
- msg_Warn( p_this, "cannot configure socket (SO_BROADCAST)" );
#endif
}
}
#endif
-#if !defined( UNDER_CE ) && !defined( SYS_BEOS )
+#if !defined( SYS_BEOS )
/* Join the multicast group if the socket is a multicast address */
if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
{
(char*)&imr,
sizeof(struct ip_mreq_source) ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Err( p_this, "failed to join IP multicast group (%i)",
+ WSAGetLastError() );
+#else
msg_Err( p_this, "failed to join IP multicast group (%s)",
strerror(errno) );
- msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
-#else
- msg_Err( p_this, "failed to join IP multicast group" );
- msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
#endif
+ msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
close( i_handle );
return( -1 );
}
if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char*)&imr, sizeof(struct ip_mreq) ) == -1 )
{
-#ifdef HAVE_ERRNO_H
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Err( p_this, "failed to join IP multicast group (%i)",
+ WSAGetLastError() );
+#else
msg_Err( p_this, "failed to join IP multicast group (%s)",
strerror(errno) );
-#else
- msg_Err( p_this, "failed to join IP multicast group" );
#endif
close( i_handle );
return( -1 );
if( connect( i_handle, (struct sockaddr *) &sock,
sizeof( sock ) ) == (-1) )
{
-#ifdef HAVE_ERRNO_H
- msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot connect socket (%i)", WSAGetLastError());
#else
- msg_Warn( p_this, "cannot connect socket" );
+ msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
#endif
close( i_handle );
return( -1 );
}
-#if !defined( UNDER_CE ) && !defined( SYS_BEOS )
+#if !defined( SYS_BEOS )
if( IN_MULTICAST( ntohl(inet_addr(psz_server_addr) ) ) )
{
/* set the time-to-live */
- int ttl = p_socket->i_ttl;
- if( ttl < 1 )
+ int i_ttl = p_socket->i_ttl;
+ unsigned char ttl;
+
+ /* set the multicast interface */
+ char * psz_mif_addr = config_GetPsz( p_this, "miface-addr" );
+ if( psz_mif_addr )
{
- ttl = config_GetInt( p_this, "ttl" );
+ struct in_addr intf;
+ intf.s_addr = inet_addr(psz_mif_addr);
+ free( psz_mif_addr );
+
+ if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_IF,
+ &intf, sizeof( intf ) ) < 0 )
+ {
+ msg_Dbg( p_this, "failed to set multicast interface (%s).", strerror(errno) );
+ close( i_handle );
+ return ( -1 );
+ }
}
- if( ttl < 1 ) ttl = 1;
+ if( i_ttl < 1 )
+ {
+ if( var_Get( p_this, "ttl", &val ) != VLC_SUCCESS )
+ {
+ var_Create( p_this, "ttl",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, "ttl", &val );
+ }
+ i_ttl = val.i_int;
+ }
+ if( i_ttl < 1 ) i_ttl = 1;
+ ttl = (unsigned char) i_ttl;
+
+ /* There is some confusion in the world whether IP_MULTICAST_TTL
+ * takes a byte or an int as an argument.
+ * BSD seems to indicate byte so we are going with that and use
+ * int as a fallback to be safe */
if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
- (void *) &ttl, sizeof( ttl ) ) < 0 )
+ &ttl, sizeof( ttl ) ) < 0 )
{
-#ifdef HAVE_ERRNO_H
- msg_Err( p_this, "failed to set ttl (%s)", strerror(errno) );
-#else
- msg_Err( p_this, "failed to set ttl" );
-#endif
- close( i_handle );
- return( -1 );
+ msg_Dbg( p_this, "failed to set ttl (%s). Let's try it "
+ "the integer way.", strerror(errno) );
+ if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
+ &i_ttl, sizeof( i_ttl ) ) <0 )
+ {
+ msg_Err( p_this, "failed to set ttl (%s)",
+ strerror(errno) );
+ close( i_handle );
+ return( -1 );
+ }
}
}
#endif
p_socket->i_handle = i_handle;
- var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
- var_Get( p_this, "mtu", &val );
+ if( var_Get( p_this, "mtu", &val ) != VLC_SUCCESS )
+ {
+ var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, "mtu", &val );
+ }
p_socket->i_mtu = val.i_int;
return( 0 );
}
* protocol */
if( (i_handle = socket( PF_INET, SOCK_STREAM, 0 )) == -1 )
{
-#ifdef HAVE_ERRNO_H
- msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );
#else
- msg_Warn( p_this, "cannot create socket" );
+ msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
#endif
return -1;
}
msg_Err( p_this, "cannot set socket to non-blocking mode" );
}
}
-#elif defined( HAVE_ERRNO_H )
+#else
{
int i_flags;
if( ( i_flags = fcntl( i_handle, F_GETFL, 0 ) ) < 0 ||
{
#if defined( WIN32 ) || defined( UNDER_CE )
if( WSAGetLastError() == WSAEWOULDBLOCK )
-#elif defined( HAVE_ERRNO_H )
- if( errno == EINPROGRESS )
#else
- if( 0 )
+ if( errno == EINPROGRESS )
#endif
{
int i_ret, i_opt, i_opt_size = sizeof( i_opt ), i_max_count;
vlc_value_t val;
fd_set fds;
- if( !var_Type( p_this, "ipv4-timeout" ) )
+ if( var_Get( p_this, "ipv4-timeout", &val ) != VLC_SUCCESS )
{
var_Create( p_this, "ipv4-timeout",
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_this, "ipv4-timeout", &val );
}
- var_Get( p_this, "ipv4-timeout", &val );
i_max_count = val.i_int * 1000 / 100000 /* timeout.tv_usec */;
msg_Dbg( p_this, "connection in progress" );
&timeout ) ) == 0 ||
#if defined( WIN32 ) || defined( UNDER_CE )
( i_ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK ) );
-#elif defined( HAVE_ERRNO_H )
- ( i_ret < 0 && errno == EINTR ) );
#else
- ( i_ret < 0 ) );
+ ( i_ret < 0 && errno == EINTR ) );
#endif
if( i_ret < 0 )
goto error;
}
-#if !defined( SYS_BEOS )
+#if !defined( SYS_BEOS ) && !defined( UNDER_CE )
if( getsockopt( i_handle, SOL_SOCKET, SO_ERROR, (void*)&i_opt,
&i_opt_size ) == -1 || i_opt != 0 )
{
}
else
{
-#if defined( HAVE_ERRNO_H )
- msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Warn( p_this, "cannot connect socket (%i)", WSAGetLastError());
#else
- msg_Warn( p_this, "cannot connect socket" );
+ msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
#endif
goto error;
}
/* Bind the socket */
if( bind( i_handle, (struct sockaddr *) &sock, sizeof( sock )) == -1 )
{
-#ifdef HAVE_ERRNO_H
- msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Err( p_this, "cannot bind socket (%i)", WSAGetLastError());
#else
- msg_Err( p_this, "cannot bind socket" );
+ msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
#endif
goto error;
}
/* Listen */
if( listen( i_handle, 100 ) == -1 )
{
-#ifdef HAVE_ERRNO_H
- msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
- strerror(errno) );
+#if defined(WIN32) || defined(UNDER_CE)
+ msg_Err( p_this, "cannot bring socket in listening mode (%i)",
+ WSAGetLastError());
#else
- msg_Err( p_this, "cannot bring the socket in listening mode" );
+ msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
+ strerror(errno) );
#endif
- goto error;
+ goto error;
}
p_socket->i_handle = i_handle;