📄 io.c
字号:
/***************************************************************************** * io.c: network I/O functions ***************************************************************************** * Copyright (C) 2004-2005 the VideoLAN team * $Id: io.c 17659 2006-11-11 16:50:15Z md $ * * 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"#ifndef INADDR_ANY# define INADDR_ANY 0x00000000#endif#ifndef INADDR_NONE# define INADDR_NONE 0xFFFFFFFF#endifint net_Socket( vlc_object_t *p_this, int i_family, int i_socktype, int i_protocol ){ int fd, i_val; fd = socket( i_family, i_socktype, i_protocol ); if( fd == -1 ) {#if defined(WIN32) || defined(UNDER_CE) if( WSAGetLastError ( ) != WSAEAFNOSUPPORT ) msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );#else if( errno != EAFNOSUPPORT ) msg_Warn( p_this, "cannot create socket (%s)", strerror( errno ) );#endif return -1; }#if defined( WIN32 ) || defined( UNDER_CE ) { unsigned long i_dummy = 1; if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 ) msg_Err( p_this, "cannot set socket to non-blocking mode" ); }#else if( fd >= FD_SETSIZE ) { /* We don't want to overflow select() fd_set */ msg_Err( p_this, "cannot create socket (too many already in use)" ); net_Close( fd ); return -1; } fcntl( fd, F_SETFD, FD_CLOEXEC ); i_val = fcntl( fd, F_GETFL, 0 ); fcntl( fd, F_SETFL, ((i_val != -1) ? i_val : 0) | O_NONBLOCK );#endif i_val = 1; setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val, sizeof( i_val ) );#ifdef IPV6_V6ONLY /* * Accepts only IPv6 connections on IPv6 sockets * (and open an IPv4 socket later as well if needed). * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets, * so this allows for more uniform handling across platforms. Besides, * it makes sure that IPv4 addresses will be printed as w.x.y.z rather * than ::ffff:w.x.y.z */ if( i_family == AF_INET6 ) setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val, sizeof( i_val ) );#endif#if defined( WIN32 ) || defined( UNDER_CE )# ifndef IPV6_PROTECTION_LEVEL# define IPV6_PROTECTION_LEVEL 23# endif if( i_family == AF_INET6 ) { i_val = 10 /*PROTECTION_LEVEL_UNRESTRICTED*/; setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&i_val, sizeof( i_val ) ); }#endif return fd;}/***************************************************************************** * __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_retry 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 (%d)", WSAGetLastError() );#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 if( WSAGetLastError() == WSAEINTR ) continue; else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );#else /* EAGAIN only happens with p_vs (TLS) 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;}/***************************************************************************** * __net_ReadNonBlock: ***************************************************************************** * Read from a network socket, non blocking mode (with timeout) *****************************************************************************/int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs, uint8_t *p_data, int i_data, mtime_t i_wait){ struct timeval timeout; fd_set fds_r, fds_e; int i_recv; int i_ret; /* 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 = i_wait; i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout); if( i_ret < 0 && errno == EINTR ) { return 0; } else if( i_ret < 0 ) {#if defined(WIN32) || defined(UNDER_CE) msg_Err( p_this, "network select error (%d)", WSAGetLastError() );#else msg_Err( p_this, "network select error (%s)", strerror(errno) );#endif return -1; } else if( i_ret == 0) { return 0; } else {#if !defined(UNDER_CE) if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else#endif 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) /* 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)" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -