📄 tcp.c
字号:
/***************************************************************************** * tcp.c: ***************************************************************************** * Copyright (C) 2004-2005 the VideoLAN team * Copyright (C) 2005-2006 Rémi Denis-Courmont * $Id: tcp.c 16544 2006-09-07 23:05:11Z hartman $ * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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"#if defined (WIN32) || defined (UNDER_CE)# undef EINPROGRESS# define EINPROGRESS WSAEWOULDBLOCK# undef EINTR# define EINTR WSAEINTR# undef ETIMEDOUT# define ETIMEDOUT WSAETIMEDOUT#endifstatic 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 );extern int rootwrap_bind (int family, int socktype, int protocol, const struct sockaddr *addr, size_t alen);/***************************************************************************** * __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, i_saved_errno = 0; unsigned u_errstep = 0; 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; ptr = ptr->ai_next ) { int fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype, 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; } 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( 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 ) ); goto next_ai; } 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" ); for (;;) { fd_set fds; int i_ret; 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 * 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 ); if( i_ret == 1 ) break; if( ( i_ret == -1 ) && ( net_errno != EINTR ) ) { msg_Warn( p_this, "select 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; } goto next_ai; } d.quot--; }#if !defined( SYS_BEOS ) && !defined( UNDER_CE ) 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", net_strerror( i_val ) ); goto next_ai; }#endif } i_handle = fd; /* success! */ break;next_ai: /* failure */ net_Close( fd ); continue; } 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 != ':' ) { 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 ) { msg_Dbg( p_this, "socket error: %s", net_strerror( net_errno ) ); continue; } /* Bind the socket */ if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) ) { int saved_errno; saved_errno = net_errno; net_Close( fd );#if !defined(WIN32) && !defined(UNDER_CE) fd = rootwrap_bind( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol, ptr->ai_addr, ptr->ai_addrlen ); if( fd != -1 ) { msg_Dbg( p_this, "got socket %d from rootwrap", fd ); } else#endif { msg_Err( p_this, "cannot bind socket (%s)", net_strerror( saved_errno ) ); continue; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -