2004-01-05 15:10:58 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* net.c:
|
|
|
|
*****************************************************************************
|
2005-07-09 08:17:09 +02:00
|
|
|
* Copyright (C) 2004-2005 the VideoLAN team
|
2004-03-08 18:08:46 +01:00
|
|
|
* $Id$
|
2004-01-05 15:10:58 +01:00
|
|
|
*
|
|
|
|
* Authors: Laurent Aimar <fenrir@videolan.org>
|
2005-05-22 13:24:08 +02:00
|
|
|
* Rémi Denis-Courmont <rem # videolan.org>
|
2004-01-05 15:10:58 +01:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* Preamble
|
|
|
|
*****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <vlc/vlc.h>
|
|
|
|
|
2004-10-04 15:34:42 +02:00
|
|
|
#include <errno.h>
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
# include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
# include <sys/time.h>
|
|
|
|
#endif
|
2004-01-09 13:23:47 +01:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
#include "network.h"
|
|
|
|
|
2004-11-15 18:07:06 +01:00
|
|
|
#ifndef INADDR_ANY
|
|
|
|
# define INADDR_ANY 0x00000000
|
|
|
|
#endif
|
|
|
|
#ifndef INADDR_NONE
|
|
|
|
# define INADDR_NONE 0xFFFFFFFF
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
|
|
|
|
char *psz_socks_user, char *psz_socks_passwd );
|
|
|
|
static int SocksHandshakeTCP( vlc_object_t *,
|
|
|
|
int fd, int i_socks_version,
|
|
|
|
char *psz_socks_user, char *psz_socks_passwd,
|
|
|
|
const char *psz_host, int i_port );
|
|
|
|
|
2005-07-04 18:42:22 +02:00
|
|
|
static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
|
|
|
|
int i_protocol )
|
|
|
|
{
|
|
|
|
int fd, i_val;
|
|
|
|
|
|
|
|
fd = socket( i_family, i_socktype, i_protocol );
|
|
|
|
if( fd == -1 )
|
|
|
|
{
|
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-08-19 17:21:25 +02:00
|
|
|
if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
|
|
|
|
msg_Warn( p_this, "cannot create socket (%i)",
|
|
|
|
WSAGetLastError() );
|
2005-07-04 18:42:22 +02:00
|
|
|
#else
|
2005-08-19 17:21:25 +02:00
|
|
|
if( errno != EAFNOSUPPORT )
|
|
|
|
msg_Warn( p_this, "cannot create socket (%s)",
|
|
|
|
strerror( errno ) );
|
2005-07-04 18:42:22 +02:00
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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_this, "cannot set socket to non-blocking mode" );
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
|
|
|
|
( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
|
|
|
|
msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
|
|
|
|
strerror( errno ) );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
i_val = 1;
|
|
|
|
setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
|
|
|
|
sizeof( i_val ) );
|
|
|
|
|
|
|
|
#ifdef IPV6_V6ONLY
|
|
|
|
/*
|
|
|
|
* Accepts only IPv6 connections on IPv6 sockets
|
|
|
|
* (and open an IPv4 socket later as well if needed).
|
|
|
|
* Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
|
|
|
|
* so this allows for more uniform handling across platforms. Besides,
|
|
|
|
* it makes sure that IPv4 addresses will be printed as w.x.y.z rather
|
|
|
|
* than ::ffff:w.x.y.z
|
|
|
|
*/
|
|
|
|
if( i_family == AF_INET6 )
|
|
|
|
setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
|
|
|
|
sizeof( i_val ) );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined( WIN32 ) || defined( UNDER_CE )
|
2005-08-21 13:27:15 +02:00
|
|
|
# ifndef IPV6_PROTECTION_LEVEL
|
|
|
|
# define IPV6_PROTECTION_LEVEL 23
|
|
|
|
# endif
|
2005-07-04 18:42:22 +02:00
|
|
|
if( i_family == AF_INET6 )
|
|
|
|
{
|
2005-08-14 14:22:25 +02:00
|
|
|
i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
|
2005-07-17 23:21:04 +02:00
|
|
|
setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
|
|
|
|
(const char*)&i_val, sizeof( i_val ) );
|
2005-07-04 18:42:22 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
/*****************************************************************************
|
2005-12-04 18:40:59 +01:00
|
|
|
* __net_ConnectTCP:
|
2004-01-05 15:10:58 +01:00
|
|
|
*****************************************************************************
|
|
|
|
* Open a TCP connection and return a handle
|
|
|
|
*****************************************************************************/
|
2005-12-04 18:40:59 +01:00
|
|
|
int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
struct addrinfo hints, *res, *ptr;
|
|
|
|
const char *psz_realhost;
|
2005-06-26 11:12:36 +02:00
|
|
|
char *psz_socks;
|
|
|
|
int i_realport, i_val, i_handle = -1;
|
2005-09-17 17:00:58 +02:00
|
|
|
vlc_bool_t b_unreach = VLC_FALSE;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
if( i_port == 0 )
|
|
|
|
i_port = 80; /* historical VLC thing */
|
2004-01-05 15:10:58 +01:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
memset( &hints, 0, sizeof( hints ) );
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
psz_socks = var_CreateGetString( p_this, "socks" );
|
|
|
|
if( *psz_socks && *psz_socks != ':' )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
char *psz = strchr( psz_socks, ':' );
|
2004-11-15 18:07:06 +01:00
|
|
|
|
|
|
|
if( psz )
|
|
|
|
*psz++ = '\0';
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
psz_realhost = psz_socks;
|
2005-06-26 11:12:36 +02:00
|
|
|
i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
|
2004-11-15 18:07:06 +01:00
|
|
|
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
|
2005-06-26 11:12:36 +02:00
|
|
|
psz_realhost, i_realport, psz_host, i_port );
|
2004-11-15 18:07:06 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
psz_realhost = psz_host;
|
2005-06-26 11:12:36 +02:00
|
|
|
i_realport = i_port;
|
2004-11-15 18:07:06 +01:00
|
|
|
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
|
2005-06-26 11:12:36 +02:00
|
|
|
i_realport );
|
2005-05-22 13:24:08 +02:00
|
|
|
}
|
2004-11-15 18:07:06 +01:00
|
|
|
|
2005-06-26 11:12:36 +02:00
|
|
|
i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
|
2005-05-22 13:24:08 +02:00
|
|
|
if( i_val )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
|
2005-06-26 11:12:36 +02:00
|
|
|
i_realport, vlc_gai_strerror( i_val ) );
|
2005-05-22 13:24:08 +02:00
|
|
|
free( psz_socks );
|
2004-01-05 15:10:58 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2005-07-04 18:42:22 +02:00
|
|
|
fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
|
|
|
|
ptr->ai_protocol );
|
2005-05-22 13:24:08 +02:00
|
|
|
if( fd == -1 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
|
|
|
|
{
|
2005-07-10 13:49:42 +02:00
|
|
|
socklen_t i_val_size = sizeof( i_val );
|
2005-06-23 17:35:18 +02:00
|
|
|
div_t d;
|
2005-05-22 13:24:08 +02:00
|
|
|
struct timeval tv;
|
|
|
|
vlc_value_t timeout;
|
2005-09-17 17:00:58 +02:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
#if defined( WIN32 ) || defined( UNDER_CE )
|
|
|
|
if( WSAGetLastError() != WSAEWOULDBLOCK )
|
|
|
|
{
|
2005-09-17 17:00:58 +02:00
|
|
|
if( WSAGetLastError () == WSAENETUNREACH )
|
|
|
|
b_unreach = VLC_TRUE;
|
|
|
|
else
|
|
|
|
msg_Warn( p_this, "connection to %s port %d failed (%d)",
|
|
|
|
psz_host, i_port, WSAGetLastError( ) );
|
2005-05-22 13:24:08 +02:00
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if( errno != EINPROGRESS )
|
|
|
|
{
|
2005-09-17 17:00:58 +02:00
|
|
|
if( errno == ENETUNREACH )
|
2005-12-04 18:40:59 +01:00
|
|
|
b_unreach = VLC_TRUE;
|
2005-09-17 17:00:58 +02:00
|
|
|
else
|
|
|
|
msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
|
|
|
|
i_port, strerror( errno ) );
|
2005-05-22 13:24:08 +02:00
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
var_Create( p_this, "ipv4-timeout",
|
|
|
|
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
|
|
|
|
var_Get( p_this, "ipv4-timeout", &timeout );
|
2005-06-23 17:35:18 +02:00
|
|
|
if( timeout.i_int < 0 )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "invalid negative value for ipv4-timeout" );
|
|
|
|
timeout.i_int = 0;
|
|
|
|
}
|
|
|
|
d = div( timeout.i_int, 100 );
|
2005-05-22 13:24:08 +02:00
|
|
|
|
|
|
|
msg_Dbg( p_this, "connection in progress" );
|
|
|
|
do
|
|
|
|
{
|
2005-06-23 17:35:18 +02:00
|
|
|
fd_set fds;
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
if( p_this->b_die )
|
|
|
|
{
|
|
|
|
msg_Dbg( p_this, "connection aborted" );
|
|
|
|
net_Close( fd );
|
|
|
|
vlc_freeaddrinfo( res );
|
|
|
|
free( psz_socks );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize file descriptor set */
|
|
|
|
FD_ZERO( &fds );
|
|
|
|
FD_SET( fd, &fds );
|
|
|
|
|
|
|
|
/* We'll wait 0.1 second if nothing happens */
|
|
|
|
tv.tv_sec = 0;
|
2005-06-23 17:35:18 +02:00
|
|
|
tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
|
2005-05-22 13:24:08 +02:00
|
|
|
|
|
|
|
i_val = select( fd + 1, NULL, &fds, NULL, &tv );
|
2005-06-23 17:35:18 +02:00
|
|
|
|
|
|
|
if( d.quot <= 0 )
|
|
|
|
{
|
|
|
|
msg_Dbg( p_this, "connection timed out" );
|
|
|
|
net_Close( fd );
|
|
|
|
fd = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
d.quot--;
|
2005-05-22 13:24:08 +02:00
|
|
|
}
|
|
|
|
while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
|
|
|
|
#if defined( WIN32 ) || defined( UNDER_CE )
|
|
|
|
( WSAGetLastError() == WSAEWOULDBLOCK )
|
|
|
|
#else
|
|
|
|
( errno == EINTR )
|
|
|
|
#endif
|
|
|
|
) );
|
|
|
|
|
2005-06-23 17:35:18 +02:00
|
|
|
if( fd == -1 )
|
|
|
|
continue; /* timeout */
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
if( i_val < 0 )
|
|
|
|
{
|
|
|
|
msg_Warn( p_this, "connection aborted (select failed)" );
|
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined( SYS_BEOS ) && !defined( UNDER_CE )
|
|
|
|
if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
|
|
|
|
&i_val_size ) == -1 || i_val != 0 )
|
|
|
|
{
|
2005-09-17 17:00:58 +02:00
|
|
|
if( i_val == ENETUNREACH )
|
|
|
|
b_unreach = VLC_TRUE;
|
|
|
|
else
|
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
#ifdef WIN32
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Warn( p_this, "connection to %s port %d failed (%d)",
|
|
|
|
psz_host, i_port, WSAGetLastError( ) );
|
2005-05-22 13:24:08 +02:00
|
|
|
#else
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
|
|
|
|
i_port, strerror( i_val ) );
|
2005-05-22 13:24:08 +02:00
|
|
|
#endif
|
2005-09-17 17:00:58 +02:00
|
|
|
}
|
2005-05-22 13:24:08 +02:00
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
i_handle = fd; /* success! */
|
|
|
|
}
|
2005-09-17 17:00:58 +02:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
vlc_freeaddrinfo( res );
|
|
|
|
|
2005-09-17 17:00:58 +02:00
|
|
|
if( i_handle == -1 )
|
|
|
|
{
|
|
|
|
if( b_unreach )
|
|
|
|
msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
|
|
|
|
i_port );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
if( *psz_socks && *psz_socks != ':' )
|
2004-11-15 18:07:06 +01:00
|
|
|
{
|
|
|
|
char *psz_user = var_CreateGetString( p_this, "socks-user" );
|
|
|
|
char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
|
2004-11-15 18:07:06 +01:00
|
|
|
psz_host, i_port ) )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "failed to use the SOCKS server" );
|
2005-05-22 13:24:08 +02:00
|
|
|
net_Close( i_handle );
|
|
|
|
i_handle = -1;
|
2004-11-15 18:07:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
free( psz_user );
|
|
|
|
free( psz_pwd );
|
|
|
|
}
|
2005-05-22 13:24:08 +02:00
|
|
|
free( psz_socks );
|
2004-11-15 18:07:06 +01:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
return i_handle;
|
2004-01-05 15:10:58 +01:00
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
|
2004-06-06 14:45:32 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_ListenTCP:
|
|
|
|
*****************************************************************************
|
2005-05-22 13:24:08 +02:00
|
|
|
* Open TCP passive "listening" socket(s)
|
|
|
|
* This function returns NULL in case of error.
|
2004-06-06 14:45:32 +02:00
|
|
|
*****************************************************************************/
|
2005-05-22 13:24:08 +02:00
|
|
|
int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
|
2004-06-06 14:45:32 +02:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
struct addrinfo hints, *res, *ptr;
|
|
|
|
int i_val, *pi_handles, i_size;
|
2004-06-06 14:45:32 +02:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
memset( &hints, 0, sizeof( hints ) );
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
2004-06-06 14:45:32 +02:00
|
|
|
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
|
2005-05-22 13:24:08 +02:00
|
|
|
|
2005-06-26 11:12:36 +02:00
|
|
|
i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
|
2005-05-22 13:24:08 +02:00
|
|
|
if( i_val )
|
2004-06-06 14:45:32 +02:00
|
|
|
{
|
2005-09-17 17:00:58 +02:00
|
|
|
msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
|
2005-05-22 13:24:08 +02:00
|
|
|
vlc_gai_strerror( i_val ) );
|
|
|
|
return NULL;
|
2004-06-06 14:45:32 +02:00
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
pi_handles = NULL;
|
|
|
|
i_size = 1;
|
2004-06-06 14:45:32 +02:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
|
2004-06-06 14:45:32 +02:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
int fd, *newpi;
|
|
|
|
|
2005-07-04 18:42:22 +02:00
|
|
|
fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
|
|
|
|
ptr->ai_protocol );
|
2005-05-22 13:24:08 +02:00
|
|
|
if( fd == -1 )
|
|
|
|
continue;
|
2005-06-26 12:29:06 +02:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
/* Bind the socket */
|
|
|
|
if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
|
|
|
|
{
|
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
|
|
|
msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
|
|
|
|
#else
|
|
|
|
msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
|
|
|
|
#endif
|
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
2005-12-04 18:40:59 +01:00
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
/* Listen */
|
|
|
|
if( listen( fd, 100 ) == -1 )
|
|
|
|
{
|
|
|
|
#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 (%s)",
|
|
|
|
strerror( errno ) );
|
|
|
|
#endif
|
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
|
|
|
|
if( newpi == NULL )
|
|
|
|
{
|
|
|
|
net_Close( fd );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newpi[i_size - 2] = fd;
|
|
|
|
pi_handles = newpi;
|
|
|
|
}
|
2004-06-06 14:45:32 +02:00
|
|
|
}
|
2005-09-17 17:00:58 +02:00
|
|
|
|
2005-05-23 08:22:02 +02:00
|
|
|
vlc_freeaddrinfo( res );
|
2004-06-06 14:45:32 +02:00
|
|
|
|
2005-06-04 17:57:14 +02:00
|
|
|
if( pi_handles != NULL )
|
|
|
|
pi_handles[i_size - 1] = -1;
|
2005-05-22 13:24:08 +02:00
|
|
|
return pi_handles;
|
2004-06-06 14:45:32 +02:00
|
|
|
}
|
|
|
|
|
2004-07-25 00:49:28 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_Accept:
|
|
|
|
*****************************************************************************
|
2005-05-22 13:24:08 +02:00
|
|
|
* Accept a connection on a set of listening sockets and return it
|
2004-07-25 00:49:28 +02:00
|
|
|
*****************************************************************************/
|
2005-05-22 13:24:08 +02:00
|
|
|
int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
|
2004-07-25 00:49:28 +02:00
|
|
|
{
|
|
|
|
vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
|
|
|
|
|
|
|
|
while( p_this->b_die == b_die )
|
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
int i_val = -1, *pi, *pi_end;
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set fds_r, fds_e;
|
|
|
|
|
|
|
|
pi = pi_fd;
|
|
|
|
|
2004-07-25 00:49:28 +02:00
|
|
|
/* Initialize file descriptor set */
|
|
|
|
FD_ZERO( &fds_r );
|
|
|
|
FD_ZERO( &fds_e );
|
2005-05-22 13:24:08 +02:00
|
|
|
|
|
|
|
for( pi = pi_fd; *pi != -1; pi++ )
|
|
|
|
{
|
|
|
|
int i_fd = *pi;
|
|
|
|
|
|
|
|
if( i_fd > i_val )
|
|
|
|
i_val = i_fd;
|
|
|
|
|
|
|
|
FD_SET( i_fd, &fds_r );
|
|
|
|
FD_SET( i_fd, &fds_e );
|
|
|
|
}
|
|
|
|
pi_end = pi;
|
2004-07-25 00:49:28 +02:00
|
|
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = b_block ? 500000 : i_wait;
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
|
|
|
|
if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
|
2004-07-25 00:49:28 +02:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
if( b_block )
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
return -1;
|
2004-07-25 00:49:28 +02:00
|
|
|
}
|
2005-05-22 13:24:08 +02:00
|
|
|
else if( i_val < 0 )
|
2004-07-25 00:49:28 +02:00
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2004-07-25 01:05:03 +02:00
|
|
|
msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
|
2004-07-25 00:49:28 +02:00
|
|
|
#else
|
2005-05-22 13:24:08 +02:00
|
|
|
msg_Err( p_this, "network select error (%s)", strerror( errno ) );
|
2004-07-25 00:49:28 +02:00
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
for( pi = pi_fd; *pi != -1; pi++ )
|
2004-07-25 00:49:28 +02:00
|
|
|
{
|
2005-05-22 13:24:08 +02:00
|
|
|
int i_fd = *pi;
|
|
|
|
|
|
|
|
if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
i_val = accept( i_fd, NULL, 0 );
|
|
|
|
if( i_val < 0 )
|
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-05-22 13:24:08 +02:00
|
|
|
msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
|
2004-07-25 00:49:28 +02:00
|
|
|
#else
|
2005-05-22 13:24:08 +02:00
|
|
|
msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
|
2004-07-25 00:49:28 +02:00
|
|
|
#endif
|
2005-05-22 13:24:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This round-robin trick ensures that the first sockets in
|
|
|
|
* pi_fd won't prevent the last ones from getting accept'ed.
|
|
|
|
*/
|
|
|
|
--pi_end;
|
|
|
|
memmove( pi, pi + 1, pi_end - pi );
|
|
|
|
*pi_end = i_fd;
|
|
|
|
return i_val;
|
|
|
|
}
|
2004-07-25 00:49:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-12-04 18:40:59 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* __net_ConnectUDP:
|
|
|
|
*****************************************************************************
|
|
|
|
* Open a UDP socket to send data to a defined destination, with an optional
|
|
|
|
* hop limit.
|
|
|
|
*****************************************************************************/
|
|
|
|
int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
|
|
|
|
int hlim )
|
|
|
|
{
|
|
|
|
struct addrinfo hints, *res, *ptr;
|
|
|
|
int i_val, i_handle = -1;
|
|
|
|
vlc_bool_t b_unreach = VLC_FALSE;
|
|
|
|
|
|
|
|
if( i_port == 0 )
|
|
|
|
i_port = 1234; /* historical VLC thing */
|
|
|
|
|
|
|
|
memset( &hints, 0, sizeof( hints ) );
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
|
|
|
|
msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
|
|
|
|
|
|
|
|
i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
|
|
|
|
if( i_val )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
|
|
|
|
vlc_gai_strerror( i_val ) );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
|
|
|
|
ptr->ai_protocol );
|
|
|
|
if( fd == -1 )
|
|
|
|
continue;
|
|
|
|
#if !defined( SYS_BEOS )
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i_val;
|
|
|
|
|
|
|
|
/* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
|
|
|
|
* packet loss caused by scheduling problems */
|
|
|
|
i_val = 0x80000;
|
|
|
|
setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
|
|
|
|
sizeof( i_val ) );
|
|
|
|
i_val = 0x80000;
|
|
|
|
setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
|
|
|
|
sizeof( i_val ) );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
|
|
|
|
{
|
|
|
|
/* success */
|
|
|
|
i_handle = fd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined( WIN32 ) || defined( UNDER_CE )
|
|
|
|
if( WSAGetLastError () == WSAENETUNREACH )
|
|
|
|
#else
|
|
|
|
if( errno == ENETUNREACH )
|
|
|
|
#endif
|
|
|
|
b_unreach = VLC_TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
|
|
|
|
strerror( errno ) );
|
|
|
|
net_Close( fd );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vlc_freeaddrinfo( res );
|
|
|
|
|
|
|
|
if( i_handle == -1 )
|
|
|
|
{
|
|
|
|
if( b_unreach )
|
|
|
|
msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
|
|
|
|
i_port );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i_handle;
|
|
|
|
}
|
|
|
|
|
2004-01-21 11:22:31 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_OpenUDP:
|
|
|
|
*****************************************************************************
|
|
|
|
* Open a UDP connection and return a handle
|
|
|
|
*****************************************************************************/
|
2005-07-27 17:46:36 +02:00
|
|
|
int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
|
|
|
|
const char *psz_server, int i_server )
|
2004-01-21 11:22:31 +01:00
|
|
|
{
|
2005-08-02 17:31:47 +02:00
|
|
|
vlc_value_t v4, v6;
|
2004-01-21 11:22:31 +01:00
|
|
|
void *private;
|
|
|
|
network_socket_t sock;
|
2005-08-02 17:31:47 +02:00
|
|
|
module_t *p_network = NULL;
|
2004-01-21 11:22:31 +01:00
|
|
|
|
2005-12-04 18:40:59 +01:00
|
|
|
if( ( psz_server != NULL ) && ( psz_server[0] == '\0' ) )
|
|
|
|
msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
|
|
|
|
"is obsolete - use net_ConnectUDP instead" );
|
|
|
|
if( i_server != 0 )
|
|
|
|
msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
|
|
|
|
"port is obsolete - use __net_ConnectUDP instead" );
|
|
|
|
|
2005-08-22 23:31:51 +02:00
|
|
|
if( psz_server == NULL ) psz_server = "";
|
|
|
|
if( psz_bind == NULL ) psz_bind = "";
|
|
|
|
|
2004-01-21 11:22:31 +01:00
|
|
|
/* Prepare the network_socket_t structure */
|
|
|
|
sock.psz_bind_addr = psz_bind;
|
|
|
|
sock.i_bind_port = i_bind;
|
|
|
|
sock.psz_server_addr = psz_server;
|
|
|
|
sock.i_server_port = i_server;
|
|
|
|
sock.i_ttl = 0;
|
2005-08-02 17:31:47 +02:00
|
|
|
sock.v6only = 0;
|
|
|
|
sock.i_handle = -1;
|
|
|
|
|
2005-07-27 18:56:58 +02:00
|
|
|
msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
|
2004-01-21 11:22:31 +01:00
|
|
|
psz_server, i_server, psz_bind, i_bind );
|
2005-08-02 17:31:47 +02:00
|
|
|
|
|
|
|
/* Check if we have force ipv4 or ipv6 */
|
|
|
|
var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
|
|
|
var_Get( p_this, "ipv4", &v4 );
|
|
|
|
var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
|
|
|
|
var_Get( p_this, "ipv6", &v6 );
|
|
|
|
|
|
|
|
if( !v4.b_bool )
|
2004-01-21 11:22:31 +01:00
|
|
|
{
|
2005-08-02 17:31:47 +02:00
|
|
|
if( v6.b_bool )
|
|
|
|
sock.v6only = 1;
|
|
|
|
|
|
|
|
/* try IPv6 first (unless IPv4 forced) */
|
|
|
|
private = p_this->p_private;
|
|
|
|
p_this->p_private = (void*)&sock;
|
|
|
|
p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
|
|
|
|
|
|
|
|
if( p_network != NULL )
|
|
|
|
module_Unneed( p_this, p_network );
|
|
|
|
|
|
|
|
p_this->p_private = private;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the IP stack can receive IPv4 packets on IPv6 sockets.
|
|
|
|
* If yes, then it is better to use the IPv6 socket.
|
|
|
|
* Otherwise, if we also get an IPv4, we have to choose, so we use
|
|
|
|
* IPv4 only.
|
|
|
|
*/
|
|
|
|
if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
|
|
|
|
return sock.i_handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !v6.b_bool )
|
|
|
|
{
|
|
|
|
int fd6 = sock.i_handle;
|
|
|
|
|
|
|
|
/* also try IPv4 (unless IPv6 forced) */
|
|
|
|
private = p_this->p_private;
|
|
|
|
p_this->p_private = (void*)&sock;
|
|
|
|
p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
|
|
|
|
|
|
|
|
if( p_network != NULL )
|
|
|
|
module_Unneed( p_this, p_network );
|
|
|
|
|
|
|
|
p_this->p_private = private;
|
|
|
|
|
|
|
|
if( fd6 != -1 )
|
|
|
|
{
|
|
|
|
if( sock.i_handle != -1 )
|
|
|
|
{
|
|
|
|
msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
|
|
|
|
"Using only IPv4." );
|
|
|
|
net_Close( fd6 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sock.i_handle = fd6;
|
|
|
|
}
|
2004-01-21 11:22:31 +01:00
|
|
|
}
|
2005-08-02 17:31:47 +02:00
|
|
|
|
|
|
|
if( sock.i_handle == -1 )
|
|
|
|
msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
|
|
|
|
psz_server, i_server, psz_bind, i_bind );
|
2004-01-21 11:22:31 +01:00
|
|
|
|
|
|
|
return sock.i_handle;
|
|
|
|
}
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_Close:
|
|
|
|
*****************************************************************************
|
|
|
|
* Close a network handle
|
|
|
|
*****************************************************************************/
|
|
|
|
void net_Close( int fd )
|
|
|
|
{
|
|
|
|
#ifdef UNDER_CE
|
|
|
|
CloseHandle( (HANDLE)fd );
|
|
|
|
#elif defined( WIN32 )
|
|
|
|
closesocket( fd );
|
|
|
|
#else
|
|
|
|
close( fd );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-05-22 13:24:08 +02:00
|
|
|
void net_ListenClose( int *pi_fd )
|
|
|
|
{
|
|
|
|
if( pi_fd != NULL )
|
|
|
|
{
|
|
|
|
int *pi;
|
|
|
|
|
|
|
|
for( pi = pi_fd; *pi != -1; pi++ )
|
|
|
|
net_Close( *pi );
|
|
|
|
free( pi_fd );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_Read:
|
|
|
|
*****************************************************************************
|
|
|
|
* Read from a network socket
|
2005-07-15 17:24:39 +02:00
|
|
|
* If b_retry is true, then we repeat until we have read the right amount of
|
2004-01-05 15:10:58 +01:00
|
|
|
* data
|
|
|
|
*****************************************************************************/
|
2004-11-07 12:02:59 +01:00
|
|
|
int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
|
|
|
|
uint8_t *p_data, int i_data, vlc_bool_t b_retry )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
|
|
|
struct timeval timeout;
|
2004-03-08 18:08:46 +01:00
|
|
|
fd_set fds_r, fds_e;
|
2004-01-05 15:10:58 +01:00
|
|
|
int i_recv;
|
|
|
|
int i_total = 0;
|
|
|
|
int i_ret;
|
2004-01-08 00:39:41 +01:00
|
|
|
vlc_bool_t b_die = p_this->b_die;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
while( i_data > 0 )
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2004-01-08 00:39:41 +01:00
|
|
|
if( p_this->b_die != b_die )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize file descriptor set */
|
2004-03-08 18:08:46 +01:00
|
|
|
FD_ZERO( &fds_r );
|
|
|
|
FD_SET( fd, &fds_r );
|
|
|
|
FD_ZERO( &fds_e );
|
|
|
|
FD_SET( fd, &fds_e );
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
/* We'll wait 0.5 second if nothing happens */
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 500000;
|
2004-03-08 18:08:46 +01:00
|
|
|
|
|
|
|
} while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
|
|
|
|
|| ( i_ret < 0 && errno == EINTR ) );
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
if( i_ret < 0 )
|
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-07-06 19:14:00 +02:00
|
|
|
msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
|
2004-10-01 17:56:10 +02:00
|
|
|
#else
|
2004-01-05 15:10:58 +01:00
|
|
|
msg_Err( p_this, "network select error (%s)", strerror(errno) );
|
2004-10-01 17:56:10 +02:00
|
|
|
#endif
|
2004-01-05 15:10:58 +01:00
|
|
|
return i_total > 0 ? i_total : -1;
|
|
|
|
}
|
|
|
|
|
2004-11-07 12:02:59 +01:00
|
|
|
if( ( i_recv = (p_vs != NULL)
|
|
|
|
? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
|
|
|
|
: recv( fd, p_data, i_data, 0 ) ) < 0 )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-05-09 21:01:25 +02:00
|
|
|
if( WSAGetLastError() == WSAEWOULDBLOCK )
|
|
|
|
{
|
|
|
|
/* only happens with p_vs (SSL) - not really an error */
|
|
|
|
}
|
|
|
|
else
|
2004-01-21 11:22:31 +01:00
|
|
|
/* For udp only */
|
|
|
|
/* On win32 recv() will fail if the datagram doesn't fit inside
|
|
|
|
* the passed buffer, even though the buffer will be filled with
|
|
|
|
* the first part of the datagram. */
|
2004-01-25 18:16:06 +01:00
|
|
|
if( WSAGetLastError() == WSAEMSGSIZE )
|
2004-01-21 11:22:31 +01:00
|
|
|
{
|
2004-01-22 18:03:44 +01:00
|
|
|
msg_Err( p_this, "recv() failed. "
|
2004-01-21 11:22:31 +01:00
|
|
|
"Increase the mtu size (--mtu option)" );
|
2004-06-09 13:13:42 +02:00
|
|
|
i_total += i_data;
|
2004-01-21 11:22:31 +01:00
|
|
|
}
|
2005-05-26 11:38:35 +02:00
|
|
|
else if( WSAGetLastError() == WSAEINTR ) continue;
|
|
|
|
else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
|
2004-03-08 18:08:46 +01:00
|
|
|
#else
|
2005-09-17 17:00:58 +02:00
|
|
|
/* EAGAIN only happens with p_vs (TLS) and it's not an error */
|
2005-05-09 21:01:25 +02:00
|
|
|
if( errno != EAGAIN )
|
|
|
|
msg_Err( p_this, "recv failed (%s)", strerror(errno) );
|
2004-03-08 18:08:46 +01:00
|
|
|
#endif
|
2004-01-05 15:10:58 +01:00
|
|
|
return i_total > 0 ? i_total : -1;
|
|
|
|
}
|
2004-03-08 18:08:46 +01:00
|
|
|
else if( i_recv == 0 )
|
|
|
|
{
|
|
|
|
/* Connection closed */
|
|
|
|
b_retry = VLC_FALSE;
|
|
|
|
}
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
p_data += i_recv;
|
|
|
|
i_data -= i_recv;
|
|
|
|
i_total+= i_recv;
|
|
|
|
if( !b_retry )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return i_total;
|
|
|
|
}
|
|
|
|
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_ReadNonBlock:
|
|
|
|
*****************************************************************************
|
|
|
|
* Read from a network socket, non blocking mode (with timeout)
|
|
|
|
*****************************************************************************/
|
2004-11-07 12:02:59 +01:00
|
|
|
int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
|
|
|
|
uint8_t *p_data, int i_data, mtime_t i_wait)
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
{
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set fds_r, fds_e;
|
|
|
|
int i_recv;
|
|
|
|
int i_ret;
|
|
|
|
|
|
|
|
/* Initialize file descriptor set */
|
|
|
|
FD_ZERO( &fds_r );
|
|
|
|
FD_SET( fd, &fds_r );
|
|
|
|
FD_ZERO( &fds_e );
|
|
|
|
FD_SET( fd, &fds_e );
|
|
|
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = i_wait;
|
|
|
|
|
|
|
|
i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
|
|
|
|
|
|
|
|
if( i_ret < 0 && errno == EINTR )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if( i_ret < 0 )
|
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-07-06 19:14:00 +02:00
|
|
|
msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
|
2004-10-01 17:56:10 +02:00
|
|
|
#else
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
msg_Err( p_this, "network select error (%s)", strerror(errno) );
|
2004-10-01 17:56:10 +02:00
|
|
|
#endif
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if( i_ret == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if !defined(UNDER_CE)
|
|
|
|
if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
|
|
|
|
#endif
|
2004-11-07 12:02:59 +01:00
|
|
|
if( ( i_recv = (p_vs != NULL)
|
|
|
|
? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
|
2005-08-18 15:53:45 +02:00
|
|
|
: recv( fd, p_data, i_data, 0 ) ) < 0 )
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
/* For udp only */
|
|
|
|
/* On win32 recv() will fail if the datagram doesn't fit inside
|
|
|
|
* the passed buffer, even though the buffer will be filled with
|
|
|
|
* the first part of the datagram. */
|
|
|
|
if( WSAGetLastError() == WSAEMSGSIZE )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "recv() failed. "
|
|
|
|
"Increase the mtu size (--mtu option)" );
|
|
|
|
}
|
2005-05-26 11:38:35 +02:00
|
|
|
else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
#else
|
|
|
|
msg_Err( p_this, "recv failed (%s)", strerror(errno) );
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
2004-07-25 00:49:28 +02:00
|
|
|
|
|
|
|
return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
}
|
2004-07-25 00:49:28 +02:00
|
|
|
|
* ALL: Better announce system
- The SAP handler now runs in a separate thread.
- RTP sessions can be announced with sap (sdp=sap://,name=...)
TODO: Make this more configurable
- Better SDP generation (the timestamp problem is not resolved)
About this, there is a problem : as, for a RTP session, the URI
is the complete SDP, if the session is recreated, as the URI has
changed, a new item is added to the playlist
- Experimental flow control algorithm :
It does not follow the "Recommended" implementation, as it needs
to count the sessions (to achieve this, we should make this work
together with the SAP listener)
It is disabled by default (use --sap-flow-control to enable).
When it is disabled, sap announcement interval is set by --sap-interval
* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem
2004-04-18 20:21:09 +02:00
|
|
|
/* We will never be here */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-11-06 12:13:23 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* __net_Select:
|
|
|
|
*****************************************************************************
|
2004-11-06 12:14:00 +01:00
|
|
|
* Read from several sockets (with timeout). Takes data from the first socket
|
|
|
|
* that has some.
|
2004-11-06 12:13:23 +01:00
|
|
|
*****************************************************************************/
|
2004-11-07 12:02:59 +01:00
|
|
|
int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
|
|
|
|
int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
|
2004-11-06 12:13:23 +01:00
|
|
|
{
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set fds_r, fds_e;
|
|
|
|
int i_recv;
|
|
|
|
int i_ret;
|
|
|
|
int i;
|
|
|
|
int i_max_fd = 0;
|
|
|
|
|
|
|
|
/* Initialize file descriptor set */
|
|
|
|
FD_ZERO( &fds_r );
|
|
|
|
FD_ZERO( &fds_e );
|
|
|
|
|
|
|
|
for( i = 0 ; i < i_fd ; i++)
|
|
|
|
{
|
|
|
|
if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
|
|
|
|
FD_SET( pi_fd[i], &fds_r );
|
|
|
|
FD_SET( pi_fd[i], &fds_e );
|
|
|
|
}
|
|
|
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = i_wait;
|
|
|
|
|
|
|
|
i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
|
|
|
|
|
|
|
|
if( i_ret < 0 && errno == EINTR )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if( i_ret < 0 )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "network select error (%s)", strerror(errno) );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if( i_ret == 0 )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for( i = 0 ; i < i_fd ; i++)
|
|
|
|
{
|
|
|
|
if( FD_ISSET( pi_fd[i], &fds_r ) )
|
|
|
|
{
|
2004-11-07 12:02:59 +01:00
|
|
|
i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
|
|
|
|
? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
|
|
|
|
: recv( pi_fd[i], p_data, i_data, 0 );
|
2005-08-18 15:53:45 +02:00
|
|
|
if( i_recv < 0 )
|
2004-11-06 12:13:23 +01:00
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
/* For udp only */
|
|
|
|
/* On win32 recv() will fail if the datagram doesn't
|
|
|
|
* fit inside the passed buffer, even though the buffer
|
|
|
|
* will be filled with the first part of the datagram. */
|
|
|
|
if( WSAGetLastError() == WSAEMSGSIZE )
|
|
|
|
{
|
|
|
|
msg_Err( p_this, "recv() failed. "
|
|
|
|
"Increase the mtu size (--mtu option)" );
|
|
|
|
}
|
2005-05-26 11:38:35 +02:00
|
|
|
else msg_Err( p_this, "recv failed (%i)",
|
|
|
|
WSAGetLastError() );
|
2004-11-06 12:13:23 +01:00
|
|
|
#else
|
2005-08-18 15:53:45 +02:00
|
|
|
msg_Err( p_this, "recv failed (%s)", strerror(errno) );
|
2004-11-06 12:13:23 +01:00
|
|
|
#endif
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i_recv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We will never be here */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
/* Write exact amount requested */
|
2004-11-07 12:02:59 +01:00
|
|
|
int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
|
2005-08-18 17:24:38 +02:00
|
|
|
const uint8_t *p_data, int i_data )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
|
|
|
struct timeval timeout;
|
2004-03-08 18:08:46 +01:00
|
|
|
fd_set fds_w, fds_e;
|
2004-01-05 15:10:58 +01:00
|
|
|
int i_send;
|
|
|
|
int i_total = 0;
|
|
|
|
int i_ret;
|
|
|
|
|
2004-01-08 00:39:41 +01:00
|
|
|
vlc_bool_t b_die = p_this->b_die;
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
while( i_data > 0 )
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2004-01-08 00:39:41 +01:00
|
|
|
if( p_this->b_die != b_die )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize file descriptor set */
|
2004-03-08 18:08:46 +01:00
|
|
|
FD_ZERO( &fds_w );
|
|
|
|
FD_SET( fd, &fds_w );
|
|
|
|
FD_ZERO( &fds_e );
|
|
|
|
FD_SET( fd, &fds_e );
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
/* We'll wait 0.5 second if nothing happens */
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 500000;
|
2004-03-08 18:08:46 +01:00
|
|
|
|
|
|
|
} while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
|
|
|
|
|| ( i_ret < 0 && errno == EINTR ) );
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
if( i_ret < 0 )
|
|
|
|
{
|
2004-10-01 17:56:10 +02:00
|
|
|
#if defined(WIN32) || defined(UNDER_CE)
|
2005-07-06 19:14:00 +02:00
|
|
|
msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
|
2004-10-01 17:56:10 +02:00
|
|
|
#else
|
2004-01-05 15:10:58 +01:00
|
|
|
msg_Err( p_this, "network select error (%s)", strerror(errno) );
|
2004-10-01 17:56:10 +02:00
|
|
|
#endif
|
2004-01-05 15:10:58 +01:00
|
|
|
return i_total > 0 ? i_total : -1;
|
|
|
|
}
|
|
|
|
|
2004-11-07 12:02:59 +01:00
|
|
|
if( ( i_send = (p_vs != NULL)
|
|
|
|
? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
|
|
|
|
: send( fd, p_data, i_data, 0 ) ) < 0 )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2004-01-22 01:00:34 +01:00
|
|
|
/* XXX With udp for example, it will issue a message if the host
|
|
|
|
* isn't listening */
|
|
|
|
/* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
|
2004-01-05 15:10:58 +01:00
|
|
|
return i_total > 0 ? i_total : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_data += i_send;
|
|
|
|
i_data -= i_send;
|
|
|
|
i_total+= i_send;
|
|
|
|
}
|
|
|
|
return i_total;
|
|
|
|
}
|
|
|
|
|
2004-11-07 12:02:59 +01:00
|
|
|
char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-07-05 18:44:56 +02:00
|
|
|
char *psz_line = NULL, *ptr = NULL;
|
|
|
|
size_t i_line = 0, i_max = 0;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
for( ;; )
|
|
|
|
{
|
2005-07-05 18:44:56 +02:00
|
|
|
if( i_line == i_max )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-07-05 18:44:56 +02:00
|
|
|
i_max += 1024;
|
|
|
|
psz_line = realloc( psz_line, i_max );
|
|
|
|
ptr = psz_line + i_line;
|
2004-01-05 15:10:58 +01:00
|
|
|
}
|
2004-01-07 00:03:17 +01:00
|
|
|
|
2005-07-10 13:49:42 +02:00
|
|
|
if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2005-07-05 18:44:56 +02:00
|
|
|
if( i_line == 0 )
|
|
|
|
{
|
|
|
|
free( psz_line );
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-01-05 15:10:58 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-07-05 18:44:56 +02:00
|
|
|
if ( *ptr == '\n' )
|
|
|
|
break;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
2005-07-05 18:44:56 +02:00
|
|
|
i_line++;
|
|
|
|
ptr++;
|
2004-01-05 15:10:58 +01:00
|
|
|
}
|
|
|
|
|
2005-07-05 18:44:56 +02:00
|
|
|
*ptr-- = '\0';
|
|
|
|
|
2005-07-05 20:28:26 +02:00
|
|
|
if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
|
2005-07-05 18:44:56 +02:00
|
|
|
*ptr = '\0';
|
|
|
|
|
2004-01-05 15:10:58 +01:00
|
|
|
return psz_line;
|
|
|
|
}
|
|
|
|
|
2004-11-07 12:02:59 +01:00
|
|
|
int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
|
|
|
|
const char *psz_fmt, ... )
|
2004-01-05 15:10:58 +01:00
|
|
|
{
|
2004-07-25 00:49:28 +02:00
|
|
|
int i_ret;
|
2004-01-05 15:10:58 +01:00
|
|
|
va_list args;
|
2004-07-25 00:49:28 +02:00
|
|
|
va_start( args, psz_fmt );
|
2004-11-07 12:02:59 +01:00
|
|
|
i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
|
2004-07-25 00:49:28 +02:00
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
return i_ret;
|
|
|
|
}
|
|
|
|
|
2004-11-07 12:02:59 +01:00
|
|
|
int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
|
|
|
|
const char *psz_fmt, va_list args )
|
2004-07-25 00:49:28 +02:00
|
|
|
{
|
2004-01-05 15:10:58 +01:00
|
|
|
char *psz;
|
2004-01-07 15:59:03 +01:00
|
|
|
int i_size, i_ret;
|
2004-01-05 15:10:58 +01:00
|
|
|
|
2005-07-15 17:24:39 +02:00
|
|
|
i_size = vasprintf( &psz, psz_fmt, args );
|
2005-07-10 13:49:42 +02:00
|
|
|
i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
|
|
|
|
? -1 : i_size;
|
2004-01-07 15:59:03 +01:00
|
|
|
free( psz );
|
|
|
|
|
|
|
|
return i_ret;
|
2004-01-05 15:10:58 +01:00
|
|
|
}
|
2004-11-15 18:07:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* SocksNegociate:
|
|
|
|
*****************************************************************************
|
|
|
|
* Negociate authentication with a SOCKS server.
|
|
|
|
*****************************************************************************/
|
|
|
|
static int SocksNegociate( vlc_object_t *p_obj,
|
|
|
|
int fd, int i_socks_version,
|
|
|
|
char *psz_socks_user,
|
|
|
|
char *psz_socks_passwd )
|
|
|
|
{
|
|
|
|
uint8_t buffer[128+2*256];
|
|
|
|
int i_len;
|
|
|
|
vlc_bool_t b_auth = VLC_FALSE;
|
|
|
|
|
|
|
|
if( i_socks_version != 5 )
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
|
|
|
|
/* We negociate authentication */
|
|
|
|
|
|
|
|
if( psz_socks_user && psz_socks_passwd &&
|
|
|
|
*psz_socks_user && *psz_socks_passwd )
|
|
|
|
b_auth = VLC_TRUE;
|
|
|
|
|
|
|
|
buffer[0] = i_socks_version; /* SOCKS version */
|
|
|
|
if( b_auth )
|
|
|
|
{
|
|
|
|
buffer[1] = 2; /* Number of methods */
|
|
|
|
buffer[2] = 0x00; /* - No auth required */
|
|
|
|
buffer[3] = 0x02; /* - USer/Password */
|
|
|
|
i_len = 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buffer[1] = 1; /* Number of methods */
|
|
|
|
buffer[2] = 0x00; /* - No auth required */
|
|
|
|
i_len = 3;
|
|
|
|
}
|
2005-12-04 18:40:59 +01:00
|
|
|
|
2004-11-15 18:07:06 +01:00
|
|
|
if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
|
|
|
|
|
|
|
|
if( buffer[1] == 0x00 )
|
|
|
|
{
|
|
|
|
msg_Dbg( p_obj, "socks: no authentication required" );
|
|
|
|
}
|
|
|
|
else if( buffer[1] == 0x02 )
|
|
|
|
{
|
|
|
|
int i_len1 = __MIN( strlen(psz_socks_user), 255 );
|
|
|
|
int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
|
|
|
|
msg_Dbg( p_obj, "socks: username/password authentication" );
|
|
|
|
|
|
|
|
/* XXX: we don't support user/pwd > 255 (truncated)*/
|
|
|
|
buffer[0] = i_socks_version; /* Version */
|
|
|
|
buffer[1] = i_len1; /* User length */
|
|
|
|
memcpy( &buffer[2], psz_socks_user, i_len1 );
|
|
|
|
buffer[2+i_len1] = i_len2; /* Password length */
|
|
|
|
memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
|
|
|
|
|
|
|
|
i_len = 3 + i_len1 + i_len2;
|
|
|
|
|
|
|
|
if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
|
|
|
|
if( buffer[1] != 0x00 )
|
|
|
|
{
|
|
|
|
msg_Err( p_obj, "socks: authentication rejected" );
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( b_auth )
|
|
|
|
msg_Err( p_obj, "socks: unsupported authentication method %x",
|
|
|
|
buffer[0] );
|
|
|
|
else
|
|
|
|
msg_Err( p_obj, "socks: authentification needed" );
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* SocksHandshakeTCP:
|
|
|
|
*****************************************************************************
|
|
|
|
* Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
|
|
|
|
*****************************************************************************/
|
|
|
|
static int SocksHandshakeTCP( vlc_object_t *p_obj,
|
|
|
|
int fd,
|
|
|
|
int i_socks_version,
|
|
|
|
char *psz_socks_user, char *psz_socks_passwd,
|
|
|
|
const char *psz_host, int i_port )
|
|
|
|
{
|
|
|
|
uint8_t buffer[128+2*256];
|
|
|
|
|
|
|
|
if( i_socks_version != 4 && i_socks_version != 5 )
|
|
|
|
{
|
|
|
|
msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
|
|
|
|
i_socks_version = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i_socks_version == 5 &&
|
|
|
|
SocksNegociate( p_obj, fd, i_socks_version,
|
|
|
|
psz_socks_user, psz_socks_passwd ) )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
if( i_socks_version == 4 )
|
|
|
|
{
|
2005-05-24 10:22:07 +02:00
|
|
|
struct addrinfo hints = { 0 }, *p_res;
|
2004-11-15 18:07:06 +01:00
|
|
|
|
|
|
|
/* v4 only support ipv4 */
|
2005-07-01 20:00:04 +02:00
|
|
|
hints.ai_family = AF_INET;
|
2005-06-26 11:12:36 +02:00
|
|
|
if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
|
2004-11-15 18:07:06 +01:00
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
buffer[0] = i_socks_version;
|
|
|
|
buffer[1] = 0x01; /* CONNECT */
|
|
|
|
SetWBE( &buffer[2], i_port ); /* Port */
|
2005-05-24 10:22:07 +02:00
|
|
|
memcpy( &buffer[4], /* Address */
|
|
|
|
&((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
|
|
|
|
vlc_freeaddrinfo( p_res );
|
|
|
|
|
2004-11-15 18:07:06 +01:00
|
|
|
buffer[8] = 0; /* Empty user id */
|
|
|
|
|
|
|
|
if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
msg_Dbg( p_obj, "socks: v=%d cd=%d",
|
|
|
|
buffer[0], buffer[1] );
|
|
|
|
|
|
|
|
if( buffer[1] != 90 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
else if( i_socks_version == 5 )
|
|
|
|
{
|
|
|
|
int i_hlen = __MIN(strlen( psz_host ), 255);
|
|
|
|
int i_len;
|
|
|
|
|
|
|
|
buffer[0] = i_socks_version; /* Version */
|
|
|
|
buffer[1] = 0x01; /* Cmd: connect */
|
|
|
|
buffer[2] = 0x00; /* Reserved */
|
|
|
|
buffer[3] = 3; /* ATYP: for now domainname */
|
|
|
|
|
|
|
|
buffer[4] = i_hlen;
|
|
|
|
memcpy( &buffer[5], psz_host, i_hlen );
|
|
|
|
SetWBE( &buffer[5+i_hlen], i_port );
|
|
|
|
|
|
|
|
i_len = 5 + i_hlen + 2;
|
|
|
|
|
|
|
|
|
|
|
|
if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
/* Read the header */
|
|
|
|
if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
|
|
|
|
buffer[0], buffer[1], buffer[3] );
|
|
|
|
|
|
|
|
if( buffer[1] != 0x00 )
|
|
|
|
{
|
|
|
|
msg_Err( p_obj, "socks: CONNECT request failed\n" );
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the remaining bytes */
|
|
|
|
if( buffer[3] == 0x01 )
|
|
|
|
i_len = 4-1 + 2;
|
|
|
|
else if( buffer[3] == 0x03 )
|
|
|
|
i_len = buffer[4] + 2;
|
|
|
|
else if( buffer[3] == 0x04 )
|
|
|
|
i_len = 16-1+2;
|
|
|
|
else
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
2005-06-17 14:43:46 +02:00
|
|
|
|
2005-07-28 17:31:10 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* inet_pton replacement for obsolete and/or crap operating systems
|
|
|
|
*****************************************************************************/
|
|
|
|
#ifndef HAVE_INET_PTON
|
|
|
|
int inet_pton(int af, const char *src, void *dst)
|
|
|
|
{
|
|
|
|
# ifdef WIN32
|
|
|
|
/* As we already know, Microsoft always go its own way, so even if they do
|
|
|
|
* provide IPv6, they don't provide the API. */
|
|
|
|
struct sockaddr_storage addr;
|
|
|
|
int len = sizeof( addr );
|
|
|
|
|
|
|
|
/* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
|
2005-10-23 18:24:30 +02:00
|
|
|
#ifdef UNICODE
|
|
|
|
wchar_t *workaround_for_ill_designed_api =
|
|
|
|
malloc( MAX_PATH * sizeof(wchar_t) );
|
|
|
|
mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
|
|
|
|
workaround_for_ill_designed_api[MAX_PATH-1] = 0;
|
|
|
|
#else
|
2005-07-28 17:31:10 +02:00
|
|
|
char *workaround_for_ill_designed_api = strdup( src );
|
2005-10-23 18:24:30 +02:00
|
|
|
#endif
|
|
|
|
|
2005-07-28 17:31:10 +02:00
|
|
|
if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
|
|
|
|
(LPSOCKADDR)&addr, &len ) )
|
|
|
|
{
|
|
|
|
free( workaround_for_ill_designed_api );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free( workaround_for_ill_designed_api );
|
|
|
|
|
|
|
|
switch( af )
|
|
|
|
{
|
|
|
|
case AF_INET6:
|
|
|
|
memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
|
|
|
|
break;
|
2005-12-04 18:40:59 +01:00
|
|
|
|
2005-07-28 17:31:10 +02:00
|
|
|
case AF_INET:
|
|
|
|
memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
WSASetLastError( WSAEAFNOSUPPORT );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
# else
|
|
|
|
/* Assume IPv6 is not supported. */
|
|
|
|
/* Would be safer and more simpler to use inet_aton() but it is most
|
|
|
|
* likely not provided either. */
|
|
|
|
uint32_t ipv4;
|
|
|
|
|
|
|
|
if( af != AF_INET )
|
|
|
|
{
|
|
|
|
errno = EAFNOSUPPORT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipv4 = inet_addr( src );
|
|
|
|
if( ipv4 == INADDR_NONE )
|
|
|
|
return -1;
|
|
|
|
|
2005-08-14 15:15:38 +02:00
|
|
|
memcpy( dst, &ipv4, 4 );
|
2005-07-28 17:31:10 +02:00
|
|
|
# endif /* WIN32 */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_INET_PTON */
|