51
58
# define ETIMEDOUT WSAETIMEDOUT
54
static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
55
char *psz_socks_user, char *psz_socks_passwd );
61
static int SocksNegotiate( vlc_object_t *, int fd, int i_socks_version,
62
const char *psz_user, const char *psz_passwd );
56
63
static int SocksHandshakeTCP( vlc_object_t *,
57
64
int fd, int i_socks_version,
58
char *psz_socks_user, char *psz_socks_passwd,
65
const char *psz_user, const char *psz_passwd,
59
66
const char *psz_host, int i_port );
60
67
extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
62
extern int rootwrap_bind (int family, int socktype, int protocol,
63
const struct sockaddr *addr, size_t alen);
65
70
/*****************************************************************************
67
72
*****************************************************************************
68
* Open a TCP connection and return a handle
73
* Open a network connection.
74
* @return socket handler or -1 on error.
69
75
*****************************************************************************/
70
int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
76
int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port,
72
79
struct addrinfo hints, *res, *ptr;
73
80
const char *psz_realhost;
75
int i_realport, i_val, i_handle = -1, i_saved_errno = 0;
76
unsigned u_errstep = 0;
82
int i_realport, i_val, i_handle = -1;
79
i_port = 80; /* historical VLC thing */
84
int evfd = vlc_object_waitpipe (p_this);
81
88
memset( &hints, 0, sizeof( hints ) );
82
89
hints.ai_socktype = SOCK_STREAM;
84
psz_socks = var_CreateGetString( p_this, "socks" );
85
if( *psz_socks && *psz_socks != ':' )
91
psz_socks = var_CreateGetNonEmptyString( p_this, "socks" );
92
if( psz_socks != NULL )
87
94
char *psz = strchr( psz_socks, ':' );
92
99
psz_realhost = psz_socks;
93
100
i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
95
msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
96
psz_realhost, i_realport, psz_host, i_port );
101
hints.ai_flags &= ~AI_NUMERICHOST;
103
msg_Dbg( p_this, "net: connecting to %s port %d (SOCKS) "
104
"for %s port %d", psz_realhost, i_realport,
107
/* We only implement TCP with SOCKS */
115
msg_Err( p_this, "Socket type not supported through SOCKS" );
126
msg_Err( p_this, "Transport not supported through SOCKS" );
107
140
i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
110
145
msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
111
146
i_realport, vlc_gai_strerror( i_val ) );
116
150
for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
118
int fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
152
int fd = net_Socket( p_this, ptr->ai_family, type ?: ptr->ai_socktype,
153
proto ?: ptr->ai_protocol );
125
i_saved_errno = net_errno;
127
msg_Dbg( p_this, "socket error: %s", strerror( net_errno ) );
156
msg_Dbg( p_this, "socket error: %m" );
131
160
if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
133
socklen_t i_val_size = sizeof( i_val );
138
if( net_errno != EINPROGRESS )
164
if( net_errno != EINPROGRESS && net_errno != EINTR )
143
i_saved_errno = net_errno;
145
msg_Dbg( p_this, "connect error: %s", strerror( net_errno ) );
166
msg_Err( p_this, "connection failed: %m" );
169
msg_Dbg( p_this, "connection: %m" );
149
var_Create( p_this, "ipv4-timeout",
150
VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
151
var_Get( p_this, "ipv4-timeout", &timeout );
152
if( timeout.i_int < 0 )
171
timeout = var_CreateGetInteger (p_this, "ipv4-timeout");
154
174
msg_Err( p_this, "invalid negative value for ipv4-timeout" );
157
d = div( timeout.i_int, 100 );
159
msg_Dbg( p_this, "connection in progress" );
167
msg_Dbg( p_this, "connection aborted" );
169
vlc_freeaddrinfo( res );
174
/* Initialize file descriptor set */
179
* We'll wait 0.1 second if nothing happens
181
* time out will be shortened if we catch a signal (EINTR)
184
tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
186
i_ret = select( fd + 1, NULL, &fds, NULL, &tv );
190
if( ( i_ret == -1 ) && ( net_errno != EINTR ) )
192
msg_Warn( p_this, "select error: %s",
193
strerror( net_errno ) );
199
msg_Dbg( p_this, "select timed out" );
203
i_saved_errno = ETIMEDOUT;
211
#if !defined( SYS_BEOS ) && !defined( UNDER_CE )
212
if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
213
&i_val_size ) == -1 || i_val != 0 )
216
i_saved_errno = i_val;
217
msg_Dbg( p_this, "connect error (via getsockopt): %s",
218
net_strerror( i_val ) );
178
struct pollfd ufd[2] = {
179
{ .fd = fd, .events = POLLOUT },
180
{ .fd = evfd, .events = POLLIN },
184
/* NOTE: timeout screwed up if we catch a signal (EINTR) */
185
val = poll (ufd, sizeof (ufd) / sizeof (ufd[0]), timeout);
186
while ((val == -1) && (net_errno == EINTR));
191
msg_Err (p_this, "connection polling error: %m");
194
case 0: /* timeout */
195
msg_Warn (p_this, "connection timed out");
198
default: /* something happended */
200
goto next_ai; /* LibVLC object killed */
203
/* There is NO WAY around checking SO_ERROR.
204
* Don't ifdef it out!!! */
205
if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &val,
206
&(socklen_t){ sizeof (val) }) || val)
209
msg_Err (p_this, "connection failed: %m");
214
msg_Dbg( p_this, "connection succeeded (socket = %d)", fd );
224
215
i_handle = fd; /* success! */
232
223
vlc_freeaddrinfo( res );
234
225
if( i_handle == -1 )
236
msg_Err( p_this, "Connection to %s port %d failed: %s", psz_host,
237
i_port, net_strerror( i_saved_errno ) );
242
if( *psz_socks && *psz_socks != ':' )
228
if( psz_socks != NULL )
244
char *psz_user = var_CreateGetString( p_this, "socks-user" );
245
char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
230
/* NOTE: psz_socks already free'd! */
231
char *psz_user = var_CreateGetNonEmptyString( p_this, "socks-user" );
232
char *psz_pwd = var_CreateGetNonEmptyString( p_this, "socks-pwd" );
247
234
if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
248
235
psz_host, i_port ) )
250
msg_Err( p_this, "Failed to use the SOCKS server" );
237
msg_Err( p_this, "SOCKS handshake failed" );
251
238
net_Close( i_handle );
255
242
free( psz_user );
264
/*****************************************************************************
266
*****************************************************************************
267
* Open TCP passive "listening" socket(s)
268
* This function returns NULL in case of error.
269
*****************************************************************************/
270
int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
250
int net_AcceptSingle (vlc_object_t *obj, int lfd)
272
struct addrinfo hints, *res, *ptr;
273
int i_val, *pi_handles, i_size;
275
memset( &hints, 0, sizeof( hints ) );
276
hints.ai_socktype = SOCK_STREAM;
277
hints.ai_flags = AI_PASSIVE;
279
msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
281
i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
284
msg_Err( p_this, "Cannot resolve %s port %d : %s", psz_host, i_port,
285
vlc_gai_strerror( i_val ) );
292
for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
296
fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
300
msg_Dbg( p_this, "socket error: %s", net_strerror( net_errno ) );
304
/* Bind the socket */
305
if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
309
saved_errno = net_errno;
311
#if !defined(WIN32) && !defined(UNDER_CE)
312
fd = rootwrap_bind( ptr->ai_family, ptr->ai_socktype,
313
ptr->ai_protocol, ptr->ai_addr,
317
msg_Dbg( p_this, "got socket %d from rootwrap", fd );
322
msg_Err( p_this, "cannot bind socket (%s)",
323
net_strerror( saved_errno ) );
329
if( listen( fd, 100 ) == -1 )
331
msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
332
net_strerror( net_errno ) );
337
newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
345
newpi[i_size - 2] = fd;
350
vlc_freeaddrinfo( res );
352
if( pi_handles != NULL )
353
pi_handles[i_size - 1] = -1;
254
fd = accept (lfd, NULL, NULL);
255
while (fd == -1 && errno == EINTR);
259
if (net_errno != EAGAIN)
260
msg_Err (obj, "accept failed (from socket %d): %m", lfd);
264
msg_Dbg (obj, "accepted socket %d (from socket %d)", fd, lfd);
265
net_SetupSocket (fd);
357
270
/*****************************************************************************
359
272
*****************************************************************************
361
274
*****************************************************************************/
362
275
int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
364
vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
366
while( p_this->b_die == b_die )
277
int timeout = (i_wait < 0) ? -1 : i_wait / 1000;
278
int evfd = vlc_object_waitpipe (p_this);
283
assert( pi_fd != NULL );
368
int i_val = -1, *pi, *pi_end;
369
struct timeval timeout;
288
while (pi_fd[n] != -1)
290
struct pollfd ufd[n + 1];
374
292
/* Initialize file descriptor set */
378
for( pi = pi_fd; *pi != -1; pi++ )
385
FD_SET( i_fd, &fds_r );
386
FD_SET( i_fd, &fds_e );
391
timeout.tv_usec = b_block ? 500000 : i_wait;
393
i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
394
if( ( ( i_val < 0 ) && ( net_errno == EINTR ) ) || i_val == 0 )
403
msg_Err( p_this, "network select error (%s)",
404
net_strerror( net_errno ) );
408
for( pi = pi_fd; *pi != -1; pi++ )
412
if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
415
i_val = accept( i_fd, NULL, 0 );
417
msg_Err( p_this, "accept failed (%s)",
418
net_strerror( net_errno ) );
420
else if( i_val >= FD_SETSIZE )
422
net_Close( i_val ); /* avoid future overflows in FD_SET */
423
msg_Err( p_this, "accept failed (too many sockets opened)" );
429
setsockopt( i_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof( yes ));
431
fcntl( i_fd, F_SETFD, FD_CLOEXEC );
434
* This round-robin trick ensures that the first sockets in
435
* pi_fd won't prevent the last ones from getting accept'ed.
438
memmove( pi, pi + 1, pi_end - pi );
293
for (unsigned i = 0; i <= n; i++)
295
ufd[i].fd = (i < n) ? pi_fd[i] : evfd;
296
ufd[i].events = POLLIN;
300
n--; /* avoid EBADF */
302
switch (poll (ufd, n, timeout))
305
if (net_errno == EINTR)
307
msg_Err (p_this, "poll error: %m");
320
for (unsigned i = 0; i < n; i++)
322
if (ufd[i].revents == 0)
326
int fd = net_AcceptSingle (p_this, sfd);
331
* Move listening socket to the end to let the others in the
332
* set a chance next time.
334
memmove (pi_fd + i, pi_fd + i + 1, n - (i + 1));
449
343
/*****************************************************************************
451
345
*****************************************************************************
452
* Negociate authentication with a SOCKS server.
346
* Negotiate authentication with a SOCKS server.
453
347
*****************************************************************************/
454
static int SocksNegociate( vlc_object_t *p_obj,
348
static int SocksNegotiate( vlc_object_t *p_obj,
455
349
int fd, int i_socks_version,
456
char *psz_socks_user,
457
char *psz_socks_passwd )
350
const char *psz_socks_user,
351
const char *psz_socks_passwd )
459
353
uint8_t buffer[128+2*256];
461
vlc_bool_t b_auth = VLC_FALSE;
463
357
if( i_socks_version != 5 )
464
358
return VLC_SUCCESS;
466
/* We negociate authentication */
360
/* We negotiate authentication */
468
if( psz_socks_user && psz_socks_passwd &&
469
*psz_socks_user && *psz_socks_passwd )
362
if( ( psz_socks_user == NULL ) && ( psz_socks_passwd == NULL ) )
472
365
buffer[0] = i_socks_version; /* SOCKS version */