Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-1.1
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-1.1
Commits
8acc19a5
Commit
8acc19a5
authored
Dec 05, 2005
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sort out io.c
parent
3793ee13
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
885 additions
and
785 deletions
+885
-785
Makefile.am
Makefile.am
+4
-2
src/network/io.c
src/network/io.c
+3
-783
src/network/tcp.c
src/network/tcp.c
+637
-0
src/network/udp.c
src/network/udp.c
+241
-0
No files found.
Makefile.am
View file @
8acc19a5
...
...
@@ -435,10 +435,12 @@ SOURCES_libvlc_common = \
src/osd/osd_parser.c
\
src/osd/osd_text.c
\
src/osd/osd_widgets.c
\
src/network/getaddrinfo.c
\
src/network/io.c
\
src/network/tcp.c
\
src/network/udp.c
\
src/network/httpd.c
\
src/network/tls.c
\
src/network/io.c
\
src/network/getaddrinfo.c
\
src/misc/charset.c
\
src/misc/md5.c
\
src/misc/mtime.c
\
...
...
src/network/io.c
View file @
8acc19a5
/*****************************************************************************
*
net.c:
*
io.c: network I/O functions
*****************************************************************************
* Copyright (C) 2004-2005 the VideoLAN team
* $Id$
...
...
@@ -49,15 +49,8 @@
# 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
);
static
int
net_Socket
(
vlc_object_t
*
p_this
,
int
i_family
,
int
i_socktype
,
int
i_protocol
)
int
net_Socket
(
vlc_object_t
*
p_this
,
int
i_family
,
int
i_socktype
,
int
i_protocol
)
{
int
fd
,
i_val
;
...
...
@@ -122,573 +115,6 @@ static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
return
fd
;
}
/*****************************************************************************
* __net_ConnectTCP:
*****************************************************************************
* Open a TCP connection and return a handle
*****************************************************************************/
int
__net_ConnectTCP
(
vlc_object_t
*
p_this
,
const
char
*
psz_host
,
int
i_port
)
{
struct
addrinfo
hints
,
*
res
,
*
ptr
;
const
char
*
psz_realhost
;
char
*
psz_socks
;
int
i_realport
,
i_val
,
i_handle
=
-
1
;
vlc_bool_t
b_unreach
=
VLC_FALSE
;
if
(
i_port
==
0
)
i_port
=
80
;
/* historical VLC thing */
memset
(
&
hints
,
0
,
sizeof
(
hints
)
);
hints
.
ai_socktype
=
SOCK_STREAM
;
psz_socks
=
var_CreateGetString
(
p_this
,
"socks"
);
if
(
*
psz_socks
&&
*
psz_socks
!=
':'
)
{
char
*
psz
=
strchr
(
psz_socks
,
':'
);
if
(
psz
)
*
psz
++
=
'\0'
;
psz_realhost
=
psz_socks
;
i_realport
=
(
psz
!=
NULL
)
?
atoi
(
psz
)
:
1080
;
msg_Dbg
(
p_this
,
"net: connecting to %s port %d for %s port %d"
,
psz_realhost
,
i_realport
,
psz_host
,
i_port
);
}
else
{
psz_realhost
=
psz_host
;
i_realport
=
i_port
;
msg_Dbg
(
p_this
,
"net: connecting to %s port %d"
,
psz_realhost
,
i_realport
);
}
i_val
=
vlc_getaddrinfo
(
p_this
,
psz_realhost
,
i_realport
,
&
hints
,
&
res
);
if
(
i_val
)
{
msg_Err
(
p_this
,
"cannot resolve %s port %d : %s"
,
psz_realhost
,
i_realport
,
vlc_gai_strerror
(
i_val
)
);
free
(
psz_socks
);
return
-
1
;
}
for
(
ptr
=
res
;
(
ptr
!=
NULL
)
&&
(
i_handle
==
-
1
);
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
(
connect
(
fd
,
ptr
->
ai_addr
,
ptr
->
ai_addrlen
)
)
{
socklen_t
i_val_size
=
sizeof
(
i_val
);
div_t
d
;
struct
timeval
tv
;
vlc_value_t
timeout
;
#if defined( WIN32 ) || defined( UNDER_CE )
if
(
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
{
if
(
WSAGetLastError
()
==
WSAENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
msg_Warn
(
p_this
,
"connection to %s port %d failed (%d)"
,
psz_host
,
i_port
,
WSAGetLastError
(
)
);
net_Close
(
fd
);
continue
;
}
#else
if
(
errno
!=
EINPROGRESS
)
{
if
(
errno
==
ENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
msg_Warn
(
p_this
,
"connection to %s port %d : %s"
,
psz_host
,
i_port
,
strerror
(
errno
)
);
net_Close
(
fd
);
continue
;
}
#endif
var_Create
(
p_this
,
"ipv4-timeout"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"ipv4-timeout"
,
&
timeout
);
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
);
msg_Dbg
(
p_this
,
"connection in progress"
);
do
{
fd_set
fds
;
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
;
tv
.
tv_usec
=
(
d
.
quot
>
0
)
?
100000
:
(
1000
*
d
.
rem
);
i_val
=
select
(
fd
+
1
,
NULL
,
&
fds
,
NULL
,
&
tv
);
if
(
d
.
quot
<=
0
)
{
msg_Dbg
(
p_this
,
"connection timed out"
);
net_Close
(
fd
);
fd
=
-
1
;
break
;
}
d
.
quot
--
;
}
while
(
(
i_val
==
0
)
||
(
(
i_val
<
0
)
&&
#if defined( WIN32 ) || defined( UNDER_CE )
(
WSAGetLastError
()
==
WSAEWOULDBLOCK
)
#else
(
errno
==
EINTR
)
#endif
)
);
if
(
fd
==
-
1
)
continue
;
/* timeout */
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
)
{
if
(
i_val
==
ENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
{
#ifdef WIN32
msg_Warn
(
p_this
,
"connection to %s port %d failed (%d)"
,
psz_host
,
i_port
,
WSAGetLastError
(
)
);
#else
msg_Warn
(
p_this
,
"connection to %s port %d : %s"
,
psz_host
,
i_port
,
strerror
(
i_val
)
);
#endif
}
net_Close
(
fd
);
continue
;
}
#endif
}
i_handle
=
fd
;
/* success! */
}
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
;
}
if
(
*
psz_socks
&&
*
psz_socks
!=
':'
)
{
char
*
psz_user
=
var_CreateGetString
(
p_this
,
"socks-user"
);
char
*
psz_pwd
=
var_CreateGetString
(
p_this
,
"socks-pwd"
);
if
(
SocksHandshakeTCP
(
p_this
,
i_handle
,
5
,
psz_user
,
psz_pwd
,
psz_host
,
i_port
)
)
{
msg_Err
(
p_this
,
"failed to use the SOCKS server"
);
net_Close
(
i_handle
);
i_handle
=
-
1
;
}
free
(
psz_user
);
free
(
psz_pwd
);
}
free
(
psz_socks
);
return
i_handle
;
}
/*****************************************************************************
* __net_ListenTCP:
*****************************************************************************
* Open TCP passive "listening" socket(s)
* This function returns NULL in case of error.
*****************************************************************************/
int
*
__net_ListenTCP
(
vlc_object_t
*
p_this
,
const
char
*
psz_host
,
int
i_port
)
{
struct
addrinfo
hints
,
*
res
,
*
ptr
;
int
i_val
,
*
pi_handles
,
i_size
;
memset
(
&
hints
,
0
,
sizeof
(
hints
)
);
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_flags
=
AI_PASSIVE
;
msg_Dbg
(
p_this
,
"net: listening 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
NULL
;
}
pi_handles
=
NULL
;
i_size
=
1
;
for
(
ptr
=
res
;
ptr
!=
NULL
;
ptr
=
ptr
->
ai_next
)
{
int
fd
,
*
newpi
;
fd
=
net_Socket
(
p_this
,
ptr
->
ai_family
,
ptr
->
ai_socktype
,
ptr
->
ai_protocol
);
if
(
fd
==
-
1
)
continue
;
/* 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
;
}
/* 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
;
}
}
vlc_freeaddrinfo
(
res
);
if
(
pi_handles
!=
NULL
)
pi_handles
[
i_size
-
1
]
=
-
1
;
return
pi_handles
;
}
/*****************************************************************************
* __net_Accept:
*****************************************************************************
* Accept a connection on a set of listening sockets and return it
*****************************************************************************/
int
__net_Accept
(
vlc_object_t
*
p_this
,
int
*
pi_fd
,
mtime_t
i_wait
)
{
vlc_bool_t
b_die
=
p_this
->
b_die
,
b_block
=
(
i_wait
<
0
);
while
(
p_this
->
b_die
==
b_die
)
{
int
i_val
=
-
1
,
*
pi
,
*
pi_end
;
struct
timeval
timeout
;
fd_set
fds_r
,
fds_e
;
pi
=
pi_fd
;
/* Initialize file descriptor set */
FD_ZERO
(
&
fds_r
);
FD_ZERO
(
&
fds_e
);
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
;
timeout
.
tv_sec
=
0
;
timeout
.
tv_usec
=
b_block
?
500000
:
i_wait
;
i_val
=
select
(
i_val
+
1
,
&
fds_r
,
NULL
,
&
fds_e
,
&
timeout
);
if
(
(
(
i_val
<
0
)
&&
(
errno
==
EINTR
)
)
||
i_val
==
0
)
{
if
(
b_block
)
continue
;
else
return
-
1
;
}
else
if
(
i_val
<
0
)
{
#if defined(WIN32) || defined(UNDER_CE)
msg_Err
(
p_this
,
"network select error (%i)"
,
WSAGetLastError
()
);
#else
msg_Err
(
p_this
,
"network select error (%s)"
,
strerror
(
errno
)
);
#endif
return
-
1
;
}
for
(
pi
=
pi_fd
;
*
pi
!=
-
1
;
pi
++
)
{
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
)
{
#if defined(WIN32) || defined(UNDER_CE)
msg_Err
(
p_this
,
"accept failed (%i)"
,
WSAGetLastError
()
);
#else
msg_Err
(
p_this
,
"accept failed (%s)"
,
strerror
(
errno
)
);
#endif
}
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
;
}
}
}
return
-
1
;
}
/*****************************************************************************
* __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
;
}
/*****************************************************************************
* __net_OpenUDP:
*****************************************************************************
* Open a UDP connection and return a handle
*****************************************************************************/
int
__net_OpenUDP
(
vlc_object_t
*
p_this
,
const
char
*
psz_bind
,
int
i_bind
,
const
char
*
psz_server
,
int
i_server
)
{
vlc_value_t
v4
,
v6
;
void
*
private
;
network_socket_t
sock
;
module_t
*
p_network
=
NULL
;
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"
);
if
(
psz_server
==
NULL
)
psz_server
=
""
;
if
(
psz_bind
==
NULL
)
psz_bind
=
""
;
/* 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
;
sock
.
v6only
=
0
;
sock
.
i_handle
=
-
1
;
msg_Dbg
(
p_this
,
"net: connecting to '[%s]:%d@[%s]:%d'"
,
psz_server
,
i_server
,
psz_bind
,
i_bind
);
/* 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
)
{
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
;
}
}
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
);
return
sock
.
i_handle
;
}
/*****************************************************************************
* __net_Close:
...
...
@@ -706,18 +132,6 @@ void net_Close( int fd )
#endif
}
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
);
}
}
/*****************************************************************************
* __net_Read:
*****************************************************************************
...
...
@@ -1099,200 +513,6 @@ int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
}
/*****************************************************************************
* 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
;
}
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
)
{
struct
addrinfo
hints
=
{
0
},
*
p_res
;
/* v4 only support ipv4 */
hints
.
ai_family
=
AF_INET
;
if
(
vlc_getaddrinfo
(
p_obj
,
psz_host
,
0
,
&
hints
,
&
p_res
)
)
return
VLC_EGENERIC
;
buffer
[
0
]
=
i_socks_version
;
buffer
[
1
]
=
0x01
;
/* CONNECT */
SetWBE
(
&
buffer
[
2
],
i_port
);
/* Port */
memcpy
(
&
buffer
[
4
],
/* Address */
&
((
struct
sockaddr_in
*
)(
p_res
->
ai_addr
))
->
sin_addr
,
4
);
vlc_freeaddrinfo
(
p_res
);
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
;
}
/*****************************************************************************
* inet_pton replacement for obsolete and/or crap operating systems
*****************************************************************************/
...
...
src/network/tcp.c
0 → 100644
View file @
8acc19a5
/*****************************************************************************
* tcp.c:
*****************************************************************************
* Copyright (C) 2004-2005 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir@videolan.org>
* Rémi Denis-Courmont <rem # videolan.org>
*
* 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>
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "network.h"
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
);
extern
int
net_Socket
(
vlc_object_t
*
p_this
,
int
i_family
,
int
i_socktype
,
int
i_protocol
);
/*****************************************************************************
* __net_ConnectTCP:
*****************************************************************************
* Open a TCP connection and return a handle
*****************************************************************************/
int
__net_ConnectTCP
(
vlc_object_t
*
p_this
,
const
char
*
psz_host
,
int
i_port
)
{
struct
addrinfo
hints
,
*
res
,
*
ptr
;
const
char
*
psz_realhost
;
char
*
psz_socks
;
int
i_realport
,
i_val
,
i_handle
=
-
1
;
vlc_bool_t
b_unreach
=
VLC_FALSE
;
if
(
i_port
==
0
)
i_port
=
80
;
/* historical VLC thing */
memset
(
&
hints
,
0
,
sizeof
(
hints
)
);
hints
.
ai_socktype
=
SOCK_STREAM
;
psz_socks
=
var_CreateGetString
(
p_this
,
"socks"
);
if
(
*
psz_socks
&&
*
psz_socks
!=
':'
)
{
char
*
psz
=
strchr
(
psz_socks
,
':'
);
if
(
psz
)
*
psz
++
=
'\0'
;
psz_realhost
=
psz_socks
;
i_realport
=
(
psz
!=
NULL
)
?
atoi
(
psz
)
:
1080
;
msg_Dbg
(
p_this
,
"net: connecting to %s port %d for %s port %d"
,
psz_realhost
,
i_realport
,
psz_host
,
i_port
);
}
else
{
psz_realhost
=
psz_host
;
i_realport
=
i_port
;
msg_Dbg
(
p_this
,
"net: connecting to %s port %d"
,
psz_realhost
,
i_realport
);
}
i_val
=
vlc_getaddrinfo
(
p_this
,
psz_realhost
,
i_realport
,
&
hints
,
&
res
);
if
(
i_val
)
{
msg_Err
(
p_this
,
"cannot resolve %s port %d : %s"
,
psz_realhost
,
i_realport
,
vlc_gai_strerror
(
i_val
)
);
free
(
psz_socks
);
return
-
1
;
}
for
(
ptr
=
res
;
(
ptr
!=
NULL
)
&&
(
i_handle
==
-
1
);
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
(
connect
(
fd
,
ptr
->
ai_addr
,
ptr
->
ai_addrlen
)
)
{
socklen_t
i_val_size
=
sizeof
(
i_val
);
div_t
d
;
struct
timeval
tv
;
vlc_value_t
timeout
;
#if defined( WIN32 ) || defined( UNDER_CE )
if
(
WSAGetLastError
()
!=
WSAEWOULDBLOCK
)
{
if
(
WSAGetLastError
()
==
WSAENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
msg_Warn
(
p_this
,
"connection to %s port %d failed (%d)"
,
psz_host
,
i_port
,
WSAGetLastError
(
)
);
net_Close
(
fd
);
continue
;
}
#else
if
(
errno
!=
EINPROGRESS
)
{
if
(
errno
==
ENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
msg_Warn
(
p_this
,
"connection to %s port %d : %s"
,
psz_host
,
i_port
,
strerror
(
errno
)
);
net_Close
(
fd
);
continue
;
}
#endif
var_Create
(
p_this
,
"ipv4-timeout"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"ipv4-timeout"
,
&
timeout
);
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
);
msg_Dbg
(
p_this
,
"connection in progress"
);
do
{
fd_set
fds
;
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
;
tv
.
tv_usec
=
(
d
.
quot
>
0
)
?
100000
:
(
1000
*
d
.
rem
);
i_val
=
select
(
fd
+
1
,
NULL
,
&
fds
,
NULL
,
&
tv
);
if
(
d
.
quot
<=
0
)
{
msg_Dbg
(
p_this
,
"connection timed out"
);
net_Close
(
fd
);
fd
=
-
1
;
break
;
}
d
.
quot
--
;
}
while
(
(
i_val
==
0
)
||
(
(
i_val
<
0
)
&&
#if defined( WIN32 ) || defined( UNDER_CE )
(
WSAGetLastError
()
==
WSAEWOULDBLOCK
)
#else
(
errno
==
EINTR
)
#endif
)
);
if
(
fd
==
-
1
)
continue
;
/* timeout */
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
)
{
if
(
i_val
==
ENETUNREACH
)
b_unreach
=
VLC_TRUE
;
else
{
#ifdef WIN32
msg_Warn
(
p_this
,
"connection to %s port %d failed (%d)"
,
psz_host
,
i_port
,
WSAGetLastError
(
)
);
#else
msg_Warn
(
p_this
,
"connection to %s port %d : %s"
,
psz_host
,
i_port
,
strerror
(
i_val
)
);
#endif
}
net_Close
(
fd
);
continue
;
}
#endif
}
i_handle
=
fd
;
/* success! */
}
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
;
}
if
(
*
psz_socks
&&
*
psz_socks
!=
':'
)
{
char
*
psz_user
=
var_CreateGetString
(
p_this
,
"socks-user"
);
char
*
psz_pwd
=
var_CreateGetString
(
p_this
,
"socks-pwd"
);
if
(
SocksHandshakeTCP
(
p_this
,
i_handle
,
5
,
psz_user
,
psz_pwd
,
psz_host
,
i_port
)
)
{
msg_Err
(
p_this
,
"failed to use the SOCKS server"
);
net_Close
(
i_handle
);
i_handle
=
-
1
;
}
free
(
psz_user
);
free
(
psz_pwd
);
}
free
(
psz_socks
);
return
i_handle
;
}
/*****************************************************************************
* __net_ListenTCP:
*****************************************************************************
* Open TCP passive "listening" socket(s)
* This function returns NULL in case of error.
*****************************************************************************/
int
*
__net_ListenTCP
(
vlc_object_t
*
p_this
,
const
char
*
psz_host
,
int
i_port
)
{
struct
addrinfo
hints
,
*
res
,
*
ptr
;
int
i_val
,
*
pi_handles
,
i_size
;
memset
(
&
hints
,
0
,
sizeof
(
hints
)
);
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_flags
=
AI_PASSIVE
;
msg_Dbg
(
p_this
,
"net: listening 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
NULL
;
}
pi_handles
=
NULL
;
i_size
=
1
;
for
(
ptr
=
res
;
ptr
!=
NULL
;
ptr
=
ptr
->
ai_next
)
{
int
fd
,
*
newpi
;
fd
=
net_Socket
(
p_this
,
ptr
->
ai_family
,
ptr
->
ai_socktype
,
ptr
->
ai_protocol
);
if
(
fd
==
-
1
)
continue
;
/* 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
;
}
/* 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
;
}
}
vlc_freeaddrinfo
(
res
);
if
(
pi_handles
!=
NULL
)
pi_handles
[
i_size
-
1
]
=
-
1
;
return
pi_handles
;
}
/*****************************************************************************
* __net_Accept:
*****************************************************************************
* Accept a connection on a set of listening sockets and return it
*****************************************************************************/
int
__net_Accept
(
vlc_object_t
*
p_this
,
int
*
pi_fd
,
mtime_t
i_wait
)
{
vlc_bool_t
b_die
=
p_this
->
b_die
,
b_block
=
(
i_wait
<
0
);
while
(
p_this
->
b_die
==
b_die
)
{
int
i_val
=
-
1
,
*
pi
,
*
pi_end
;
struct
timeval
timeout
;
fd_set
fds_r
,
fds_e
;
pi
=
pi_fd
;
/* Initialize file descriptor set */
FD_ZERO
(
&
fds_r
);
FD_ZERO
(
&
fds_e
);
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
;
timeout
.
tv_sec
=
0
;
timeout
.
tv_usec
=
b_block
?
500000
:
i_wait
;
i_val
=
select
(
i_val
+
1
,
&
fds_r
,
NULL
,
&
fds_e
,
&
timeout
);
if
(
(
(
i_val
<
0
)
&&
(
errno
==
EINTR
)
)
||
i_val
==
0
)
{
if
(
b_block
)
continue
;
else
return
-
1
;
}
else
if
(
i_val
<
0
)
{
#if defined(WIN32) || defined(UNDER_CE)
msg_Err
(
p_this
,
"network select error (%i)"
,
WSAGetLastError
()
);
#else
msg_Err
(
p_this
,
"network select error (%s)"
,
strerror
(
errno
)
);
#endif
return
-
1
;
}
for
(
pi
=
pi_fd
;
*
pi
!=
-
1
;
pi
++
)
{
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
)
{
#if defined(WIN32) || defined(UNDER_CE)
msg_Err
(
p_this
,
"accept failed (%i)"
,
WSAGetLastError
()
);
#else
msg_Err
(
p_this
,
"accept failed (%s)"
,
strerror
(
errno
)
);
#endif
}
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
;
}
}
}
return
-
1
;
}
/*****************************************************************************
* 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
;
}
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
)
{
struct
addrinfo
hints
=
{
0
},
*
p_res
;
/* v4 only support ipv4 */
hints
.
ai_family
=
AF_INET
;
if
(
vlc_getaddrinfo
(
p_obj
,
psz_host
,
0
,
&
hints
,
&
p_res
)
)
return
VLC_EGENERIC
;
buffer
[
0
]
=
i_socks_version
;
buffer
[
1
]
=
0x01
;
/* CONNECT */
SetWBE
(
&
buffer
[
2
],
i_port
);
/* Port */
memcpy
(
&
buffer
[
4
],
/* Address */
&
((
struct
sockaddr_in
*
)(
p_res
->
ai_addr
))
->
sin_addr
,
4
);
vlc_freeaddrinfo
(
p_res
);
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
;
}
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
);
}
}
src/network/udp.c
0 → 100644
View file @
8acc19a5
/*****************************************************************************
* udp.c:
*****************************************************************************
* Copyright (C) 2004-2005 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir@videolan.org>
* Rémi Denis-Courmont <rem # videolan.org>
*
* 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>
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "network.h"
#ifndef INADDR_ANY
# define INADDR_ANY 0x00000000
#endif
#ifndef INADDR_NONE
# define INADDR_NONE 0xFFFFFFFF
#endif
extern
int
net_Socket
(
vlc_object_t
*
p_this
,
int
i_family
,
int
i_socktype
,
int
i_protocol
);
/*****************************************************************************
* __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
;
}
/*****************************************************************************
* __net_OpenUDP:
*****************************************************************************
* Open a UDP connection and return a handle
*****************************************************************************/
int
__net_OpenUDP
(
vlc_object_t
*
p_this
,
const
char
*
psz_bind
,
int
i_bind
,
const
char
*
psz_server
,
int
i_server
)
{
vlc_value_t
v4
,
v6
;
void
*
private
;
network_socket_t
sock
;
module_t
*
p_network
=
NULL
;
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"
);
if
(
psz_server
==
NULL
)
psz_server
=
""
;
if
(
psz_bind
==
NULL
)
psz_bind
=
""
;
/* 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
;
sock
.
v6only
=
0
;
sock
.
i_handle
=
-
1
;
msg_Dbg
(
p_this
,
"net: connecting to '[%s]:%d@[%s]:%d'"
,
psz_server
,
i_server
,
psz_bind
,
i_bind
);
/* 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
)
{
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
;
}
}
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
);
return
sock
.
i_handle
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment