/* Socket types */
#define NETWORK_UDP 1
#define NETWORK_TCP 2
+#define NETWORK_TCP_PASSIVE 3
typedef struct
#define net_OpenTCP(a, b, c) __net_OpenTCP(VLC_OBJECT(a), b, c)
VLC_EXPORT( int, __net_OpenTCP, ( vlc_object_t *p_this, char *psz_host, int i_port ) );
+#define net_ListenTCP(a, b, c) __net_ListenTCP(VLC_OBJECT(a), b, c)
+VLC_EXPORT( int, __net_ListenTCP, ( vlc_object_t *p_this, char *psz_localaddr, int i_port ) );
+
#define net_OpenUDP(a, b, c, d, e ) __net_OpenUDP(VLC_OBJECT(a), b, c, d, e)
VLC_EXPORT( int, __net_OpenUDP, ( vlc_object_t *p_this, char *psz_bind, int i_bind, char *psz_server, int i_server ) );
# include <winsock.h>
#elif defined( WIN32 )
# include <winsock2.h>
-# include <ws2tcpip.h>
-# ifndef IN_MULTICAST
-# define IN_MULTICAST(a) IN_CLASSD(a)
-# endif
#else
-# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
-# include <netinet/in.h>
-# ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
-# endif
#endif
#include "network.h"
#define SOCKET_CLOSE(a) close(a)
#endif
-#define LISTEN_BACKLOG 100
-
#define READ_MODE_PWD 1
#define READ_MODE_CMD 2
#define WRITE_MODE_PWD 3 // when we write the word "Password:"
static char* MessageToString( vlm_message_t* , int );
static void Write_message( telnet_client_t * , vlm_message_t* , char * , int );
-static int SocketListen( intf_thread_t * , int );
struct intf_sys_t
{
p_intf->pf_run = Run;
p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
- if( ( p_intf->p_sys->fd = SocketListen( p_intf , i_telnetport ) ) < 0 )
+ if( ( p_intf->p_sys->fd = net_ListenTCP( p_intf , "", i_telnetport ) ) < 0 )
{
msg_Err( p_intf, "cannot listen for telnet" );
free( p_intf->p_sys );
{
intf_sys_t *p_sys = p_intf->p_sys;
struct timeval timeout;
- int i_sock_size = sizeof( struct sockaddr_in );
char *s_password;
s_password = config_GetPsz( p_intf, "telnet-password" );
fd_set fds_write;
int i_handle_max = 0;
int i_ret;
- struct sockaddr_in sock2;
int i_len;
int fd;
int i;
/* if a new client wants to communicate */
- fd = accept( p_sys->fd, (struct sockaddr *)&sock2, &i_sock_size );
+ fd = accept( p_sys->fd, NULL, NULL );
if( fd > 0 )
{
telnet_client_t *cl;
free( psz_message );
}
-/* Does what we want except select and accept */
-static int SocketListen( intf_thread_t *p_intf , int i_port )
-{
- struct sockaddr_in sock;
- int fd;
- int i_opt;
- int i_flags;
-
- /* open socket */
- fd = socket( AF_INET, SOCK_STREAM, 0 );
- if( fd < 0 )
- {
- msg_Err( p_intf, "cannot open socket" );
- goto socket_failed;
- }
- /* reuse socket */
- i_opt = 1;
- if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
- (void *) &i_opt, sizeof( i_opt ) ) < 0 )
- {
- msg_Warn( p_intf, "cannot configure socket (SO_REUSEADDR)" );
- }
-
- /* fill p_socket structure */
- memset( &sock, 0, sizeof( struct sockaddr_in ) );
- sock.sin_family = AF_INET; /* family */
- sock.sin_port = htons( (uint16_t)i_port );
- sock.sin_addr.s_addr = INADDR_ANY;
-
- /* bind it */
- if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
- {
- msg_Err( p_intf, "cannot bind socket" );
- goto socket_failed;
- }
-
- /* set to non-blocking */
-#if defined( WIN32 ) || defined( UNDER_CE )
- {
- unsigned long i_dummy = 1;
- if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
- {
- msg_Err( p_intf, "cannot set socket to non-blocking mode" );
- goto socket_failed;
- }
- }
-#else
- if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
- {
- msg_Err( p_intf, "cannot F_GETFL socket" );
- goto socket_failed;
- }
- if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
- {
- msg_Err( p_intf, "cannot F_SETFL O_NONBLOCK" );
- goto socket_failed;
- }
-#endif
- /* listen */
- if( listen( fd, LISTEN_BACKLOG ) < 0 )
- {
- msg_Err( p_intf, "cannot listen socket" );
- goto socket_failed;
- }
-
- return fd;
-
-socket_failed:
- if( fd >= 0 )
- {
- SOCKET_CLOSE( fd );
- }
- return -1;
-}
-
/* we need the level of the message to put a beautiful indentation.
first level is 0 */
static char* MessageToString( vlm_message_t* message , int i_level )
}
/*****************************************************************************
- * OpenTCP: open a TCP socket
+ * SocketTCP: create a TCP socket
*****************************************************************************
- * psz_server_addr, i_server_port : address and port used for the connect()
- * system call. If i_server_port == 0, 80 is used.
- * Other parameters are ignored.
* This function returns -1 in case of error.
*****************************************************************************/
-static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
+static int SocketTCP( vlc_object_t * p_this )
{
- char * psz_server_addr = p_socket->psz_server_addr;
- int i_server_port = p_socket->i_server_port;
-
int i_handle;
- struct sockaddr_in sock;
-
- if( i_server_port == 0 )
- {
- i_server_port = 80;
- }
-
- /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
+
+ /* Open a SOCK_STREAM (TCP) socket, in the PF_INET domain, automatic (0)
* protocol */
- if( (i_handle = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
+ if( (i_handle = socket( PF_INET, SOCK_STREAM, 0 )) == -1 )
{
#ifdef HAVE_ERRNO_H
msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
#else
msg_Warn( p_this, "cannot create socket" );
#endif
- goto error;
- }
-
- /* Build remote address */
- if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
- {
- msg_Dbg( p_this, "could not build local address" );
- goto error;
+ return -1;
}
/* Set to non-blocking */
}
#endif
+ return i_handle;
+}
+
+/*****************************************************************************
+ * OpenTCP: open a TCP socket
+ *****************************************************************************
+ * psz_server_addr, i_server_port : address and port used for the connect()
+ * system call. If i_server_port == 0, 80 is used.
+ * Other parameters are ignored.
+ * This function returns -1 in case of error.
+ *****************************************************************************/
+static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
+{
+ char * psz_server_addr = p_socket->psz_server_addr;
+ int i_server_port = p_socket->i_server_port;
+
+ int i_handle;
+ struct sockaddr_in sock;
+
+ if( i_server_port == 0 )
+ {
+ i_server_port = 80;
+ }
+
+ if( (i_handle = SocketTCP( p_this )) == -1 )
+ return VLC_EGENERIC;
+
+ /* Build remote address */
+ if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
+ {
+ msg_Dbg( p_this, "could not build local address" );
+ goto error;
+ }
+
/* Connect the socket */
if( connect( i_handle, (struct sockaddr *) &sock, sizeof( sock ) ) == -1 )
{
return VLC_SUCCESS;
error:
- if( i_handle > 0 )
+ close( i_handle );
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * ListenTCP: open a TCP passive socket (server-side)
+ *****************************************************************************
+ * psz_server_addr, i_server_port : address and port used for the bind()
+ * system call. If i_server_port == 0, 80 is used.
+ * Other parameters are ignored.
+ * This function returns -1 in case of error.
+ *****************************************************************************/
+static int ListenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
+{
+ char * psz_server_addr = p_socket->psz_server_addr;
+ int i_server_port = p_socket->i_server_port;
+
+ int i_handle, i_dummy = 1;
+ struct sockaddr_in sock;
+
+ if( (i_handle = SocketTCP( p_this )) == -1 )
+ return VLC_EGENERIC;
+
+ if ( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&i_dummy, sizeof( i_dummy ) ) == -1 )
{
- close( i_handle );
+ msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
+ }
+
+ /* Build remote address */
+ if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
+ {
+ msg_Dbg( p_this, "could not build local address" );
+ return VLC_EGENERIC;
+ }
+
+ /* 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) );
+#else
+ msg_Err( p_this, "cannot bind socket" );
+#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) );
+#else
+ msg_Err( p_this, "cannot bring the socket in listening mode" );
+#endif
+ goto error;
}
+
+ p_socket->i_handle = i_handle;
+ p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
+ return VLC_SUCCESS;
+
+error:
+ close( i_handle );
return VLC_EGENERIC;
}
/*****************************************************************************
- * NetOpen: wrapper around OpenUDP and OpenTCP
+ * NetOpen: wrapper around OpenUDP, ListenTCP and OpenTCP
*****************************************************************************/
static int NetOpen( vlc_object_t * p_this )
{
{
return OpenUDP( p_this, p_socket );
}
+ else if( p_socket->i_type == NETWORK_TCP_PASSIVE )
+ {
+ return ListenTCP( p_this, p_socket );
+ }
else
{
return OpenTCP( p_this, p_socket );
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-static int Open( vlc_object_t * );
+static int NetOpen( vlc_object_t * );
/*****************************************************************************
* Module descriptor
vlc_module_begin();
set_description( _("IPv6 network abstraction layer") );
set_capability( "network", 40 );
- set_callbacks( Open, NULL );
+ set_callbacks( NetOpen, NULL );
vlc_module_end();
/*****************************************************************************
return( 0 );
}
+/*****************************************************************************
+ * SocketTCP: create a TCP socket
+ *****************************************************************************
+ * This function returns -1 in case of error.
+ *****************************************************************************/
+static int SocketTCP( vlc_object_t * p_this )
+{
+ int i_handle;
+
+ /* Open a SOCK_STREAM (TCP) socket, in the PF_INET6 domain, automatic (0)
+ * protocol */
+ if( (i_handle = socket( PF_INET6, SOCK_STREAM, 0 )) == -1 )
+ {
+#ifdef HAVE_ERRNO_H
+ msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
+#else
+ msg_Warn( p_this, "cannot create socket" );
+#endif
+ return -1;
+ }
+
+ /* Set to non-blocking */
+#if defined( WIN32 ) || defined( UNDER_CE )
+ {
+ unsigned long i_dummy = 1;
+ if( ioctlsocket( i_handle, FIONBIO, &i_dummy ) != 0 )
+ {
+ msg_Err( p_this, "cannot set socket to non-blocking mode" );
+ }
+ }
+#elif defined( HAVE_ERRNO_H )
+ {
+ int i_flags;
+ if( ( i_flags = fcntl( i_handle, F_GETFL, 0 ) ) < 0 ||
+ fcntl( i_handle, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
+ {
+ msg_Err( p_this, "cannot set socket to non-blocking mode" );
+ }
+ }
+#endif
+
+ return i_handle;
+}
+
/*****************************************************************************
* OpenTCP: open a TCP socket
*****************************************************************************
i_server_port = 80;
}
- /* Open a SOCK_STREAM (TCP) socket, in the AF_INET6 domain, automatic (0)
- * protocol */
- if( (i_handle = socket( AF_INET6, SOCK_STREAM, 0 )) == -1 )
+ if( (i_handle = SocketTCP( p_this )) == -1 )
+ return VLC_EGENERIC;
+
+ /* Build remote address */
+ if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
+ goto error;
+
+ /* Connect the socket */
+ if( connect( i_handle, (struct sockaddr *) &sock, sizeof( sock ) ) == -1 )
{
- msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
- return( -1 );
+#if defined( WIN32 ) || defined( UNDER_CE )
+ if( WSAGetLastError() == WSAEWOULDBLOCK )
+#elif defined( HAVE_ERRNO_H )
+ if( errno == EINPROGRESS )
+#else
+ if( 0 )
+#endif
+ {
+ int i_ret, i_opt, i_opt_size = sizeof( i_opt ), i_max_count;
+ struct timeval timeout;
+ vlc_value_t val;
+ fd_set fds;
+
+ /* FIXME: There is no ipv6-timeout option, so we use ipv4-timeout
+ * instead */
+ if( !var_Type( p_this, "ipv4-timeout" ) )
+ {
+ var_Create( p_this, "ipv4-timeout",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ }
+ 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" );
+ do
+ {
+ if( p_this->b_die || i_max_count <= 0 )
+ {
+ msg_Dbg( p_this, "connection aborted" );
+ goto error;
+ }
+
+ i_max_count--;
+
+ /* Initialize file descriptor set */
+ FD_ZERO( &fds );
+ FD_SET( i_handle, &fds );
+
+ /* We'll wait 0.1 second if nothing happens */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+
+ } while( ( i_ret = select( i_handle + 1, NULL, &fds, NULL,
+ &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 ) );
+#endif
+
+ if( i_ret < 0 )
+ {
+ msg_Warn( p_this, "cannot connect socket (select failed)" );
+ goto error;
+ }
+
+#if !defined( SYS_BEOS )
+ if( getsockopt( i_handle, SOL_SOCKET, SO_ERROR, (void*)&i_opt,
+ &i_opt_size ) == -1 || i_opt != 0 )
+ {
+ msg_Warn( p_this, "cannot connect socket (SO_ERROR)" );
+ goto error;
+ }
+#endif
+ }
+ else
+ {
+#if defined( HAVE_ERRNO_H )
+ msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
+#else
+ msg_Warn( p_this, "cannot connect socket" );
+#endif
+ goto error;
+ }
+ }
+
+ p_socket->i_handle = i_handle;
+ p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
+ return VLC_SUCCESS;
+
+error:
+ close( i_handle );
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * ListenTCP: open a TCP passive socket (server-side)
+ *****************************************************************************
+ * psz_server_addr, i_server_port : address and port used for the bind()
+ * system call. If i_server_port == 0, 80 is used.
+ * Other parameters are ignored.
+ * This function returns -1 in case of error.
+ *****************************************************************************/
+static int ListenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
+{
+ char * psz_server_addr = p_socket->psz_server_addr;
+ int i_server_port = p_socket->i_server_port;
+
+ int i_handle, i_dummy = 1;
+ struct sockaddr_in6 sock;
+
+ if( (i_handle = SocketTCP( p_this )) == -1 )
+ return VLC_EGENERIC;
+
+ if ( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&i_dummy, sizeof( i_dummy ) ) == -1 )
+ {
+ msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
}
/* Build remote address */
if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
{
- close( i_handle );
- return( -1 );
+ msg_Dbg( p_this, "could not build local address" );
+ return VLC_EGENERIC;
}
-
- /* Connect the socket */
- if( connect( i_handle, (struct sockaddr *) &sock,
- sizeof( sock ) ) == (-1) )
+
+ /* Bind the socket */
+ if( bind( i_handle, (struct sockaddr *) &sock, sizeof( sock )) == -1 )
{
- msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
- close( i_handle );
- return( -1 );
+#ifdef HAVE_ERRNO_H
+ msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
+#else
+ msg_Err( p_this, "cannot bind socket" );
+#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) );
+#else
+ msg_Err( p_this, "cannot bring the socket in listening mode" );
+#endif
+ goto error;
}
p_socket->i_handle = i_handle;
p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
+ return VLC_SUCCESS;
- return( 0 );
+error:
+ close( i_handle );
+ return VLC_EGENERIC;
}
/*****************************************************************************
- * Open: wrapper around OpenUDP and OpenTCP
+ * NetOpen: wrapper around OpenUDP, ListenTCP and OpenTCP
*****************************************************************************/
-static int Open( vlc_object_t * p_this )
+static int NetOpen( vlc_object_t * p_this )
{
network_socket_t * p_socket = p_this->p_private;
{
return OpenUDP( p_this, p_socket );
}
+ else if( p_socket->i_type == NETWORK_TCP_PASSIVE )
+ {
+ return ListenTCP( p_this, p_socket );
+ }
else
{
return OpenTCP( p_this, p_socket );
return sock.i_handle;
}
+/*****************************************************************************
+ * __net_ListenTCP:
+ *****************************************************************************
+ * Open a TCP listening socket and return it
+ *****************************************************************************/
+int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
+{
+ vlc_value_t val;
+ void *private;
+
+ char *psz_network = "";
+ network_socket_t sock;
+ module_t *p_network;
+
+ /* Check if we have force ipv4 or ipv6 */
+ var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+ var_Get( p_this, "ipv4", &val );
+ if( val.b_bool )
+ {
+ psz_network = "ipv4";
+ }
+
+ var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+ var_Get( p_this, "ipv6", &val );
+ if( val.b_bool )
+ {
+ psz_network = "ipv6";
+ }
+
+ /* Prepare the network_socket_t structure */
+ sock.i_type = NETWORK_TCP_PASSIVE;
+ sock.psz_bind_addr = "";
+ sock.i_bind_port = 0;
+ sock.psz_server_addr = psz_host;
+ sock.i_server_port = i_port;
+ sock.i_ttl = 0;
+
+ msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
+ private = p_this->p_private;
+ p_this->p_private = (void*)&sock;
+ if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
+ {
+ msg_Dbg( p_this, "net: listening to '%s:%d' failed",
+ psz_host, i_port );
+ return -1;
+ }
+ module_Unneed( p_this, p_network );
+ p_this->p_private = private;
+
+ return sock.i_handle;
+}
+
/*****************************************************************************
* __net_OpenUDP:
*****************************************************************************