📄 network.c
字号:
/* * Network layer for MPlayer * by Bertrand BAUDET <bertrand_baudet@yahoo.com> * (C) 2001, MPlayer team. *///#define DUMP2FILE#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <ctype.h>#include "config.h"#ifndef HAVE_WINSOCK2#define closesocket close#else#include <winsock2.h>#include <ws2tcpip.h>#endif#include "stream.h"#include "demuxer.h"#include "../m_config.h"#include "network.h"#include "http.h"#include "cookies.h"#include "url.h"#include "asf.h"#include "rtp.h"#include "pnm.h"#include "realrtsp/rtsp_session.h"#include "../version.h"extern int verbose;extern int stream_cache_size;extern int mp_input_check_interrupt(int time);int asf_streaming_start( stream_t *stream, int *demuxer_type );int rtsp_streaming_start( stream_t *stream );/* Variables for the command line option -user, -passwd, -bandwidth, -user-agent and -nocookies */char *network_username=NULL;char *network_password=NULL;int network_bandwidth=0;int network_cookies_enabled = 0;char *network_useragent=NULL;/* IPv6 options */int network_prefer_ipv4 = 0;int network_ipv4_only_proxy = 0;static struct { char *mime_type; int demuxer_type;} mime_type_table[] = { // MP3 streaming, some MP3 streaming server answer with audio/mpeg { "audio/mpeg", DEMUXER_TYPE_AUDIO }, // MPEG streaming { "video/mpeg", DEMUXER_TYPE_UNKNOWN }, { "video/x-mpeg", DEMUXER_TYPE_UNKNOWN }, { "video/x-mpeg2", DEMUXER_TYPE_UNKNOWN }, // AVI ??? => video/x-msvideo { "video/x-msvideo", DEMUXER_TYPE_AVI }, // MOV => video/quicktime { "video/quicktime", DEMUXER_TYPE_MOV }, // ASF { "audio/x-ms-wax", DEMUXER_TYPE_ASF }, { "audio/x-ms-wma", DEMUXER_TYPE_ASF }, { "video/x-ms-asf", DEMUXER_TYPE_ASF }, { "video/x-ms-afs", DEMUXER_TYPE_ASF }, { "video/x-ms-wvx", DEMUXER_TYPE_ASF }, { "video/x-ms-wmv", DEMUXER_TYPE_ASF }, { "video/x-ms-wma", DEMUXER_TYPE_ASF }, // Playlists { "video/x-ms-wmx", DEMUXER_TYPE_PLAYLIST }, { "audio/x-scpls", DEMUXER_TYPE_PLAYLIST }, { "audio/x-mpegurl", DEMUXER_TYPE_PLAYLIST }, { "audio/x-pls", DEMUXER_TYPE_PLAYLIST }, // Real Media { "audio/x-pn-realaudio", DEMUXER_TYPE_REAL }, // OGG Streaming { "application/x-ogg", DEMUXER_TYPE_OGG }, // NullSoft Streaming Video { "video/nsv", DEMUXER_TYPE_NSV}, { "misc/ultravox", DEMUXER_TYPE_NSV}};/* * An autodetection based on the extension is not a good idea. * static struct { char *extension; int demuxer_type;} extensions_table[] = { { "mpeg", DEMUXER_TYPE_MPEG_PS }, { "mpg", DEMUXER_TYPE_MPEG_PS }, { "mpe", DEMUXER_TYPE_MPEG_ES }, { "avi", DEMUXER_TYPE_AVI }, { "mov", DEMUXER_TYPE_MOV }, { "qt", DEMUXER_TYPE_MOV }, { "asx", DEMUXER_TYPE_ASF }, { "asf", DEMUXER_TYPE_ASF }, { "wmv", DEMUXER_TYPE_ASF }, { "wma", DEMUXER_TYPE_ASF }, { "viv", DEMUXER_TYPE_VIVO }, { "rm", DEMUXER_TYPE_REAL }, { "ra", DEMUXER_TYPE_REAL }, { "y4m", DEMUXER_TYPE_Y4M }, { "mp3", DEMUXER_TYPE_AUDIO }, { "ogg", DEMUXER_TYPE_OGG }, { "wav", DEMUXER_TYPE_AUDIO }, { "pls", DEMUXER_TYPE_PLAYLIST }, { "m3u", DEMUXER_TYPE_PLAYLIST }};*/streaming_ctrl_t *streaming_ctrl_new( ) { streaming_ctrl_t *streaming_ctrl; streaming_ctrl = (streaming_ctrl_t*)malloc(sizeof(streaming_ctrl_t)); if( streaming_ctrl==NULL ) { mp_msg(MSGT_NETWORK,MSGL_FATAL,"Failed to allocate memory\n"); return NULL; } memset( streaming_ctrl, 0, sizeof(streaming_ctrl_t) ); return streaming_ctrl;}voidstreaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) { if( streaming_ctrl==NULL ) return; if( streaming_ctrl->url ) url_free( streaming_ctrl->url ); if( streaming_ctrl->buffer ) free( streaming_ctrl->buffer ); if( streaming_ctrl->data ) free( streaming_ctrl->data ); free( streaming_ctrl );}intread_rtp_from_server(int fd, char *buffer, int length) { struct rtpheader rh; char *data; int len; static int got_first = 0; static unsigned short sequence; if( buffer==NULL || length<0 ) return -1; getrtp2(fd, &rh, &data, &len); if( got_first && rh.b.sequence != (unsigned short)(sequence+1) ) mp_msg(MSGT_NETWORK,MSGL_ERR,"RTP packet sequence error! Expected: %d, received: %d\n", sequence+1, rh.b.sequence); got_first = 1; sequence = rh.b.sequence; memcpy(buffer, data, len); return(len);}// Converts an address family constant to a stringchar *af2String(int af) { switch (af) { case AF_INET: return "AF_INET"; #ifdef HAVE_AF_INET6 case AF_INET6: return "AF_INET6";#endif default: return "Unknown address family!"; }}// Connect to a server using a TCP connection, with specified address family// return -2 for fatal error, like unable to resolve name, connection timeout...// return -1 is unable to connect to a particular portintconnect2Server_with_af(char *host, int port, int af,int verb) { int socket_server_fd; int err, err_len; int ret,count = 0; fd_set set; struct timeval tv; union { struct sockaddr_in four;#ifdef HAVE_AF_INET6 struct sockaddr_in6 six;#endif } server_address; size_t server_address_size; void *our_s_addr; // Pointer to sin_addr or sin6_addr struct hostent *hp=NULL; char buf[255]; #ifdef HAVE_WINSOCK2 u_long val;#endif socket_server_fd = socket(af, SOCK_STREAM, 0); if( socket_server_fd==-1 ) {// mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af)); return -2; } switch (af) { case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break;#ifdef HAVE_AF_INET6 case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break;#endif default: mp_msg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d:\n", af); return -2; } memset(&server_address, 0, sizeof(server_address)); #ifndef HAVE_WINSOCK2#ifdef USE_ATON if (inet_aton(host, our_s_addr)!=1)#else if (inet_pton(af, host, our_s_addr)!=1)#endif#else if ( inet_addr(host)==INADDR_NONE )#endif { if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,"Resolving %s for %s...\n", host, af2String(af)); #ifdef HAVE_GETHOSTBYNAME2 hp=(struct hostent*)gethostbyname2( host, af );#else hp=(struct hostent*)gethostbyname( host );#endif if( hp==NULL ) { if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't resolve name for %s: %s\n", af2String(af), host); return -2; } memcpy( our_s_addr, (void*)hp->h_addr, hp->h_length ); }#ifdef HAVE_WINSOCK2 else { unsigned long addr = inet_addr(host); memcpy( our_s_addr, (void*)&addr, sizeof(addr) ); }#endif switch (af) { case AF_INET: server_address.four.sin_family=af; server_address.four.sin_port=htons(port); server_address_size = sizeof(server_address.four); break;#ifdef HAVE_AF_INET6 case AF_INET6: server_address.six.sin6_family=af; server_address.six.sin6_port=htons(port); server_address_size = sizeof(server_address.six); break;#endif default: mp_msg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d:\n", af); return -2; }#if defined(USE_ATON) || defined(HAVE_WINSOCK2) strncpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);#else inet_ntop(af, our_s_addr, buf, 255);#endif if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,"Connecting to server %s[%s]:%d ...\n", host, buf , port ); // Turn the socket as non blocking so we can timeout on the connection#ifndef HAVE_WINSOCK2 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );#else val = 1; ioctlsocket( socket_server_fd, FIONBIO, &val );#endif if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) {#ifndef HAVE_WINSOCK2 if( errno!=EINPROGRESS ) {#else if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {#endif if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server with %s\n", af2String(af)); closesocket(socket_server_fd); return -1; } } tv.tv_sec = 0; tv.tv_usec = 500000; FD_ZERO( &set ); FD_SET( socket_server_fd, &set ); // When the connection will be made, we will have a writable fd while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) { if( ret<0 ) mp_msg(MSGT_NETWORK,MSGL_ERR,"select failed\n"); else if(ret > 0) break; else if(count > 30 || mp_input_check_interrupt(500)) { if(count > 30) mp_msg(MSGT_NETWORK,MSGL_ERR,"Connection timeout\n"); else mp_msg(MSGT_NETWORK,MSGL_V,"Connection interuppted by user\n"); return -3; } count++; FD_ZERO( &set ); FD_SET( socket_server_fd, &set ); tv.tv_sec = 0; tv.tv_usec = 500000; } // Turn back the socket as blocking#ifndef HAVE_WINSOCK2 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );#else val = 0; ioctlsocket( socket_server_fd, FIONBIO, &val );#endif // Check if there were any error err_len = sizeof(int); ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len); if(ret < 0) { mp_msg(MSGT_NETWORK,MSGL_ERR,"getsockopt failed : %s\n",strerror(errno)); return -2; } if(err > 0) { mp_msg(MSGT_NETWORK,MSGL_ERR,"Connect error : %s\n",strerror(err)); return -1; } return socket_server_fd;}// Connect to a server using a TCP connection// return -2 for fatal error, like unable to resolve name, connection timeout...// return -1 is unable to connect to a particular portintconnect2Server(char *host, int port, int verb) {#ifdef HAVE_AF_INET6 int r; int s = -2; r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb); if (r > -1) return r; s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb); if (s == -2) return r; return s;#else return connect2Server_with_af(host, port, AF_INET,verb);#endif }URL_t*check4proxies( URL_t *url ) { URL_t *url_out = NULL; if( url==NULL ) return NULL; url_out = url_new( url->url ); if( !strcasecmp(url->protocol, "http_proxy") ) { mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: http://%s:%d\n", url->hostname, url->port ); return url_out; } // Check if the http_proxy environment variable is set. if( !strcasecmp(url->protocol, "http") ) { char *proxy; proxy = getenv("http_proxy"); if( proxy!=NULL ) { // We got a proxy, build the URL to use it int len; char *new_url; URL_t *tmp_url; URL_t *proxy_url = url_new( proxy ); if( proxy_url==NULL ) { mp_msg(MSGT_NETWORK,MSGL_WARN,"Invalid proxy setting...Trying without proxy.\n"); return url_out; } #ifdef HAVE_AF_INET6 if (network_ipv4_only_proxy && (gethostbyname(url->hostname)==NULL)) { mp_msg(MSGT_NETWORK,MSGL_WARN, "Could not find resolve remote hostname for AF_INET. Trying without proxy.\n"); return url_out; }#endif mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: %s\n", proxy_url->url ); len = strlen( proxy_url->hostname ) + strlen( url->url ) + 20; // 20 = http_proxy:// + port new_url = malloc( len+1 ); if( new_url==NULL ) { mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); return url_out; } sprintf(new_url, "http_proxy://%s:%d/%s", proxy_url->hostname, proxy_url->port, url->url ); tmp_url = url_new( new_url ); if( tmp_url==NULL ) { return url_out; } url_free( url_out ); url_out = tmp_url; free( new_url ); url_free( proxy_url ); } } return url_out;}inthttp_send_request( URL_t *url, off_t pos ) { HTTP_header_t *http_hdr; URL_t *server_url; char str[256]; int fd; int ret; int proxy = 0; // Boolean http_hdr = http_new_header(); if( !strcasecmp(url->protocol, "http_proxy") ) { proxy = 1; server_url = url_new( (url->file)+1 ); http_set_uri( http_hdr, server_url->url ); } else { server_url = url; http_set_uri( http_hdr, server_url->file ); } if (server_url->port && server_url->port != 80) snprintf(str, 256, "Host: %s:%d", server_url->hostname, server_url->port ); else snprintf(str, 256, "Host: %s", server_url->hostname ); http_set_field( http_hdr, str); if (network_useragent) { snprintf(str, 256, "User-Agent: %s", network_useragent); http_set_field(http_hdr, str); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -