X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Ftcp.c;h=7bfd3a99d5ab575d4816baabd4d13d3b9d0011b3;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=c5ed0034c425f4d942e99ad10b8672cc52c5d209;hpb=f9279bb46db3777459df7c0fb67b01ead1ffa0ee;p=vlc diff --git a/src/network/tcp.c b/src/network/tcp.c index c5ed0034c4..7bfd3a99d5 100644 --- a/src/network/tcp.c +++ b/src/network/tcp.c @@ -26,7 +26,6 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include #include #include @@ -40,6 +39,9 @@ #ifdef HAVE_UNISTD_H # include #endif +#ifdef HAVE_POLL +# include +#endif #include #if defined (WIN32) || defined (UNDER_CE) @@ -72,8 +74,7 @@ int __net_Connect( 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, i_saved_errno = 0; - unsigned u_errstep = 0; + int i_realport, i_val, i_handle = -1; if( i_port == 0 ) i_port = 80; /* historical VLC thing */ @@ -81,8 +82,8 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, memset( &hints, 0, sizeof( hints ) ); hints.ai_socktype = SOCK_STREAM; - psz_socks = var_CreateGetString( p_this, "socks" ); - if( *psz_socks && *psz_socks != ':' ) + psz_socks = var_CreateGetNonEmptyString( p_this, "socks" ); + if( psz_socks != NULL ) { char *psz = strchr( psz_socks, ':' ); @@ -91,9 +92,35 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, psz_realhost = psz_socks; i_realport = ( psz != NULL ) ? atoi( psz ) : 1080; + hints.ai_flags &= ~AI_NUMERICHOST; + + msg_Dbg( p_this, "net: connecting to %s port %d (SOCKS) " + "for %s port %d", psz_realhost, i_realport, + psz_host, i_port ); - msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d", - psz_realhost, i_realport, psz_host, i_port ); + /* We only implement TCP with SOCKS */ + switch( type ) + { + case 0: + type = SOCK_STREAM; + case SOCK_STREAM: + break; + default: + msg_Err( p_this, "Socket type not supported through SOCKS" ); + free( psz_socks ); + return -1; + } + switch( proto ) + { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: + break; + default: + msg_Err( p_this, "Transport not supported through SOCKS" ); + free( psz_socks ); + return -1; + } } else { @@ -105,11 +132,12 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, } i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res ); + free( psz_socks ); + 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; } @@ -119,11 +147,6 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, proto ?: ptr->ai_protocol ); if( fd == -1 ) { - if( u_errstep <= 0 ) - { - u_errstep = 1; - i_saved_errno = net_errno; - } msg_Dbg( p_this, "socket error: %s", strerror( net_errno ) ); continue; } @@ -132,17 +155,12 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, { socklen_t i_val_size = sizeof( i_val ); div_t d; - struct timeval tv; vlc_value_t timeout; if( net_errno != EINPROGRESS ) { - if( u_errstep <= 1 ) - { - u_errstep = 2; - i_saved_errno = net_errno; - } - msg_Dbg( p_this, "connect error: %s", strerror( net_errno ) ); + msg_Err( p_this, "connection failed: %s", + strerror( net_errno ) ); goto next_ai; } @@ -159,7 +177,7 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, msg_Dbg( p_this, "connection in progress" ); for (;;) { - fd_set fds; + struct pollfd ufd = { .fd = fd, .events = POLLOUT }; int i_ret; if( p_this->b_die ) @@ -167,41 +185,28 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, 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 * NOTE: * time out will be shortened if we catch a signal (EINTR) */ - tv.tv_sec = 0; - tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem); - - i_ret = select( fd + 1, NULL, &fds, NULL, &tv ); + i_ret = poll (&ufd, 1, (d.quot > 0) ? 100 : d.rem); if( i_ret == 1 ) break; if( ( i_ret == -1 ) && ( net_errno != EINTR ) ) { - msg_Warn( p_this, "select error: %s", + msg_Err( p_this, "connection polling error: %s", strerror( net_errno ) ); goto next_ai; } if( d.quot <= 0 ) { - msg_Dbg( p_this, "select timed out" ); - if( u_errstep <= 2 ) - { - u_errstep = 3; - i_saved_errno = ETIMEDOUT; - } + msg_Warn( p_this, "connection timed out" ); goto next_ai; } @@ -212,9 +217,7 @@ int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val, &i_val_size ) == -1 || i_val != 0 ) { - u_errstep = 4; - i_saved_errno = i_val; - msg_Dbg( p_this, "connect error (via getsockopt): %s", + msg_Err( p_this, "connection failed: %s", net_strerror( i_val ) ); goto next_ai; } @@ -232,22 +235,18 @@ next_ai: /* failure */ vlc_freeaddrinfo( res ); if( i_handle == -1 ) - { - msg_Err( p_this, "Connection to %s port %d failed: %s", psz_host, - i_port, net_strerror( i_saved_errno ) ); - free( psz_socks ); return -1; - } - if( *psz_socks && *psz_socks != ':' ) + if( psz_socks != NULL ) { + /* NOTE: psz_socks already free'd! */ 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" ); + msg_Err( p_this, "SOCKS handshake failed" ); net_Close( i_handle ); i_handle = -1; } @@ -255,7 +254,6 @@ next_ai: /* failure */ free( psz_user ); free( psz_pwd ); } - free( psz_socks ); return i_handle; } @@ -272,50 +270,43 @@ int __net_Accept( vlc_object_t *p_this, int pi_fd[], mtime_t i_wait ) while( !p_this->b_die ) { - int maxfd = -1; - fd_set readset; + unsigned n = 0; + while (pi_fd[n] != -1) + n++; + struct pollfd ufd[n]; /* Initialize file descriptor set */ - FD_ZERO (&readset); - - int *pi_end = pi_fd; - for (const int *pi = pi_fd; *pi != -1; pi++) + for (unsigned i = 0; i < n; i++) { - int fd = *pi; - - if (fd > maxfd) - maxfd = fd; - - FD_SET (fd, &readset); - pi_end++; + ufd[i].fd = pi_fd[i]; + ufd[i].events = POLLIN; + ufd[i].revents = 0; } - struct timeval tv = { 0, b_block ? 500000 : i_wait }; - - int val = select (maxfd + 1, &readset, NULL, NULL, &tv); - if (val == 0) - { - if (b_block) - continue; - return -1; - } - if (val < 0) + switch (poll (ufd, n, b_block ? 500 : i_wait)) { - if (net_errno != EINTR) - msg_Err( p_this, "network select error (%s)", - net_strerror( net_errno ) ); - return -1; + case -1: + if (net_errno != EINTR) + { + msg_Err (p_this, "poll error: %s", + net_strerror (net_errno)); + } + return -1; + + case 0: + if (b_block) + continue; + return -1; } - for (const int *pi = pi_fd; *pi != -1; pi++) + for (unsigned i = 0; i < n; i++) { - int fd = *pi; - - if (!FD_ISSET (fd, &readset)) + if (ufd[i].revents == 0) continue; - fd = accept (fd, NULL, 0); - if (fd < 0) + int sfd = ufd[i].fd; + int fd = accept (sfd, NULL, NULL); + if (fd == -1) { msg_Err (p_this, "accept failed (%s)", net_strerror (net_errno)); @@ -324,13 +315,12 @@ int __net_Accept( vlc_object_t *p_this, int pi_fd[], mtime_t i_wait ) net_SetupSocket (fd); /* - * This round-robin trick ensures that the first sockets in - * pi_fd won't prevent the last ones from getting accept'ed. + * Move listening socket to the end to let the others in the + * set a chance next time. */ - --pi_end; - memmove (pi_fd, pi_fd + 1, pi_end - pi_fd); - *pi_end = *pi; - msg_Dbg (p_this, "accepted socket %d (from socket %d)", fd, *pi); + memmove (pi_fd + i, pi_fd + i + 1, n - (i + 1)); + pi_fd[n - 1] = sfd; + msg_Dbg (p_this, "accepted socket %d (from socket %d)", fd, sfd); return fd; } } @@ -448,7 +438,7 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj, i_socks_version = 5; } - if( 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; @@ -458,7 +448,7 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj, struct addrinfo hints, *p_res; /* v4 only support ipv4 */ - memset (&hints, 0, sizeof (hints)); + memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_INET; if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) ) return VLC_EGENERIC; @@ -523,7 +513,7 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj, i_len = buffer[4] + 2; else if( buffer[3] == 0x04 ) i_len = 16-1+2; - else + else return VLC_EGENERIC; if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )