📄 net.c
字号:
/***************************************************************************** * net.c: ***************************************************************************** * Copyright (C) 2004 VideoLAN * $Id: net.c 10947 2005-05-09 19:01:25Z courmisch $ * * Authors: Laurent Aimar <fenrir@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#if defined( UNDER_CE )# include <winsock.h>#elif defined( WIN32 )# include <winsock2.h># include <ws2tcpip.h># ifndef IN_MULTICAST# define IN_MULTICAST(a) IN_CLASSD(a)# endif#else# include <sys/socket.h># include <netinet/in.h># ifdef HAVE_ARPA_INET_H# include <arpa/inet.h># endif# include <netdb.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#elif defined( WIN32 ) && !defined( UNDER_CE )# include <io.h>#endif#include "network.h"#ifndef INADDR_ANY# define INADDR_ANY 0x00000000#endif#ifndef INADDR_NONE# define INADDR_NONE 0xFFFFFFFF#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 );/***************************************************************************** * net_ConvertIPv4: ***************************************************************************** * Open a TCP connection and return a handle *****************************************************************************/int net_ConvertIPv4( uint32_t *p_addr, const char * psz_address ){ /* Reset struct */ if( !*psz_address ) { *p_addr = INADDR_ANY; } else { struct hostent *p_hostent; /* Try to convert address directly from in_addr - this will work if * psz_address is dotted decimal. */#ifdef HAVE_ARPA_INET_H if( !inet_aton( psz_address, (struct in_addr *)p_addr ) )#else *p_addr = inet_addr( psz_address ); if( *p_addr == INADDR_NONE )#endif { /* We have a fqdn, try to find its address */ if ( (p_hostent = gethostbyname( psz_address )) == NULL ) { return VLC_EGENERIC; } /* Copy the first address of the host in the socket address */ memcpy( p_addr, p_hostent->h_addr_list[0], p_hostent->h_length ); } } return VLC_SUCCESS;}/***************************************************************************** * __net_OpenTCP: ***************************************************************************** * Open a TCP connection and return a handle *****************************************************************************/int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port ){ vlc_value_t val; void *private; char *psz_network = ""; network_socket_t sock; module_t *p_network; /* Check if we have force ipv4 or ipv6 */ var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv4", &val ); if( val.b_bool ) { psz_network = "ipv4"; } var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv6", &val ); if( val.b_bool ) { psz_network = "ipv6"; } /* Prepare the network_socket_t structure */ sock.i_type = NETWORK_TCP; sock.psz_bind_addr = ""; sock.i_bind_port = 0; sock.i_ttl = 0; var_Create( p_this, "socks", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_this, "socks", &val ); if( *val.psz_string && *val.psz_string != ':' ) { char *psz = strchr( val.psz_string, ':' ); if( psz ) *psz++ = '\0'; sock.psz_server_addr = (char*)val.psz_string; sock.i_server_port = psz ? atoi( psz ) : 1080; msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'", sock.psz_server_addr, sock.i_server_port, psz_host, i_port ); } else { sock.psz_server_addr = (char*)psz_host; sock.i_server_port = i_port; msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port ); } private = p_this->p_private; p_this->p_private = (void*)&sock; if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) ) { msg_Dbg( p_this, "net: connection to '%s:%d' failed", psz_host, i_port ); return -1; } module_Unneed( p_this, p_network ); p_this->p_private = private; if( *val.psz_string && *val.psz_string != ':' ) { char *psz_user = var_CreateGetString( p_this, "socks-user" ); char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" ); if( SocksHandshakeTCP( p_this, sock.i_handle, 5, psz_user, psz_pwd, psz_host, i_port ) ) { msg_Err( p_this, "failed to use the SOCKS server" ); net_Close( sock.i_handle ); return -1; } free( psz_user ); free( psz_pwd ); } free( val.psz_string ); return sock.i_handle;}/***************************************************************************** * __net_ListenTCP: ***************************************************************************** * Open a TCP listening socket and return it *****************************************************************************/int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port ){ vlc_value_t val; void *private; char *psz_network = ""; network_socket_t sock; module_t *p_network; /* Check if we have force ipv4 or ipv6 */ var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv4", &val ); if( val.b_bool ) { psz_network = "ipv4"; } var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv6", &val ); if( val.b_bool ) { psz_network = "ipv6"; } /* Prepare the network_socket_t structure */ sock.i_type = NETWORK_TCP_PASSIVE; sock.psz_bind_addr = ""; sock.i_bind_port = 0; sock.psz_server_addr = psz_host; sock.i_server_port = i_port; sock.i_ttl = 0; msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port ); private = p_this->p_private; p_this->p_private = (void*)&sock; if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) ) { msg_Dbg( p_this, "net: listening to '%s:%d' failed", psz_host, i_port ); return -1; } module_Unneed( p_this, p_network ); p_this->p_private = private; return sock.i_handle;}/***************************************************************************** * __net_Accept: ***************************************************************************** * Accept a connection on a listening socket and return it *****************************************************************************/int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait ){ vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0); struct timeval timeout; fd_set fds_r, fds_e; int i_ret; while( p_this->b_die == b_die ) { /* Initialize file descriptor set */ FD_ZERO( &fds_r ); FD_SET( fd, &fds_r ); FD_ZERO( &fds_e ); FD_SET( fd, &fds_e ); timeout.tv_sec = 0; timeout.tv_usec = b_block ? 500000 : i_wait; i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout); if( (i_ret < 0 && errno == EINTR) || i_ret == 0 ) { if( b_block ) continue; else return -1; } else if( i_ret < 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; } if( ( i_ret = accept( fd, 0, 0 ) ) <= 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 return -1; } return i_ret; } return -1;}/***************************************************************************** * __net_OpenUDP: ***************************************************************************** * Open a UDP connection and return a handle *****************************************************************************/int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind, char *psz_server, int i_server ){ vlc_value_t val; void *private; char *psz_network = ""; network_socket_t sock; module_t *p_network; /* Check if we have force ipv4 or ipv6 */ var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv4", &val ); if( val.b_bool ) { psz_network = "ipv4"; } var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_this, "ipv6", &val ); if( val.b_bool ) { psz_network = "ipv6"; } if( psz_server == NULL ) psz_server = ""; if( psz_bind == NULL ) psz_bind = ""; /* Prepare the network_socket_t structure */ sock.i_type = NETWORK_UDP; 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; msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'", psz_server, i_server, psz_bind, i_bind ); private = p_this->p_private; p_this->p_private = (void*)&sock; if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) ) { msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed", psz_server, i_server, psz_bind, i_bind ); return -1; } module_Unneed( p_this, p_network ); p_this->p_private = private; return sock.i_handle;}/***************************************************************************** * __net_Close: ***************************************************************************** * Close a network handle *****************************************************************************/void net_Close( int fd ){#ifdef UNDER_CE CloseHandle( (HANDLE)fd );#elif defined( WIN32 ) closesocket( fd );#else close( fd );#endif}/***************************************************************************** * __net_Read: ***************************************************************************** * Read from a network socket * If b_rety is true, then we repeat until we have read the right amount of * data *****************************************************************************/int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs, uint8_t *p_data, int i_data, vlc_bool_t b_retry ){ struct timeval timeout; fd_set fds_r, fds_e; int i_recv; int i_total = 0; int i_ret; vlc_bool_t b_die = p_this->b_die; while( i_data > 0 ) { do { if( p_this->b_die != b_die ) { return 0; } /* Initialize file descriptor set */ FD_ZERO( &fds_r ); FD_SET( fd, &fds_r ); FD_ZERO( &fds_e ); FD_SET( fd, &fds_e ); /* We'll wait 0.5 second if nothing happens */ timeout.tv_sec = 0; timeout.tv_usec = 500000; } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0 || ( i_ret < 0 && errno == EINTR ) ); if( i_ret < 0 ) {#if defined(WIN32) || defined(UNDER_CE) msg_Err( p_this, "network select error" );#else msg_Err( p_this, "network select error (%s)", strerror(errno) );#endif return i_total > 0 ? i_total : -1; } if( ( i_recv = (p_vs != NULL) ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data ) : recv( fd, p_data, i_data, 0 ) ) < 0 ) {#if defined(WIN32) || defined(UNDER_CE) if( WSAGetLastError() == WSAEWOULDBLOCK ) { /* only happens with p_vs (SSL) - not really an error */ } else /* For udp only */ /* On win32 recv() will fail if the datagram doesn't fit inside * the passed buffer, even though the buffer will be filled with * the first part of the datagram. */ if( WSAGetLastError() == WSAEMSGSIZE ) { msg_Err( p_this, "recv() failed. " "Increase the mtu size (--mtu option)" ); i_total += i_data; } else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );#else /* EAGAIN only happens with p_vs (SSL) and it's not an error */ if( errno != EAGAIN ) msg_Err( p_this, "recv failed (%s)", strerror(errno) );#endif return i_total > 0 ? i_total : -1; } else if( i_recv == 0 ) { /* Connection closed */ b_retry = VLC_FALSE; } p_data += i_recv; i_data -= i_recv; i_total+= i_recv; if( !b_retry ) { break; } } return i_total;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -