📄 tcp.c
字号:
/***************************************************************************** * tcp.c: ***************************************************************************** * Copyright (C) 2004-2005 the VideoLAN team * Copyright (C) 2005-2006 Rémi Denis-Courmont * $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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <errno.h>#include <assert.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#ifdef HAVE_POLL# include <poll.h>#endif#include <vlc_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 SocksNegotiate( vlc_object_t *, int fd, int i_socks_version, const char *psz_user, const char *psz_passwd );static int SocksHandshakeTCP( vlc_object_t *, int fd, int i_socks_version, const char *psz_user, const char *psz_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_Connect: ***************************************************************************** * Open a network connection. * @return socket handler or -1 on error. *****************************************************************************/int __net_Connect( vlc_object_t *p_this, const char *psz_host, int i_port, int type, int proto ){ struct addrinfo hints, *res, *ptr; const char *psz_realhost; char *psz_socks; int i_realport, i_val, i_handle = -1; int evfd = vlc_object_waitpipe (p_this); if (evfd == -1) return -1; memset( &hints, 0, sizeof( hints ) ); hints.ai_socktype = SOCK_STREAM; psz_socks = var_CreateGetNonEmptyString( p_this, "socks" ); if( psz_socks != NULL ) { char *psz = strchr( psz_socks, ':' ); if( psz ) *psz++ = '\0'; 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 ); /* 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 { 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 ); 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 ) ); return -1; } for( ptr = res; ptr != NULL; ptr = ptr->ai_next ) { int fd = net_Socket( p_this, ptr->ai_family, type ?: ptr->ai_socktype, proto ?: ptr->ai_protocol ); if( fd == -1 ) { msg_Dbg( p_this, "socket error: %m" ); continue; } if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) ) { int timeout, val; if( net_errno != EINPROGRESS && net_errno != EINTR ) { msg_Err( p_this, "connection failed: %m" ); goto next_ai; } msg_Dbg( p_this, "connection: %m" ); timeout = var_CreateGetInteger (p_this, "ipv4-timeout"); if (timeout < 0) { msg_Err( p_this, "invalid negative value for ipv4-timeout" ); timeout = 0; } struct pollfd ufd[2] = { { .fd = fd, .events = POLLOUT }, { .fd = evfd, .events = POLLIN }, }; do /* NOTE: timeout screwed up if we catch a signal (EINTR) */ val = poll (ufd, sizeof (ufd) / sizeof (ufd[0]), timeout); while ((val == -1) && (net_errno == EINTR)); switch (val) { case -1: /* error */ msg_Err (p_this, "connection polling error: %m"); goto next_ai; case 0: /* timeout */ msg_Warn (p_this, "connection timed out"); goto next_ai; default: /* something happended */ if (ufd[1].revents) goto next_ai; /* LibVLC object killed */ } /* There is NO WAY around checking SO_ERROR. * Don't ifdef it out!!! */ if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &val, &(socklen_t){ sizeof (val) }) || val) { errno = val; msg_Err (p_this, "connection failed: %m"); goto next_ai; } } msg_Dbg( p_this, "connection succeeded (socket = %d)", fd ); i_handle = fd; /* success! */ break;next_ai: /* failure */ net_Close( fd ); continue; } vlc_freeaddrinfo( res ); if( i_handle == -1 ) return -1; if( psz_socks != NULL ) { /* NOTE: psz_socks already free'd! */ char *psz_user = var_CreateGetNonEmptyString( p_this, "socks-user" ); char *psz_pwd = var_CreateGetNonEmptyString( p_this, "socks-pwd" ); if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd, psz_host, i_port ) ) { msg_Err( p_this, "SOCKS handshake failed" ); net_Close( i_handle ); i_handle = -1; } free( psz_user ); free( psz_pwd ); } return i_handle;}int net_AcceptSingle (vlc_object_t *obj, int lfd){ int fd; do fd = accept (lfd, NULL, NULL); while (fd == -1 && errno == EINTR); if (fd == -1) { if (net_errno != EAGAIN) msg_Err (obj, "accept failed (from socket %d): %m", lfd); return -1; } msg_Dbg (obj, "accepted socket %d (from socket %d)", fd, lfd); net_SetupSocket (fd); return fd;}/***************************************************************************** * __net_Accept: ***************************************************************************** * Accept a connection on a set of listening sockets and return it *****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -