1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-25 04:38:01 +00:00

Remove internal network support

This commit removes the "old" networking code in favor of libavformat's
code.

The code was still used for mp_http, udp, ftp, cddb. http has been
mapped to libavformat's http support since approximately 6 months ago.
udp and ftp have support in ffmpeg (though ftp was added only last
month). cddb support is removed with this commit - it's probably not
important and rarely used if at all, so we don't care about it.
This commit is contained in:
wm4 2013-07-07 19:40:14 +02:00
parent feaa721916
commit 854303ad49
28 changed files with 43 additions and 6240 deletions

View File

@ -1051,12 +1051,6 @@
work (key bindings that normally quit will be shown on OSD only, just
like any other binding).
--ipv4-only-proxy
Skip any HTTP proxy for IPv6 addresses. It will still be used for IPv4
connections.
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--joystick, --no-joystick
Enable/disable joystick support. Enabled by default.
@ -1416,12 +1410,6 @@
allows a zoom factor of up to 4. This feature is experimental. Do not
report bugs unless you are using ``--vo=opengl``.
--passwd=<password>
Used with some network protocols. Specify password for HTTP authentication.
See also ``--user``.
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--playing-msg=<string>
Print out a string after starting playback. The string is expanded for
properties, e.g. ``--playing-msg=file: ${filename}`` will print the string
@ -1466,16 +1454,6 @@
--pphelp
See also ``--vf=pp``.
--prefer-ipv4
Use IPv4 on network connections. Falls back on IPv6 automatically.
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--prefer-ipv6
Use IPv6 on network connections. Falls back on IPv4 automatically.
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--priority=<prio>
(Windows only.)
Set process priority for mpv according to the predefined priorities
@ -2284,12 +2262,6 @@
*WARNING*: May be dangerous if playing from untrusted media.
--user=<username>
Used with some network protocols.
Specify username for HTTP authentication. See also ``--passwd``.
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--user-agent=<string>
Use <string> as user agent for HTTP streaming.

View File

@ -28,13 +28,11 @@ SOURCES_AUDIO_INPUT-$(OSS) += stream/ai_oss.c
SOURCES-$(AUDIO_INPUT) += $(SOURCES_AUDIO_INPUT-yes)
SOURCES-$(CDDA) += stream/stream_cdda.c \
stream/cdinfo.c
SOURCES-$(CDDB) += stream/stream_cddb.c
SOURCES-$(DVBIN) += stream/dvb_tune.c \
stream/stream_dvb.c
SOURCES-$(DVDREAD) += stream/stream_dvd.c \
stream/stream_dvd_common.c
SOURCES-$(FTP) += stream/stream_ftp.c
SOURCES-$(HAVE_SYS_MMAN_H) += audio/filter/af_export.c osdep/mmap_anon.c
SOURCES-$(LADSPA) += audio/filter/af_ladspa.c
SOURCES-$(LIBASS) += sub/ass_mp.c sub/sd_ass.c \
@ -56,14 +54,6 @@ SOURCES-$(MPG123) += audio/decode/ad_mpg123.c
SOURCES-$(NEED_GETTIMEOFDAY) += osdep/gettimeofday.c
SOURCES-$(NEED_GLOB) += osdep/glob-win.c
SOURCES-$(NETWORKING) += stream/asf_mmst_streaming.c \
stream/asf_streaming.c \
stream/cookies.c \
stream/http.c \
stream/network.c \
stream/udp.c \
stream/tcp.c \
stream/stream_udp.c \
SOURCES-$(PRIORITY) += osdep/priority.c
SOURCES-$(PVR) += stream/stream_pvr.c
@ -223,6 +213,7 @@ SOURCES = talloc.c \
osdep/io.c \
osdep/numcores.c \
osdep/timer.c \
stream/cookies.c \
stream/stream.c \
stream/stream_avdevice.c \
stream/stream_file.c \
@ -230,7 +221,6 @@ SOURCES = talloc.c \
stream/stream_memory.c \
stream/stream_mf.c \
stream/stream_null.c \
stream/url.c \
sub/dec_sub.c \
sub/draw_bmp.c \
sub/find_subfiles.c \

190
configure vendored
View File

@ -307,8 +307,6 @@ Optional features:
--disable-tv disable TV interface (TV/DVB grabbers) [enable]
--disable-tv-v4l2 disable Video4Linux2 TV interface [autodetect]
--disable-pvr disable Video4Linux2 MPEG PVR [autodetect]
--disable-networking disable networking [enable]
--enable-winsock2_h enable winsock2_h [autodetect]
--enable-smb enable Samba (SMB) input [autodetect]
--disable-libquvi4 disable libquvi 0.4.x [autodetect]
--disable-libquvi9 disable libquvi 0.9.x [autodetect]
@ -316,12 +314,10 @@ Optional features:
--disable-vcd disable VCD support [autodetect]
--disable-bluray disable Blu-ray support [autodetect]
--disable-dvdread disable libdvdread [autodetect]
--disable-cddb disable cddb [autodetect]
--disable-enca disable ENCA charset oracle library [autodetect]
--enable-macosx-bundle enable Mac OS X bundle file locations [autodetect]
--disable-inet6 disable IPv6 support [autodetect]
--disable-gethostbyname2 gethostbyname2 part of the C library [autodetect]
--disable-ftp disable FTP support [enabled]
--disable-vstream disable TiVo vstream client support [autodetect]
--disable-pthreads disable Posix threads support [autodetect]
--disable-libass disable subtitle rendering with libass [autodetect]
@ -463,8 +459,6 @@ _radio_v4l2=auto
_tv=yes
_tv_v4l2=auto
_pvr=auto
networking=yes
_winsock2_h=auto
_smb=auto
_libquvi4=auto
_libquvi9=auto
@ -477,7 +471,6 @@ _termios=auto
_shm=auto
_gettext=no
_cdda=auto
_cddb=auto
_coreaudio=auto
_corevideo=auto
_cocoa=auto
@ -485,7 +478,6 @@ _macosx_bundle=auto
_enca=auto
_inet6=auto
_gethostbyname2=auto
_ftp=auto
_vstream=auto
_pthreads=auto
_ass=auto
@ -662,10 +654,6 @@ for ac_option do
--disable-radio-v4l2) _radio_v4l2=no ;;
--enable-pvr) _pvr=yes ;;
--disable-pvr) _pvr=no ;;
--enable-networking) networking=yes ;;
--disable-networking) networking=no ;;
--enable-winsock2_h) _winsock2_h=yes ;;
--disable-winsock2_h) _winsock2_h=no ;;
--enable-smb) _smb=yes ;;
--disable-smb) _smb=no ;;
--enable-libquvi4) _libquvi4=yes ;;
@ -692,10 +680,6 @@ for ac_option do
--disable-shm) _shm=no ;;
--enable-select) _select=yes ;;
--disable-select) _select=no ;;
--enable-cddb) _cddb=yes ;;
--disable-cddb) _cddb=no ;;
--enable-ftp) _ftp=yes ;;
--disable-ftp) _ftp=no ;;
--enable-vstream) _vstream=yes ;;
--disable-vstream) _vstream=no ;;
--enable-pthreads) _pthreads=yes ;;
@ -1247,146 +1231,6 @@ fi
echores "$_nanosleep"
echocheck "socklib"
# for Solaris (socket stuff is in -lsocket, gethostbyname and friends in -lnsl):
cat > $TMPC << EOF
#include <netdb.h>
#include <sys/socket.h>
int main(void) { gethostbyname(0); socket(AF_INET, SOCK_STREAM, 0); return 0; }
EOF
_socklib=no
for _ld_tmp in "" "-lsocket -lbind" "-lsocket -ldnet" "-lsocket -lnsl" "-lnsl" "-lsocket" ; do
cc_check $_ld_tmp && _ld_sock="$_ld_tmp" && _socklib=yes && break
done
test $_socklib = yes && test $_winsock2_h = auto && _winsock2_h=no
if test $_winsock2_h = auto ; then
_winsock2_h=no
statement_check winsock2.h 'gethostbyname(0)' -lws2_32 && _ld_sock="-lws2_32" && _winsock2_h=yes
fi
test "$_ld_sock" && res_comment="using $_ld_sock"
echores "$_socklib"
if test $_winsock2_h = yes ; then
_ld_sock="-lws2_32"
def_winsock2_h='#define HAVE_WINSOCK2_H 1'
else
def_winsock2_h='#define HAVE_WINSOCK2_H 0'
fi
echocheck "inet_pton()"
def_inet_pton='#define HAVE_INET_PTON 0'
inet_pton=no
for _ld_tmp in "$_ld_sock" "$_ld_sock -lresolv" ; do
statement_check arpa/inet.h 'inet_pton(0, 0, 0)' $_ld_tmp && inet_pton=yes && break
done
if test $inet_pton = yes ; then
test "$_ld_tmp" && res_comment="using $_ld_tmp"
def_inet_pton='#define HAVE_INET_PTON 1'
fi
echores "$inet_pton"
echocheck "inet_aton()"
def_inet_aton='#define HAVE_INET_ATON 0'
inet_aton=no
for _ld_tmp in "$_ld_sock" "$_ld_sock -lresolv" ; do
statement_check arpa/inet.h 'inet_aton(0, 0)' $_ld_tmp && inet_aton=yes && break
done
if test $inet_aton = yes ; then
test "$_ld_tmp" && res_comment="using $_ld_tmp"
def_inet_aton='#define HAVE_INET_ATON 1'
fi
echores "$inet_aton"
echocheck "socklen_t"
_socklen_t=no
for header in "sys/socket.h" "ws2tcpip.h" "sys/types.h" ; do
statement_check $header 'socklen_t v = 0' && _socklen_t=yes && break
done
if test "$_socklen_t" = yes ; then
def_socklen_t='#define HAVE_SOCKLEN_T 1'
else
def_socklen_t='#define HAVE_SOCKLEN_T 0'
fi
echores "$_socklen_t"
echocheck "closesocket()"
_closesocket=no
statement_check winsock2.h 'closesocket(~0)' $_ld_sock && _closesocket=yes
if test "$_closesocket" = yes ; then
def_closesocket='#define HAVE_CLOSESOCKET 1'
else
def_closesocket='#define HAVE_CLOSESOCKET 0'
fi
echores "$_closesocket"
echocheck "networking"
test $_winsock2_h = no && test $inet_pton = no &&
test $inet_aton = no && networking=no
if test "$networking" = yes ; then
def_network='#define CONFIG_NETWORK 1'
def_networking='#define CONFIG_NETWORKING 1'
libs_mplayer="$libs_mplayer $_ld_sock"
inputmodules="networking $inputmodules"
else
noinputmodules="networking $noinputmodules"
def_network='#define CONFIG_NETWORK 0'
def_networking='#undef CONFIG_NETWORKING'
fi
echores "$networking"
echocheck "inet6"
if test "$_inet6" = auto ; then
cat > $TMPC << EOF
#include <sys/types.h>
#if !defined(_WIN32)
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <ws2tcpip.h>
#endif
int main(void) { struct sockaddr_in6 six; socket(AF_INET6, SOCK_STREAM, AF_INET6); return 0; }
EOF
_inet6=no
if cc_check $_ld_sock ; then
_inet6=yes
fi
fi
if test "$_inet6" = yes ; then
def_inet6='#define HAVE_AF_INET6 1'
else
def_inet6='#undef HAVE_AF_INET6'
fi
echores "$_inet6"
echocheck "gethostbyname2"
if test "$_gethostbyname2" = auto ; then
cat > $TMPC << EOF
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main(void) { gethostbyname2("", AF_INET); return 0; }
EOF
_gethostbyname2=no
if cc_check ; then
_gethostbyname2=yes
fi
fi
if test "$_gethostbyname2" = yes ; then
def_gethostbyname2='#define HAVE_GETHOSTBYNAME2 1'
else
def_gethostbyname2='#undef HAVE_GETHOSTBYNAME2'
fi
echores "$_gethostbyname2"
echocheck "mman.h"
_mman=no
statement_check sys/mman.h 'mmap(0, 0, 0, 0, 0, 0)' && _mman=yes
@ -2585,7 +2429,6 @@ fi
if test "$_libcdio" = yes ; then
_cdda='yes'
def_cdda='#define CONFIG_CDDA 1'
test $_cddb = auto && test $networking = yes && _cddb=yes
inputmodules="cdda $inputmodules"
else
_libcdio=no
@ -2595,15 +2438,6 @@ else
fi
echores "$_libcdio"
if test "$_cddb" = yes ; then
def_cddb='#define CONFIG_CDDB 1'
inputmodules="cddb $inputmodules"
else
_cddb=no
def_cddb='#undef CONFIG_CDDB'
noinputmodules="cddb $noinputmodules"
fi
echocheck "SSA/ASS support"
if test "$_ass" = auto ; then
@ -2999,19 +2833,6 @@ fi
echores "$_pvr"
echocheck "ftp"
if test "$_ftp" = "auto" ; then
test "$networking" = "yes" && _ftp=yes
fi
if test "$_ftp" = yes ; then
def_ftp='#define CONFIG_FTP 1'
inputmodules="ftp $inputmodules"
else
noinputmodules="ftp $noinputmodules"
def_ftp='#undef CONFIG_FTP'
fi
echores "$_ftp"
echocheck "vstream client"
if test "$_vstream" = auto ; then
_vstream=no
@ -3175,7 +2996,6 @@ ALSA = $_alsa
AUDIO_INPUT = $_audio_input
CACA = $_caca
CDDA = $_cdda
CDDB = $_cddb
COCOA = $_cocoa
COREAUDIO = $_coreaudio
COREVIDEO = $_corevideo
@ -3187,7 +3007,6 @@ WASAPI0 = $_wasapi0
DVBIN = $_dvbin
DVDREAD = $_dvdread
DXR3 = $_dxr3
FTP = $_ftp
GL = $_gl
GL_COCOA = $_gl_cocoa
GL_WIN32 = $_gl_win32
@ -3220,7 +3039,6 @@ LIRC = $_lirc
MACOSX_BUNDLE = $_macosx_bundle
MNG = $_mng
MPG123 = $_mpg123
NETWORKING = $networking
OPENAL = $_openal
OSS = $_ossaudio
PE_EXECUTABLE = $_pe_executable
@ -3344,7 +3162,6 @@ $(ff_config_enable "$subarch_all" "$subarch" "ARCH")
$def_bluray
$def_bsdi_dvd
$def_cdda
$def_cddb
$def_cdio
$def_cdrom
$def_dvd
@ -3405,17 +3222,10 @@ $def_ass
$def_enca
/* networking */
$def_closesocket
$def_ftp
$def_inet6
$def_inet_aton
$def_inet_pton
$def_networking
$def_smb
$def_libquvi4
$def_libquvi9
$def_libguess
$def_socklen_t
$def_vstream
$def_lcms2

View File

@ -29,6 +29,7 @@
#include <limits.h>
#include <inttypes.h>
#include <unistd.h>
#include <ctype.h>
#include <assert.h>
#include <libavutil/common.h>
@ -38,7 +39,6 @@
#include "core/mp_common.h"
#include "core/m_option.h"
#include "core/mp_msg.h"
#include "stream/url.h"
char *m_option_strerror(int code)
{
@ -2367,6 +2367,38 @@ const m_option_type_t m_option_type_obj_settings_list = {
};
/* Replace escape sequences in an URL (or a part of an URL) */
/* works like strcpy(), but without return argument,
except that outbuf == inbuf is allowed */
static void url_unescape_string(char *outbuf, const char *inbuf)
{
unsigned char c,c1,c2;
int i,len=strlen(inbuf);
for (i=0;i<len;i++) {
c = inbuf[i];
if (c == '%' && i<len-2) { //must have 2 more chars
c1 = toupper(inbuf[i+1]); // we need uppercase characters
c2 = toupper(inbuf[i+2]);
if (((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) &&
((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) )
{
if (c1>='0' && c1<='9')
c1-='0';
else
c1-='A'-10;
if (c2>='0' && c2<='9')
c2-='0';
else
c2-='A'-10;
c = (c1<<4) + c2;
i=i+2; //only skip next 2 chars if valid esc
}
}
*outbuf++ = c;
}
*outbuf++='\0'; //add nullterm to string
}
static int parse_custom_url(const m_option_t *opt, struct bstr name,
struct bstr url, void *dst)
{

View File

@ -40,8 +40,6 @@
#include "mp_core.h"
#include "osdep/priority.h"
char *network_username=NULL;
char *network_password=NULL;
int network_bandwidth=0;
int network_cookies_enabled = 0;
char *network_useragent="MPlayer 1.1-4.7";
@ -351,20 +349,11 @@ const m_option_t mp_opts[] = {
{"bluray-angle", &bluray_angle, CONF_TYPE_INT, CONF_RANGE, 0, 999, NULL},
#endif /* CONFIG_LIBBLURAY */
{"user", &network_username, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"passwd", &network_password, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"bandwidth", &network_bandwidth, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL},
{"http-header-fields", &network_http_header_fields, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
{"user-agent", &network_useragent, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"referrer", &network_referrer, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"cookies", &network_cookies_enabled, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"cookies-file", &cookies_file, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"prefer-ipv4", &network_prefer_ipv4, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"ipv4-only-proxy", &network_ipv4_only_proxy, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"reuse-socket", &reuse_socket, CONF_TYPE_FLAG, 0, 0, 1, NULL},
#ifdef HAVE_AF_INET6
{"prefer-ipv6", &network_prefer_ipv4, CONF_TYPE_FLAG, 0, 1, 0, NULL},
#endif /* HAVE_AF_INET6 */
// ------------------------- demuxer options --------------------

View File

@ -268,9 +268,6 @@ typedef struct MPOpts {
// Should be moved into MPOpts
extern char **network_http_header_fields;
extern char *network_username;
extern char *network_password;
extern int network_bandwidth;
extern char *network_useragent;
extern char *network_referrer;
extern int network_cookies_enabled;

View File

@ -1,686 +0,0 @@
/*
* MMST implementation taken from the xine-mms plugin made by
* Major MMS (http://geocities.com/majormms/).
* Ported to MPlayer by Abhijeet Phatak <abhijeetphatak@yahoo.com>.
*
* Information about the MMS protocol can be found at http://get.to/sdp
*
* copyright (C) 2002 Abhijeet Phatak <abhijeetphatak@yahoo.com>
* copyright (C) 2002 the xine project
* copyright (C) 2000-2001 major mms
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include "config.h"
#include "core/options.h"
#include "core/mp_msg.h"
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef CONFIG_ICONV
#include <iconv.h>
#endif
#include "url.h"
#include "demux/asf.h"
#include "stream.h"
#include "asf_mmst_streaming.h"
#include "network.h"
#include "tcp.h"
extern int audio_id;
extern int video_id;
#define BUF_SIZE 102400
#define HDR_BUF_SIZE 8192
#define MAX_STREAMS 20
typedef struct
{
uint8_t buf[BUF_SIZE];
int num_bytes;
} command_t;
static int seq_num;
static int num_stream_ids;
static int stream_ids[MAX_STREAMS];
static int get_data (int s, char *buf, size_t count);
static void put_32 (command_t *cmd, uint32_t value)
{
cmd->buf[cmd->num_bytes ] = value % 256;
value = value >> 8;
cmd->buf[cmd->num_bytes+1] = value % 256 ;
value = value >> 8;
cmd->buf[cmd->num_bytes+2] = value % 256 ;
value = value >> 8;
cmd->buf[cmd->num_bytes+3] = value % 256 ;
cmd->num_bytes += 4;
}
static uint32_t get_32 (unsigned char *cmd, int offset)
{
uint32_t ret;
ret = cmd[offset] ;
ret |= cmd[offset+1]<<8 ;
ret |= cmd[offset+2]<<16 ;
ret |= cmd[offset+3]<<24 ;
return ret;
}
static void send_command (int s, int command, uint32_t switches,
uint32_t extra, int length,
char *data)
{
command_t cmd;
int len8;
len8 = (length + 7) / 8;
cmd.num_bytes = 0;
put_32 (&cmd, 0x00000001); /* start sequence */
put_32 (&cmd, 0xB00BFACE); /* #-)) */
put_32 (&cmd, len8*8 + 32);
put_32 (&cmd, 0x20534d4d); /* protocol type "MMS " */
put_32 (&cmd, len8 + 4);
put_32 (&cmd, seq_num);
seq_num++;
put_32 (&cmd, 0x0); /* unknown */
put_32 (&cmd, 0x0);
put_32 (&cmd, len8+2);
put_32 (&cmd, 0x00030000 | command); /* dir | command */
put_32 (&cmd, switches);
put_32 (&cmd, extra);
memcpy (&cmd.buf[48], data, length);
if (length & 7)
memset(&cmd.buf[48 + length], 0, 8 - (length & 7));
if (send (s, cmd.buf, len8*8+48, 0) != (len8*8+48)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"write error\n");
}
}
#ifdef CONFIG_ICONV
static iconv_t url_conv;
#endif
static void string_utf16(char *dest, char *src, int len) {
int i;
#ifdef CONFIG_ICONV
size_t len1, len2;
char *ip, *op;
if (url_conv != (iconv_t)(-1))
{
memset(dest, 0, 1000);
len1 = len; len2 = 1000;
ip = src; op = dest;
iconv(url_conv, &ip, &len1, &op, &len2);
}
else
{
#endif
if (len > 499) len = 499;
for (i=0; i<len; i++) {
dest[i*2] = src[i];
dest[i*2+1] = 0;
}
/* trailing zeroes */
dest[i*2] = 0;
dest[i*2+1] = 0;
#ifdef CONFIG_ICONV
}
#endif
}
static void get_answer (int s)
{
char data[BUF_SIZE];
int command = 0x1b;
while (command == 0x1b) {
int len;
len = recv (s, data, BUF_SIZE, 0) ;
if (!len) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"\nAlert! EOF\n");
return;
}
command = get_32 (data, 36) & 0xFFFF;
if (command == 0x1b)
send_command (s, 0x1b, 0, 0, 0, data);
}
}
static int get_data (int s, char *buf, size_t count)
{
ssize_t len;
size_t total = 0;
while (total < count) {
len = recv (s, &buf[total], count-total, 0);
if (len<=0) {
perror ("read error:");
return 0;
}
total += len;
if (len != 0) {
// mp_msg(MSGT_NETWORK,MSGL_INFO,"[%d/%d]", total, count);
fflush (stdout);
}
}
return 1;
}
static int get_header (int s, uint8_t *header, streaming_ctrl_t *streaming_ctrl)
{
unsigned char pre_header[8];
int header_len;
header_len = 0;
while (1) {
if (!get_data (s, pre_header, 8)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"pre-header read failed\n");
return 0;
}
if (pre_header[4] == 0x02) {
int packet_len;
packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf header packet detected, len=%d\n", packet_len);
if (packet_len < 0 || packet_len > HDR_BUF_SIZE - header_len) {
mp_tmsg(MSGT_NETWORK, MSGL_FATAL, "Invalid header size, giving up.\n");
return 0;
}
if (!get_data (s, &header[header_len], packet_len)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Header data read failed.\n");
return 0;
}
header_len += packet_len;
if ( (header[header_len-1] == 1) && (header[header_len-2]==1)) {
if( streaming_bufferize( streaming_ctrl, header, header_len )<0 ) {
return -1;
}
// mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet finished\n");
return header_len;
}
} else {
int32_t packet_len;
int command;
char data[BUF_SIZE];
if (!get_data (s, (char*)&packet_len, 4)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"packet_len read failed.\n");
return 0;
}
packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"command packet detected, len=%d\n", packet_len);
if (packet_len < 0 || packet_len > BUF_SIZE) {
mp_tmsg(MSGT_NETWORK, MSGL_FATAL,
"Invalid RTSP packet size, giving up.\n");
return 0;
}
if (!get_data (s, data, packet_len)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Command data read failed.\n");
return 0;
}
command = get_32 (data, 24) & 0xFFFF;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"command: %02x\n", command);
if (command == 0x1b)
send_command (s, 0x1b, 0, 0, 0, data);
}
// mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet succ\n");
}
}
static int interp_header (uint8_t *header, int header_len)
{
int i;
int packet_length=-1;
/*
* parse header
*/
i = 30;
while (i<header_len) {
uint64_t guid_1, guid_2, length;
guid_2 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
| ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
| ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
| ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
i += 8;
guid_1 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
| ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
| ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
| ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
i += 8;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"guid found: %016llx%016llx\n", guid_1, guid_2);
length = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8)
| ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24)
| ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40)
| ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56);
i += 8;
if ( (guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22630ULL) ) {
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"header object\n");
} else if ((guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22636ULL)) {
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"data object\n");
} else if ((guid_1 == 0x6553200cc000e48eULL) && (guid_2 == 0x11cfa9478cabdca1ULL)) {
packet_length = get_32(header, i+92-24);
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"file object, packet length = %d (%d)\n",
packet_length, get_32(header, i+96-24));
} else if ((guid_1 == 0x6553200cc000e68eULL) && (guid_2 == 0x11cfa9b7b7dc0791ULL)) {
int stream_id = header[i+48] | header[i+49] << 8;
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"stream object, stream ID: %d\n", stream_id);
if (num_stream_ids < MAX_STREAMS) {
stream_ids[num_stream_ids] = stream_id;
num_stream_ids++;
} else {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Too many IDs, stream skipped.");
}
} else {
#if 0
int b = i;
printf ("unknown object (guid: %016llx, %016llx, len: %lld)\n", guid_1, guid_2, length);
for (; b < length; b++)
{
if (isascii(header[b]) || isalpha(header[b]))
printf("%c ", header[b]);
else
printf("%x ", header[b]);
}
printf("\n");
#else
mp_tmsg(MSGT_NETWORK,MSGL_WARN,"unknown object\n");
#endif
}
// mp_msg(MSGT_NETWORK,MSGL_INFO,"length : %lld\n", length);
i += length-24;
}
return packet_length;
}
static int get_media_packet (int s, int padding, streaming_ctrl_t *stream_ctrl) {
unsigned char pre_header[8];
char data[BUF_SIZE];
if (!get_data (s, pre_header, 8)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"pre-header read failed\n");
return 0;
}
// for (i=0; i<8; i++)
// mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n",
// i, pre_header[i], pre_header[i]);
if (pre_header[4] == 0x04) {
int packet_len;
packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len);
if (packet_len < 0 || packet_len > BUF_SIZE) {
mp_tmsg(MSGT_NETWORK, MSGL_FATAL, "Invalid RTSP packet size, giving up.\n");
return 0;
}
if (!get_data (s, data, packet_len)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Media data read failed.\n");
return 0;
}
streaming_bufferize(stream_ctrl, data, padding);
} else {
int32_t packet_len;
int command;
if (!get_data (s, (char*)&packet_len, 4)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"packet_len read failed.\n");
return 0;
}
packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4;
if (packet_len < 0 || packet_len > BUF_SIZE) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Invalid RTSP packet size, giving up.\n");
return 0;
}
if (!get_data (s, data, packet_len)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Command data read failed.\n");
return 0;
}
if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b)
|| (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"missing signature\n");
return -1;
}
command = get_32 (data, 24) & 0xFFFF;
// mp_msg(MSGT_NETWORK,MSGL_INFO,"\ncommand packet detected, len=%d cmd=0x%X\n", packet_len, command);
if (command == 0x1b)
send_command (s, 0x1b, 0, 0, 0, data);
else if (command == 0x1e) {
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"Everything done. Thank you for downloading a media file containing proprietary and patented technology.\n");
return 0;
}
else if (command == 0x21 ) {
// Looks like it's new in WMS9
// Unknown command, but ignoring it seems to work.
return 0;
}
else if (command != 0x05) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"unknown command %02x\n",command);
return -1;
}
}
// mp_msg(MSGT_NETWORK,MSGL_INFO,"get media packet succ\n");
return 1;
}
static int packet_length1;
static int asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl )
{
int len;
while( stream_ctrl->buffer_size==0 ) {
// buffer is empty - fill it!
int ret = get_media_packet( fd, packet_length1, stream_ctrl);
if( ret<0 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"get_media_packet error : %s\n",strerror(errno));
return -1;
} else if (ret==0) //EOF?
return ret;
}
len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos;
if(len>size) len=size;
memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len );
stream_ctrl->buffer_pos += len;
if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) {
free( stream_ctrl->buffer );
stream_ctrl->buffer = NULL;
stream_ctrl->buffer_size = 0;
stream_ctrl->buffer_pos = 0;
}
return len;
}
static int asf_mmst_streaming_seek( int fd, int64_t pos, streaming_ctrl_t *streaming_ctrl )
{
return -1;
// Shut up gcc warning
fd++;
pos++;
streaming_ctrl=NULL;
}
int asf_mmst_streaming_start(stream_t *stream)
{
char str[1024];
char data[BUF_SIZE];
uint8_t asf_header[HDR_BUF_SIZE];
int asf_header_len;
int i, packet_length;
char *path, *unescpath;
URL_t *url1 = stream->streaming_ctrl->url;
int s = stream->fd;
if( s>0 ) {
closesocket( stream->fd );
stream->fd = -1;
}
/* parse url */
path = strchr(url1->file,'/') + 1;
/* mmst filename are not url_escaped by MS MediaPlayer and are expected as
* "plain text" by the server, so need to decode it here
*/
unescpath=malloc(strlen(path)+1);
if (!unescpath) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return -1;
}
url_unescape_string(unescpath,path);
path=unescpath;
if( url1->port==0 ) {
url1->port=1755;
}
s = connect2Server( url1->hostname, url1->port, 1);
if( s<0 ) {
free(path);
return s;
}
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"Connected\n");
seq_num=0;
/*
* Send the initial connect info including player version no. Client GUID (random) and the host address being connected to.
* This command is sent at the very start of protocol initiation. It sends local information to the serve
* cmd 1 0x01
* */
/* prepare for the url encoding conversion */
#ifdef CONFIG_ICONV
url_conv = iconv_open("UTF-16LE", "UTF-8");
#endif
snprintf (str, 1023, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", url1->hostname);
string_utf16 (data, str, strlen(str));
// send_command(s, commandno ....)
send_command (s, 1, 0, 0x0004000b, strlen(str)*2+2, data);
recv (s, data, BUF_SIZE, 0) ;
/*This sends details of the local machine IP address to a Funnel system at the server.
* Also, the TCP or UDP transport selection is sent.
*
* here 192.168.0.1 is local ip address TCP/UDP states the tronsport we r using
* and 1037 is the local TCP or UDP socket number
* cmd 2 0x02
* */
string_utf16 (&data[8], "\002\000\\\\192.168.0.1\\TCP\\1037", 24);
memset (data, 0, 8);
send_command (s, 2, 0, 0, 24*2+10, data);
recv (s, data, BUF_SIZE, 0) ;
/* This command sends file path (at server) and file name request to the server.
* 0x5 */
string_utf16 (&data[8], path, strlen(path));
memset (data, 0, 8);
send_command (s, 5, 0, 0, strlen(path)*2+10, data);
free(path);
get_answer (s);
/* The ASF header chunk request. Includes ?session' variable for pre header value.
* After this command is sent,
* the server replies with 0x11 command and then the header chunk with header data follows.
* 0x15 */
memset (data, 0, 40);
data[32] = 2;
send_command (s, 0x15, 1, 0, 40, data);
num_stream_ids = 0;
/* get_headers(s, asf_header); */
asf_header_len = get_header (s, asf_header, stream->streaming_ctrl);
// mp_msg(MSGT_NETWORK,MSGL_INFO,"---------------------------------- asf_header %d\n",asf_header);
if (asf_header_len==0) { //error reading header
closesocket(s);
return -1;
}
packet_length = interp_header (asf_header, asf_header_len);
/*
* This command is the media stream MBR selector. Switches are always 6 bytes in length.
* After all switch elements, data ends with bytes [00 00] 00 20 ac 40 [02].
* Where:
* [00 00] shows 0x61 0x00 (on the first 33 sent) or 0xff 0xff for ASF files, and with no ending data for WMV files.
* It is not yet understood what all this means.
* And the last [02] byte is probably the header ?session' value.
*
* 0x33 */
memset (data, 0, 40);
int audio_id = stream->opts->audio_id;
if (audio_id > 0) {
data[2] = 0xFF;
data[3] = 0xFF;
data[4] = audio_id;
send_command(s, 0x33, num_stream_ids, 0xFFFF | audio_id << 16, 8, data);
} else {
for (i=1; i<num_stream_ids; i++) {
data [ (i-1) * 6 + 2 ] = 0xFF;
data [ (i-1) * 6 + 3 ] = 0xFF;
data [ (i-1) * 6 + 4 ] = stream_ids[i];
data [ (i-1) * 6 + 5 ] = 0x00;
}
send_command (s, 0x33, num_stream_ids, 0xFFFF | stream_ids[0] << 16, (num_stream_ids-1)*6+2 , data);
}
get_answer (s);
/* Start sending file from packet xx.
* This command is also used for resume downloads or requesting a lost packet.
* Also used for seeking by sending a play point value which seeks to the media time point.
* Includes ?session' value in pre header and the maximum media stream time.
* 0x07 */
memset (data, 0, 40);
for (i=8; i<16; i++)
data[i] = 0xFF;
data[20] = 0x04;
send_command (s, 0x07, 1, 0xFFFF | stream_ids[0] << 16, 24, data);
stream->fd = s;
stream->streaming_ctrl->streaming_read = asf_mmst_streaming_read;
stream->streaming_ctrl->streaming_seek = asf_mmst_streaming_seek;
stream->streaming_ctrl->status = streaming_playing_e;
stream->streaming = true;
packet_length1 = packet_length;
mp_msg(MSGT_NETWORK,MSGL_INFO,"mmst packet_length = %d\n", packet_length);
#ifdef CONFIG_ICONV
if (url_conv != (iconv_t)(-1))
iconv_close(url_conv);
#endif
return 0;
}

View File

@ -1,26 +0,0 @@
/*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_ASF_MMST_STREAMING_H
#define MPLAYER_ASF_MMST_STREAMING_H
#include "stream.h"
int asf_mmst_streaming_start(stream_t *stream);
#endif /* MPLAYER_ASF_MMST_STREAMING_H */

View File

@ -1,855 +0,0 @@
/*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <libavutil/intreadwrite.h>
#include "config.h"
#include "core/mp_msg.h"
#include "core/options.h"
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#include "url.h"
#include "http.h"
#include "demux/asf.h"
#include "stream.h"
#include "demux/demux.h"
#include "asf_mmst_streaming.h"
#include "network.h"
#include "tcp.h"
#include "demux/asfguid.h"
static int asf_http_streaming_start(stream_t *stream, int *demuxer_type);
static int asf_read_wrapper(int fd, void *buffer, int len, streaming_ctrl_t *stream_ctrl) {
uint8_t *buf = buffer;
while (len > 0) {
int got = nop_streaming_read(fd, buf, len, stream_ctrl);
if (got <= 0) {
mp_tmsg(MSGT_NETWORK, MSGL_ERR, "Error while reading network stream.\n");
return got;
}
buf += got;
len -= got;
}
return 1;
}
// We can try several protocol for asf streaming
// * First we can try TCP, but if there is a proxy for
// internet connection, the TCP connection will not get
// through
// * Then we can try HTTP.
//
// Note: Using WMP sequence MMST and then HTTP.
static int asf_streaming_start( stream_t *stream, int *demuxer_type) {
char *proto = stream->streaming_ctrl->url->protocol;
int fd = -1;
int port = stream->streaming_ctrl->url->port;
//Is protocol mms or mmst?
if (!strcasecmp(proto, "mp_mmst") || !strcasecmp(proto, "mp_mms"))
{
mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/TCP...\n");
fd = asf_mmst_streaming_start( stream );
stream->streaming_ctrl->url->port = port;
if( fd>-1 ) return fd;
mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/TCP failed\n");
if( fd==-2 ) return -1;
}
//Is protocol http, http_proxy, or mms?
if (!strcasecmp(proto, "mp_http_proxy") || !strcasecmp(proto, "mp_http") ||
!strcasecmp(proto, "mp_mms") || !strcasecmp(proto, "mp_mmsh") ||
!strcasecmp(proto, "mp_mmshttp"))
{
mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/HTTP...\n");
fd = asf_http_streaming_start( stream, demuxer_type );
stream->streaming_ctrl->url->port = port;
if( fd>-1 ) return fd;
mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/HTTP failed\n");
if( fd==-2 ) return -1;
}
//everything failed
return -1;
}
static int asf_streaming(ASF_stream_chunck_t *stream_chunck, int *drop_packet ) {
/*
printf("ASF stream chunck size=%d\n", stream_chunck->size);
printf("length: %d\n", length );
printf("0x%02X\n", stream_chunck->type );
*/
if( drop_packet!=NULL ) *drop_packet = 0;
if( stream_chunck->size<8 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Ahhhh, stream_chunck size is too small: %d\n", stream_chunck->size);
return -1;
}
if( stream_chunck->size!=stream_chunck->size_confirm ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"size_confirm mismatch!: %d %d\n", stream_chunck->size, stream_chunck->size_confirm);
return -1;
}
/*
printf(" type: 0x%02X\n", stream_chunck->type );
printf(" size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size );
printf(" sequence_number: 0x%04X\n", stream_chunck->sequence_number );
printf(" unknown: 0x%02X\n", stream_chunck->unknown );
printf(" size_confirm: 0x%02X\n", stream_chunck->size_confirm );
*/
switch(stream_chunck->type) {
case ASF_STREAMING_CLEAR: // $C Clear ASF configuration
mp_msg(MSGT_NETWORK,MSGL_V,"=====> Clearing ASF stream configuration!\n");
if( drop_packet!=NULL ) *drop_packet = 1;
return stream_chunck->size;
break;
case ASF_STREAMING_DATA: // $D Data follows
// printf("=====> Data follows\n");
break;
case ASF_STREAMING_END_TRANS: // $E Transfer complete
mp_msg(MSGT_NETWORK,MSGL_V,"=====> Transfer complete\n");
if( drop_packet!=NULL ) *drop_packet = 1;
return stream_chunck->size;
break;
case ASF_STREAMING_HEADER: // $H ASF header chunk follows
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF header chunk follows\n");
break;
default:
mp_msg(MSGT_NETWORK,MSGL_V,"=====> Unknown stream type 0x%x\n", stream_chunck->type );
}
return stream_chunck->size+4;
}
static void close_s(stream_t *stream) {
closesocket(stream->fd);
stream->fd=-1;
}
static int max_idx(int s_count, int *s_rates, int bound) {
int i, best = -1, rate = -1;
for (i = 0; i < s_count; i++) {
if (s_rates[i] > rate && s_rates[i] <= bound) {
rate = s_rates[i];
best = i;
}
}
return best;
}
static int asf_streaming_parse_header(stream_t *s, int fd) {
streaming_ctrl_t* streaming_ctrl = s->streaming_ctrl;
ASF_stream_chunck_t chunk;
asf_http_streaming_ctrl_t* asf_ctrl = streaming_ctrl->data;
char* buffer=NULL, *chunk_buffer=NULL;
int i,r,size,pos = 0;
int start;
int buffer_size = 0;
int chunk_size2read = 0;
int bw = streaming_ctrl->bandwidth;
int *v_rates = NULL, *a_rates = NULL;
int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1;
if(asf_ctrl == NULL) return -1;
// The ASF header can be in several network chunks. For example if the content description
// is big, the ASF header will be split in 2 network chunk.
// So we need to retrieve all the chunk before starting to parse the header.
do {
if (asf_read_wrapper(fd, &chunk, sizeof(ASF_stream_chunck_t), streaming_ctrl) <= 0)
return -1;
// Endian handling of the stream chunk
le2me_ASF_stream_chunck_t(&chunk);
size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t);
if(r) mp_tmsg(MSGT_NETWORK,MSGL_WARN,"Warning: drop header ????\n");
if(size < 0){
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Error while parsing chunk header\n");
return -1;
}
if (chunk.type != ASF_STREAMING_HEADER) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Didn't get a header as first chunk !!!!\n");
return -1;
}
// audit: do not overflow buffer_size
if (size > SIZE_MAX - buffer_size) return -1;
buffer = malloc(size+buffer_size);
if(buffer == NULL) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Error: Can't allocate %d bytes buffer.\n",size+buffer_size);
return -1;
}
if( chunk_buffer!=NULL ) {
memcpy( buffer, chunk_buffer, buffer_size );
free( chunk_buffer );
}
chunk_buffer = buffer;
buffer += buffer_size;
buffer_size += size;
if (asf_read_wrapper(fd, buffer, size, streaming_ctrl) <= 0)
return -1;
if( chunk_size2read==0 ) {
ASF_header_t *asfh = (ASF_header_t *)buffer;
if(size < (int)sizeof(ASF_header_t)) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Error: Chunk is too small.\n");
return -1;
} else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n");
chunk_size2read = AV_RL64(&asfh->objh.size);
mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read);
}
} while( buffer_size<chunk_size2read);
buffer = chunk_buffer;
size = buffer_size;
start = sizeof(ASF_header_t);
pos = find_asf_guid(buffer, asf_file_header_guid, start, size);
if (pos >= 0) {
ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos];
pos += sizeof(ASF_file_header_t);
if (pos > size) goto len_err_out;
/*
if(fileh.packetsize != fileh.packetsize2) {
printf("Error packetsize check don't match\n");
return -1;
}
*/
asf_ctrl->packet_size = AV_RL32(&fileh->max_packet_size);
// before playing.
// preroll: time in ms to bufferize before playing
unsigned int preroll = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0));
// buffer in KBytes, *5 assuming the prefill is 20% of the buffer.
s->cache_size = preroll / 1024 * 5;
}
pos = start;
while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0)
{
ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos];
pos += sizeof(ASF_stream_header_t);
if (pos > size) goto len_err_out;
switch(ASF_LOAD_GUID_PREFIX(streamh->type)) {
case 0xF8699E40 : // audio stream
if(asf_ctrl->audio_streams == NULL){
asf_ctrl->audio_streams = malloc(sizeof(int));
asf_ctrl->n_audio = 1;
} else {
asf_ctrl->n_audio++;
asf_ctrl->audio_streams = realloc(asf_ctrl->audio_streams,
asf_ctrl->n_audio*sizeof(int));
}
asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = AV_RL16(&streamh->stream_no);
break;
case 0xBC19EFC0 : // video stream
if(asf_ctrl->video_streams == NULL){
asf_ctrl->video_streams = malloc(sizeof(int));
asf_ctrl->n_video = 1;
} else {
asf_ctrl->n_video++;
asf_ctrl->video_streams = realloc(asf_ctrl->video_streams,
asf_ctrl->n_video*sizeof(int));
}
asf_ctrl->video_streams[asf_ctrl->n_video-1] = AV_RL16(&streamh->stream_no);
break;
}
}
// always allocate to avoid lots of ifs later
v_rates = calloc(asf_ctrl->n_video, sizeof(int));
a_rates = calloc(asf_ctrl->n_audio, sizeof(int));
pos = find_asf_guid(buffer, asf_stream_group_guid, start, size);
if (pos >= 0) {
// stream bitrate properties object
int stream_count;
char *ptr = &buffer[pos];
char *end = &buffer[size];
mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n");
if (ptr + 2 > end) goto len_err_out;
stream_count = AV_RL16(ptr);
ptr += 2;
mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n",
stream_count, stream_count );
for( i=0 ; i<stream_count ; i++ ) {
uint32_t rate;
int id;
int j;
if (ptr + 6 > end) goto len_err_out;
id = AV_RL16(ptr);
ptr += 2;
rate = AV_RL32(ptr);
ptr += 4;
mp_msg(MSGT_NETWORK, MSGL_V,
" stream id=[0x%x][%u]\n", id, id);
mp_msg(MSGT_NETWORK, MSGL_V,
" max bitrate=[0x%x][%u]\n", rate, rate);
for (j = 0; j < asf_ctrl->n_video; j++) {
if (id == asf_ctrl->video_streams[j]) {
mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n");
v_rates[j] = rate;
break;
}
}
for (j = 0; j < asf_ctrl->n_audio; j++) {
if (id == asf_ctrl->audio_streams[j]) {
mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n");
a_rates[j] = rate;
break;
}
}
}
}
free(buffer);
// automatic stream selection based on bandwidth
if (bw == 0) bw = INT_MAX;
mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw);
if (asf_ctrl->n_audio) {
// find lowest-bitrate audio stream
a_rate = a_rates[0];
a_idx = 0;
for (i = 0; i < asf_ctrl->n_audio; i++) {
if (a_rates[i] < a_rate) {
a_rate = a_rates[i];
a_idx = i;
}
}
if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) {
// both audio and video are not possible, try video only next
a_idx = -1;
a_rate = 0;
}
}
// find best video stream
v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate);
if (v_idx >= 0)
v_rate = v_rates[v_idx];
// find best audio stream
a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate);
free(v_rates);
free(a_rates);
if (a_idx < 0 && v_idx < 0) {
mp_tmsg(MSGT_NETWORK, MSGL_FATAL, "Bandwidth too small, file cannot be played!\n");
return -1;
}
if (*streaming_ctrl->audio_id_ptr > 0)
// a audio stream was forced
asf_ctrl->audio_id = *streaming_ctrl->audio_id_ptr;
else if (a_idx >= 0)
asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx];
else if (asf_ctrl->n_audio) {
mp_tmsg(MSGT_NETWORK, MSGL_WARN, "Bandwidth too small, deselected audio stream.\n");
*streaming_ctrl->audio_id_ptr = -2;
}
if (*streaming_ctrl->video_id_ptr > 0)
// a video stream was forced
asf_ctrl->video_id = *streaming_ctrl->video_id_ptr;
else if (v_idx >= 0)
asf_ctrl->video_id = asf_ctrl->video_streams[v_idx];
else if (asf_ctrl->n_video) {
mp_tmsg(MSGT_NETWORK, MSGL_WARN, "Bandwidth too small, deselected video stream.\n");
*streaming_ctrl->video_id_ptr = -2;
}
return 1;
len_err_out:
mp_tmsg(MSGT_NETWORK, MSGL_FATAL, "Invalid length in ASF header!\n");
free(buffer);
free(v_rates);
free(a_rates);
return -1;
}
static int asf_http_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) {
static ASF_stream_chunck_t chunk;
int read,chunk_size = 0;
static int rest = 0, drop_chunk = 0, waiting = 0;
asf_http_streaming_ctrl_t *asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data;
while(1) {
if (rest == 0 && waiting == 0) {
if (asf_read_wrapper(fd, &chunk, sizeof(ASF_stream_chunck_t), streaming_ctrl) <= 0)
return -1;
// Endian handling of the stream chunk
le2me_ASF_stream_chunck_t(&chunk);
chunk_size = asf_streaming( &chunk, &drop_chunk );
if(chunk_size < 0) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Error while parsing chunk header\n");
return -1;
}
chunk_size -= sizeof(ASF_stream_chunck_t);
if(chunk.type != ASF_STREAMING_HEADER && (!drop_chunk)) {
if (asf_http_ctrl->packet_size < chunk_size) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Error: chunk_size > packet_size\n");
return -1;
}
waiting = asf_http_ctrl->packet_size;
} else {
waiting = chunk_size;
}
} else if (rest){
chunk_size = rest;
rest = 0;
}
read = 0;
if ( waiting >= chunk_size) {
if (chunk_size > size){
rest = chunk_size - size;
chunk_size = size;
}
if (asf_read_wrapper(fd, buffer, chunk_size, streaming_ctrl) <= 0)
return -1;
read = chunk_size;
waiting -= read;
if (drop_chunk) continue;
}
if (rest == 0 && waiting > 0 && size-read > 0) {
int s = FFMIN(waiting,size-read);
memset(buffer+read,0,s);
waiting -= s;
read += s;
}
break;
}
return read;
}
static int asf_http_streaming_seek( int fd, int64_t pos, streaming_ctrl_t *streaming_ctrl ) {
return -1;
// to shut up gcc warning
fd++;
pos++;
streaming_ctrl=NULL;
}
static int asf_header_check( HTTP_header_t *http_hdr ) {
ASF_obj_header_t *objh;
if( http_hdr==NULL ) return -1;
if( http_hdr->body==NULL || http_hdr->body_size<sizeof(ASF_obj_header_t) ) return -1;
objh = (ASF_obj_header_t*)http_hdr->body;
if( ASF_LOAD_GUID_PREFIX(objh->guid)==0x75B22630 ) return 0;
return -1;
}
static int asf_http_streaming_type(char *content_type, char *features, HTTP_header_t *http_hdr ) {
if( content_type==NULL ) return ASF_Unknown_e;
if( !strcasecmp(content_type, "application/octet-stream") ||
!strcasecmp(content_type, "application/vnd.ms.wms-hdr.asfv1") || // New in Corona, first request
!strcasecmp(content_type, "application/x-mms-framed") || // New in Corana, second request
!strcasecmp(content_type, "video/x-ms-wmv") ||
!strcasecmp(content_type, "video/x-ms-asf")) {
if( strstr(features, "broadcast") ) {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Live stream\n");
return ASF_Live_e;
} else {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Prerecorded\n");
return ASF_Prerecorded_e;
}
} else {
// Ok in a perfect world, web servers should be well configured
// so we could used mime type to know the stream type,
// but guess what? All of them are not well configured.
// So we have to check for an asf header :(, but it works :p
if( http_hdr->body_size>sizeof(ASF_obj_header_t) ) {
if( asf_header_check( http_hdr )==0 ) {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n");
return ASF_PlainText_e;
} else if( (!strcasecmp(content_type, "text/html")) ) {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> HTML, MPlayer is not a browser...yet!\n");
return ASF_Unknown_e;
} else {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Redirector\n");
return ASF_Redirector_e;
}
} else {
if( (!strcasecmp(content_type, "audio/x-ms-wax")) ||
(!strcasecmp(content_type, "audio/x-ms-wma")) ||
(!strcasecmp(content_type, "video/x-ms-asf")) ||
(!strcasecmp(content_type, "video/x-ms-afs")) ||
(!strcasecmp(content_type, "video/x-ms-wmv")) ||
(!strcasecmp(content_type, "video/x-ms-wma")) ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"=====> ASF Redirector\n");
return ASF_Redirector_e;
} else if( !strcasecmp(content_type, "text/plain") ) {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n");
return ASF_PlainText_e;
} else {
mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF unknown content-type: %s\n", content_type );
return ASF_Unknown_e;
}
}
}
return ASF_Unknown_e;
}
static HTTP_header_t *asf_http_request(streaming_ctrl_t *streaming_ctrl) {
HTTP_header_t *http_hdr;
URL_t *url = NULL;
URL_t *server_url = NULL;
asf_http_streaming_ctrl_t *asf_http_ctrl;
char str[250];
char *ptr;
int i, enable;
int offset_hi=0, offset_lo=0, length=0;
int asf_nb_stream=0, stream_id;
// Sanity check
if( streaming_ctrl==NULL ) return NULL;
url = streaming_ctrl->url;
asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data;
if( url==NULL || asf_http_ctrl==NULL ) return NULL;
// Common header for all requests.
http_hdr = http_new_header();
http_set_field( http_hdr, "Accept: */*" );
http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" );
http_add_basic_authentication( http_hdr, url->username, url->password );
// Check if we are using a proxy
if( !strcasecmp( url->protocol, "mp_http_proxy" ) ) {
server_url = url_new( (url->file)+1 );
if( server_url==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"invalid proxy URL\n");
http_free( http_hdr );
return NULL;
}
http_set_uri( http_hdr, server_url->url );
sprintf( str, "Host: %.220s:%d", server_url->hostname, server_url->port );
url_free( server_url );
} else {
http_set_uri( http_hdr, url->file );
sprintf( str, "Host: %.220s:%d", url->hostname, url->port );
}
http_set_field( http_hdr, str );
http_set_field( http_hdr, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}" );
sprintf(str,
"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=%u",
offset_hi, offset_lo, asf_http_ctrl->request, length );
http_set_field( http_hdr, str );
switch( asf_http_ctrl->streaming_type ) {
case ASF_Live_e:
case ASF_Prerecorded_e:
http_set_field( http_hdr, "Pragma: xPlayStrm=1" );
ptr = str;
ptr += sprintf( ptr, "Pragma: stream-switch-entry=");
if(asf_http_ctrl->n_audio > 0) {
for( i=0; i<asf_http_ctrl->n_audio ; i++ ) {
stream_id = asf_http_ctrl->audio_streams[i];
if(stream_id == asf_http_ctrl->audio_id) {
enable = 0;
} else {
enable = 2;
continue;
}
asf_nb_stream++;
ptr += sprintf(ptr, "ffff:%x:%d ", stream_id, enable);
}
}
if(asf_http_ctrl->n_video > 0) {
for( i=0; i<asf_http_ctrl->n_video ; i++ ) {
stream_id = asf_http_ctrl->video_streams[i];
if(stream_id == asf_http_ctrl->video_id) {
enable = 0;
} else {
enable = 2;
continue;
}
asf_nb_stream++;
ptr += sprintf(ptr, "ffff:%x:%d ", stream_id, enable);
}
}
http_set_field( http_hdr, str );
sprintf( str, "Pragma: stream-switch-count=%d", asf_nb_stream );
http_set_field( http_hdr, str );
break;
case ASF_Redirector_e:
break;
case ASF_Unknown_e:
// First request goes here.
break;
default:
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"unknown ASF stream type\n");
}
http_set_field( http_hdr, "Connection: Close" );
http_build_request( http_hdr );
return http_hdr;
}
static int asf_http_parse_response(asf_http_streaming_ctrl_t *asf_http_ctrl, HTTP_header_t *http_hdr ) {
char *content_type, *pragma;
char features[64] = "\0";
size_t len;
if( http_response_parse(http_hdr)<0 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Failed to parse HTTP response.\n");
return -1;
}
switch( http_hdr->status_code ) {
case 200:
break;
case 401: // Authentication required
return ASF_Authenticate_e;
default:
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Server returned %d:%s\n", http_hdr->status_code, http_hdr->reason_phrase);
return -1;
}
content_type = http_get_field( http_hdr, "Content-Type");
//printf("Content-Type: [%s]\n", content_type);
pragma = http_get_field( http_hdr, "Pragma");
while( pragma!=NULL ) {
char *comma_ptr=NULL;
char *end;
//printf("Pragma: [%s]\n", pragma );
// The pragma line can get severals attributes
// separeted with a comma ','.
do {
if( !strncasecmp( pragma, "features=", 9) ) {
pragma += 9;
end = strstr( pragma, "," );
if( end==NULL ) {
len = strlen(pragma);
} else {
len = (unsigned int)(end-pragma);
}
if(len > sizeof(features) - 1) {
mp_tmsg(MSGT_NETWORK,MSGL_WARN,"ASF HTTP PARSE WARNING : Pragma %s cut from %zd bytes to %zd\n",pragma,len,sizeof(features) - 1);
len = sizeof(features) - 1;
}
strncpy( features, pragma, len );
features[len]='\0';
break;
}
comma_ptr = strstr( pragma, "," );
if( comma_ptr!=NULL ) {
pragma = comma_ptr+1;
if( pragma[0]==' ' ) pragma++;
}
} while( comma_ptr!=NULL );
pragma = http_get_next_field( http_hdr );
}
asf_http_ctrl->streaming_type = asf_http_streaming_type( content_type, features, http_hdr );
return 0;
}
static int asf_http_streaming_start( stream_t *stream, int *demuxer_type ) {
HTTP_header_t *http_hdr=NULL;
URL_t *url = stream->streaming_ctrl->url;
asf_http_streaming_ctrl_t *asf_http_ctrl;
char buffer[BUFFER_SIZE];
int i, ret;
int fd = stream->fd;
int done;
int auth_retry = 0;
asf_http_ctrl = malloc(sizeof(asf_http_streaming_ctrl_t));
if( asf_http_ctrl==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return -1;
}
asf_http_ctrl->streaming_type = ASF_Unknown_e;
asf_http_ctrl->request = 1;
asf_http_ctrl->audio_streams = asf_http_ctrl->video_streams = NULL;
asf_http_ctrl->n_audio = asf_http_ctrl->n_video = 0;
stream->streaming_ctrl->data = (void*)asf_http_ctrl;
do {
done = 1;
if( fd>0 ) closesocket( fd );
if( !strcasecmp( url->protocol, "mp_http_proxy" ) ) {
if( url->port==0 ) url->port = 8080;
} else {
if( url->port==0 ) url->port = 80;
}
fd = connect2Server( url->hostname, url->port, 1);
if( fd<0 ) return fd;
http_hdr = asf_http_request( stream->streaming_ctrl );
mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request [%s]\n", http_hdr->buffer );
for(i=0; i < (int)http_hdr->buffer_size ; ) {
int r = send( fd, http_hdr->buffer+i, http_hdr->buffer_size-i, DEFAULT_SEND_FLAGS );
if(r <0) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"socket write error: %s\n",strerror(errno));
goto err_out;
}
i += r;
}
http_free( http_hdr );
http_hdr = http_new_header();
do {
i = recv( fd, buffer, BUFFER_SIZE, 0 );
//printf("read: %d\n", i );
if( i<=0 ) {
perror("read");
goto err_out;
}
http_response_append( http_hdr, buffer, i );
} while( !http_is_header_entire( http_hdr ) );
if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) {
http_hdr->buffer[http_hdr->buffer_size]='\0';
mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer );
}
ret = asf_http_parse_response(asf_http_ctrl, http_hdr);
if( ret<0 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Failed to parse header.\n");
goto err_out;
}
switch( asf_http_ctrl->streaming_type ) {
case ASF_Live_e:
case ASF_Prerecorded_e:
case ASF_PlainText_e:
if( http_hdr->body_size>0 ) {
if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
goto err_out;
}
}
if( asf_http_ctrl->request==1 ) {
if( asf_http_ctrl->streaming_type!=ASF_PlainText_e ) {
// First request, we only got the ASF header.
ret = asf_streaming_parse_header(stream,fd);
if(ret < 0) goto err_out;
if(asf_http_ctrl->n_audio == 0 && asf_http_ctrl->n_video == 0) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"No stream found.\n");
goto err_out;
}
asf_http_ctrl->request++;
done = 0;
} else {
done = 1;
}
}
break;
case ASF_Redirector_e:
if( http_hdr->body_size>0 ) {
if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
goto err_out;
}
}
*demuxer_type = DEMUXER_TYPE_PLAYLIST;
done = 1;
break;
case ASF_Authenticate_e:
if( http_authenticate( http_hdr, url, &auth_retry)<0 ) return -1;
asf_http_ctrl->streaming_type = ASF_Unknown_e;
done = 0;
break;
case ASF_Unknown_e:
default:
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"unknown ASF streaming type\n");
goto err_out;
}
// Check if we got a redirect.
} while(!done);
stream->fd = fd;
if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e ) {
stream->streaming_ctrl->streaming_read = nop_streaming_read;
stream->streaming_ctrl->streaming_seek = nop_streaming_seek;
} else {
stream->streaming_ctrl->streaming_read = asf_http_streaming_read;
stream->streaming_ctrl->streaming_seek = asf_http_streaming_seek;
stream->streaming = true;
}
stream->streaming_ctrl->status = streaming_playing_e;
stream->close = close_s;
http_free( http_hdr );
return 0;
err_out:
if (fd > 0)
closesocket(fd);
stream->fd = -1;
http_free(http_hdr);
return -1;
}
static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
stream->streaming_ctrl = streaming_ctrl_new();
if( stream->streaming_ctrl==NULL ) {
return STREAM_ERROR;
}
stream->streaming_ctrl->audio_id_ptr = &stream->opts->audio_id;
stream->streaming_ctrl->video_id_ptr = &stream->opts->video_id;
stream->streaming_ctrl->bandwidth = network_bandwidth;
stream->streaming_ctrl->url = url_new_with_proxy(stream->url);
mp_tmsg(MSGT_OPEN, MSGL_INFO, "STREAM_ASF, URL: %s\n", stream->url);
if((!strncmp(stream->url, "mp_http", 4)) && (*file_format!=DEMUXER_TYPE_ASF && *file_format!=DEMUXER_TYPE_UNKNOWN)) {
streaming_ctrl_free(stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
if(asf_streaming_start(stream, file_format) < 0) {
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed, exiting.\n");
streaming_ctrl_free(stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
if (*file_format != DEMUXER_TYPE_PLAYLIST)
*file_format = DEMUXER_TYPE_ASF;
stream->type = STREAMTYPE_STREAM;
return STREAM_OK;
}
const stream_info_t stream_info_asf = {
"mms and mms over http streaming",
"null",
"Bertrand, Reimar Doeffinger, Albeu",
"originally based on work by Majormms (is that code still there?)",
open_s,
{"mp_mms", "mp_mmst", "mp_http", "mp_http_proxy", "mp_mmsh", "mp_mmshttp", NULL},
NULL,
0 // Urls are an option string
};

View File

@ -33,8 +33,8 @@
#include "osdep/io.h"
#include "core/options.h"
#include "cookies.h"
#include "http.h"
#include "core/mp_msg.h"
#define MAX_COOKIES 20
@ -72,24 +72,6 @@ static char *col_dup(const char *src)
return dst;
}
static int right_hand_strcmp(const char *cookie_domain, const char *url_domain)
{
int c_l;
int u_l;
c_l = strlen(cookie_domain);
u_l = strlen(url_domain);
if (c_l > u_l)
return -1;
return strcmp(cookie_domain, url_domain + u_l - c_l);
}
static int left_hand_strcmp(const char *cookie_path, const char *url_path)
{
return strncmp(cookie_path, url_path, strlen(cookie_path));
}
/* Finds the start of all the columns */
static int parse_line(char **ptr, char *cols[6])
{
@ -196,72 +178,6 @@ static struct cookie_list_type *load_cookies(void)
return NULL;
}
/* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */
void
cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url)
{
int found_cookies = 0;
struct cookie_list_type *cookies[MAX_COOKIES];
struct cookie_list_type *list, *start;
int i;
char *path;
char *buf;
path = strchr(url, '/');
if (!path)
path = "";
if (!cookie_list)
cookie_list = load_cookies();
list = start = cookie_list;
/* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */
while (list) {
/* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */
if ((right_hand_strcmp(list->domain, domain) == 0)
&& (left_hand_strcmp(list->path, path) == 0) && !list->secure) {
int replacing = 0;
for (i = 0; i < found_cookies; i++) {
if (strcmp(list->name, cookies[i]->name) == 0) {
replacing = 0;
if (strlen(list->domain) <= strlen(cookies[i]->domain)) {
cookies[i] = list;
} else if (strlen(list->path) <= strlen(cookies[i]->path)) {
cookies[i] = list;
}
}
}
if (found_cookies > MAX_COOKIES) {
/* Cookie jar overflow! */
break;
}
if (!replacing)
cookies[found_cookies++] = list;
}
list = list->next;
}
buf = strdup("Cookie:");
for (i = 0; i < found_cookies; i++) {
char *nbuf;
nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) +
strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1);
sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name,
cookies[i]->value);
free(buf);
buf = nbuf;
}
if (found_cookies)
http_set_field(http_hdr, buf);
free(buf);
}
// Return a cookies string as expected by lavf (libavformat/http.c). The format
// is like a Set-Cookie header (http://curl.haxx.se/rfc/cookie_spec.html),
// separated by newlines.

View File

@ -24,10 +24,6 @@
#ifndef MPLAYER_COOKIES_H
#define MPLAYER_COOKIES_H
#include "http.h"
void cookies_set(HTTP_header_t * http_hdr, const char *hostname,
const char *url);
char *cookies_lavf(void);
#endif /* MPLAYER_COOKIES_H */

View File

@ -1,966 +0,0 @@
/*
* HTTP Helper
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if !HAVE_WINSOCK2_H
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "http.h"
#include "url.h"
#include "core/options.h"
#include "core/mp_msg.h"
#include "stream.h"
#include "demux/demux.h"
#include "network.h"
#include "libavutil/base64.h"
#include <libavutil/avutil.h>
typedef struct {
unsigned metaint;
unsigned metapos;
int is_ultravox;
} scast_data_t;
/**
* \brief first read any data from sc->buffer then from fd
* \param fd file descriptor to read data from
* \param buffer buffer to read into
* \param len how many bytes to read
* \param sc streaming control containing buffer to read from first
* \return len unless there is a read error or eof
*/
static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) {
unsigned pos = 0;
unsigned cp_len = sc->buffer_size - sc->buffer_pos;
if (cp_len > len)
cp_len = len;
memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len);
sc->buffer_pos += cp_len;
pos += cp_len;
while (pos < len) {
int ret = recv(fd, &buffer[pos], len - pos, 0);
if (ret <= 0)
break;
pos += ret;
}
return pos;
}
/**
* \brief read and process (i.e. discard *g*) a block of ultravox metadata
* \param fd file descriptor to read from
* \param sc streaming_ctrl_t whose buffer is consumed before reading from fd
* \return number of real data before next metadata block starts or 0 on error
*
* You can use unsv://samples.mplayerhq.hu/V-codecs/VP5/vp5_artefacts.nsv to
* test.
*/
static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) {
unsigned metaint;
unsigned char info[6] = {0, 0, 0, 0, 0, 0};
int info_read;
do {
info_read = my_read(fd, info, 1, sc);
if (info[0] == 0x00)
info_read = my_read(fd, info, 6, sc);
else
info_read += my_read(fd, &info[1], 5, sc);
if (info_read != 6) // read error or eof
return 0;
// sync byte and reserved flags
if (info[0] != 0x5a || (info[1] & 0xfc) != 0x00) {
mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n");
return 0;
}
if (info[1] & 0x01)
mp_msg(MSGT_DEMUXER, MSGL_WARN, "Encrypted ultravox data\n");
metaint = info[4] << 8 | info[5];
if ((info[3] & 0xf) < 0x07) { // discard any metadata nonsense
char *metabuf = malloc(metaint);
my_read(fd, metabuf, metaint, sc);
free(metabuf);
}
} while ((info[3] & 0xf) < 0x07);
return metaint;
}
/**
* \brief read one scast meta data entry and print it
* \param fd file descriptor to read from
* \param sc streaming_ctrl_t whose buffer is consumed before reading from fd
*/
static void scast_meta_read(int fd, streaming_ctrl_t *sc) {
unsigned char tmp = 0;
unsigned metalen;
my_read(fd, &tmp, 1, sc);
metalen = tmp * 16;
if (metalen > 0) {
int i;
uint8_t *info = malloc(metalen + 1);
unsigned nlen = my_read(fd, info, metalen, sc);
// avoid breaking the user's terminal too much
if (nlen > 256) nlen = 256;
for (i = 0; i < nlen; i++)
if (info[i] && info[i] < 32) info[i] = '?';
info[nlen] = 0;
mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info);
free(info);
}
}
/**
* \brief read data from scast/ultravox stream without any metadata
* \param fd file descriptor to read from
* \param buffer buffer to read data into
* \param size number of bytes to read
* \param sc streaming_ctrl_t whose buffer is consumed before reading from fd
*/
static int scast_streaming_read(int fd, char *buffer, int size,
streaming_ctrl_t *sc) {
scast_data_t *sd = (scast_data_t *)sc->data;
unsigned block, ret;
unsigned done = 0;
// first read remaining data up to next metadata
block = sd->metaint - sd->metapos;
if (block > size)
block = size;
ret = my_read(fd, buffer, block, sc);
sd->metapos += ret;
done += ret;
if (ret != block) // read problems or eof
size = done;
while (done < size) { // now comes the metadata
if (sd->is_ultravox)
{
sd->metaint = uvox_meta_read(fd, sc);
if (!sd->metaint)
size = done;
}
else
scast_meta_read(fd, sc); // read and display metadata
sd->metapos = 0;
block = size - done;
if (block > sd->metaint)
block = sd->metaint;
ret = my_read(fd, &buffer[done], block, sc);
sd->metapos += ret;
done += ret;
if (ret != block) // read problems or eof
size = done;
}
return done;
}
static int scast_streaming_start(stream_t *stream) {
int metaint;
scast_data_t *scast_data;
HTTP_header_t *http_hdr = stream->streaming_ctrl->data;
if (!stream || stream->fd < 0 || !http_hdr)
return -1;
int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0;
if (is_ultravox)
metaint = 0;
else {
metaint = -1;
char *h = http_get_field(http_hdr, "Icy-MetaInt");
if (h)
metaint = atoi(h);
if (metaint <= 0)
return -1;
}
stream->streaming_ctrl->buffer = malloc(http_hdr->body_size);
stream->streaming_ctrl->buffer_size = http_hdr->body_size;
stream->streaming_ctrl->buffer_pos = 0;
memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size);
scast_data = malloc(sizeof(scast_data_t));
scast_data->metaint = metaint;
scast_data->metapos = 0;
scast_data->is_ultravox = is_ultravox;
http_free(http_hdr);
stream->streaming_ctrl->data = scast_data;
stream->streaming_ctrl->streaming_read = scast_streaming_read;
stream->streaming_ctrl->streaming_seek = NULL;
stream->streaming_ctrl->status = streaming_playing_e;
stream->streaming = true;
return 0;
}
static int nop_streaming_start( stream_t *stream ) {
HTTP_header_t *http_hdr = NULL;
char *next_url=NULL;
int fd,ret;
if( stream==NULL ) return -1;
fd = stream->fd;
if( fd<0 ) {
fd = http_send_request( stream->streaming_ctrl->url, 0 );
if( fd<0 ) return -1;
http_hdr = http_read_response( fd );
if( http_hdr==NULL ) return -1;
switch( http_hdr->status_code ) {
case 200: // OK
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") );
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") );
if( http_hdr->body_size>0 ) {
if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
http_free( http_hdr );
return -1;
}
}
break;
// Redirect
case 301: // Permanently
case 302: // Temporarily
case 303: // See Other
case 307: // Temporarily (since HTTP/1.1)
ret=-1;
next_url = http_get_field( http_hdr, "Location" );
if (next_url != NULL) {
mp_msg(MSGT_NETWORK,MSGL_STATUS,"Redirected: Using this url instead %s\n",next_url);
stream->streaming_ctrl->url=url_new_with_proxy(next_url);
ret=nop_streaming_start(stream); //recursively get streaming started
} else {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n");
closesocket( fd );
fd = -1;
}
return ret;
break;
case 401: //Authorization required
case 403: //Forbidden
case 404: //Not found
case 500: //Server Error
default:
mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
closesocket( fd );
fd = -1;
return -1;
break;
}
stream->fd = fd;
} else {
http_hdr = (HTTP_header_t*)stream->streaming_ctrl->data;
if( http_hdr->body_size>0 ) {
if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
http_free( http_hdr );
stream->streaming_ctrl->data = NULL;
return -1;
}
}
}
if( http_hdr ) {
http_free( http_hdr );
stream->streaming_ctrl->data = NULL;
}
stream->streaming_ctrl->streaming_read = nop_streaming_read;
stream->streaming_ctrl->streaming_seek = nop_streaming_seek;
stream->streaming_ctrl->status = streaming_playing_e;
stream->streaming = true;
return 0;
}
HTTP_header_t *
http_new_header(void) {
HTTP_header_t *http_hdr;
http_hdr = calloc(1, sizeof(*http_hdr));
if( http_hdr==NULL ) return NULL;
return http_hdr;
}
void
http_free( HTTP_header_t *http_hdr ) {
HTTP_field_t *field, *field2free;
if( http_hdr==NULL ) return;
free(http_hdr->protocol);
free(http_hdr->uri);
free(http_hdr->reason_phrase);
free(http_hdr->field_search);
free(http_hdr->method);
free(http_hdr->buffer);
field = http_hdr->first_field;
while( field!=NULL ) {
field2free = field;
free(field->field_name);
field = field->next;
free( field2free );
}
free( http_hdr );
http_hdr = NULL;
}
int
http_response_append( HTTP_header_t *http_hdr, char *response, int length ) {
if( http_hdr==NULL || response==NULL || length<0 ) return -1;
if( (unsigned)length > SIZE_MAX - http_hdr->buffer_size - 1) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Bad size in memory (re)allocation\n");
return -1;
}
http_hdr->buffer = realloc( http_hdr->buffer, http_hdr->buffer_size+length+1 );
if( http_hdr->buffer==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory (re)allocation failed\n");
return -1;
}
memcpy( http_hdr->buffer+http_hdr->buffer_size, response, length );
http_hdr->buffer_size += length;
http_hdr->buffer[http_hdr->buffer_size]=0; // close the string!
return http_hdr->buffer_size;
}
int
http_is_header_entire( HTTP_header_t *http_hdr ) {
if( http_hdr==NULL ) return -1;
if( http_hdr->buffer==NULL ) return 0; // empty
if(http_hdr->buffer_size > 128*1024) return 1;
if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL &&
strstr(http_hdr->buffer, "\n\n")==NULL ) return 0;
return 1;
}
int
http_response_parse( HTTP_header_t *http_hdr ) {
char *hdr_ptr, *ptr;
char *field=NULL;
int pos_hdr_sep, hdr_sep_len;
size_t len;
if( http_hdr==NULL ) return -1;
if( http_hdr->is_parsed ) return 0;
// Get the protocol
hdr_ptr = strstr( http_hdr->buffer, " " );
if( hdr_ptr==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. No space separator found.\n");
return -1;
}
len = hdr_ptr-http_hdr->buffer;
http_hdr->protocol = malloc(len+1);
if( http_hdr->protocol==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return -1;
}
strncpy( http_hdr->protocol, http_hdr->buffer, len );
http_hdr->protocol[len]='\0';
if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) {
if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get HTTP minor version.\n");
return -1;
}
}
// Get the status code
if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get status code.\n");
return -1;
}
hdr_ptr += 4;
// Get the reason phrase
ptr = strstr( hdr_ptr, "\n" );
if( ptr==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get the reason phrase.\n");
return -1;
}
len = ptr-hdr_ptr;
http_hdr->reason_phrase = malloc(len+1);
if( http_hdr->reason_phrase==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return -1;
}
strncpy( http_hdr->reason_phrase, hdr_ptr, len );
if( http_hdr->reason_phrase[len-1]=='\r' ) {
len--;
}
http_hdr->reason_phrase[len]='\0';
// Set the position of the header separator: \r\n\r\n
hdr_sep_len = 4;
ptr = strstr( http_hdr->buffer, "\r\n\r\n" );
if( ptr==NULL ) {
hdr_sep_len = 2;
ptr = strstr( http_hdr->buffer, "\n\n" );
if( ptr==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Header may be incomplete. No CRLF CRLF found.\n");
hdr_sep_len = 0;
}
}
pos_hdr_sep = ptr-http_hdr->buffer;
// Point to the first line after the method line.
hdr_ptr = strstr( http_hdr->buffer, "\n" )+1;
do {
ptr = hdr_ptr;
while( *ptr!='\r' && *ptr!='\n' ) ptr++;
len = ptr-hdr_ptr;
if (len == 0 || !memchr(hdr_ptr, ':', len)) {
mp_msg(MSGT_NETWORK, MSGL_ERR, "Broken response header, missing ':'\n");
pos_hdr_sep = ptr - http_hdr->buffer;
hdr_sep_len = 0;
break;
}
if (len > 16 && !strncasecmp(hdr_ptr + 4, "icy-metaint:", 12))
{
mp_msg(MSGT_NETWORK, MSGL_WARN, "Server sent a severely broken icy-metaint HTTP header!\n");
hdr_ptr += 4;
len -= 4;
}
field = realloc(field, len+1);
if( field==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n");
return -1;
}
strncpy( field, hdr_ptr, len );
field[len]='\0';
http_set_field( http_hdr, field );
hdr_ptr = ptr+((*ptr=='\r')?2:1);
} while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) );
free(field);
if( pos_hdr_sep+hdr_sep_len<http_hdr->buffer_size ) {
// Response has data!
http_hdr->body = http_hdr->buffer+pos_hdr_sep+hdr_sep_len;
http_hdr->body_size = http_hdr->buffer_size-(pos_hdr_sep+hdr_sep_len);
}
http_hdr->is_parsed = 1;
return 0;
}
char *
http_build_request( HTTP_header_t *http_hdr ) {
char *ptr;
int len;
HTTP_field_t *field;
if( http_hdr==NULL ) return NULL;
if( http_hdr->uri==NULL ) return NULL;
if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET");
if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/");
if( !http_hdr->uri || !http_hdr->method)
return NULL;
//**** Compute the request length
// Add the Method line
len = strlen(http_hdr->method)+strlen(http_hdr->uri)+12;
// Add the fields
field = http_hdr->first_field;
while( field!=NULL ) {
len += strlen(field->field_name)+2;
field = field->next;
}
// Add the CRLF
len += 2;
// Add the body
if( http_hdr->body!=NULL ) {
len += http_hdr->body_size;
}
// Free the buffer if it was previously used
if( http_hdr->buffer!=NULL ) {
free( http_hdr->buffer );
http_hdr->buffer = NULL;
}
http_hdr->buffer = malloc(len+1);
if( http_hdr->buffer==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n");
return NULL;
}
http_hdr->buffer_size = len;
//*** Building the request
ptr = http_hdr->buffer;
// Add the method line
ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, http_hdr->uri, http_hdr->http_minor_version );
field = http_hdr->first_field;
// Add the field
while( field!=NULL ) {
ptr += sprintf( ptr, "%s\r\n", field->field_name );
field = field->next;
}
ptr += sprintf( ptr, "\r\n" );
// Add the body
if( http_hdr->body!=NULL ) {
memcpy( ptr, http_hdr->body, http_hdr->body_size );
}
return http_hdr->buffer;
}
char *
http_get_field( HTTP_header_t *http_hdr, const char *field_name ) {
if( http_hdr==NULL || field_name==NULL ) return NULL;
http_hdr->field_search_pos = http_hdr->first_field;
http_hdr->field_search = realloc( http_hdr->field_search, strlen(field_name)+1 );
if( http_hdr->field_search==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return NULL;
}
strcpy( http_hdr->field_search, field_name );
return http_get_next_field( http_hdr );
}
char *
http_get_next_field( HTTP_header_t *http_hdr ) {
char *ptr;
HTTP_field_t *field;
if( http_hdr==NULL ) return NULL;
field = http_hdr->field_search_pos;
while( field!=NULL ) {
ptr = strstr( field->field_name, ":" );
if( ptr==NULL ) return NULL;
if( !strncasecmp( field->field_name, http_hdr->field_search, ptr-(field->field_name) ) ) {
ptr++; // Skip the column
while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some
http_hdr->field_search_pos = field->next;
return ptr; // return the value without the field name
}
field = field->next;
}
return NULL;
}
void
http_set_field( HTTP_header_t *http_hdr, const char *field_name ) {
HTTP_field_t *new_field;
if( http_hdr==NULL || field_name==NULL ) return;
new_field = malloc(sizeof(HTTP_field_t));
if( new_field==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return;
}
new_field->next = NULL;
new_field->field_name = malloc(strlen(field_name)+1);
if( new_field->field_name==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
free(new_field);
return;
}
strcpy( new_field->field_name, field_name );
if( http_hdr->last_field==NULL ) {
http_hdr->first_field = new_field;
} else {
http_hdr->last_field->next = new_field;
}
http_hdr->last_field = new_field;
http_hdr->field_nb++;
}
void
http_set_method( HTTP_header_t *http_hdr, const char *method ) {
if( http_hdr==NULL || method==NULL ) return;
http_hdr->method = malloc(strlen(method)+1);
if( http_hdr->method==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return;
}
strcpy( http_hdr->method, method );
}
void
http_set_uri( HTTP_header_t *http_hdr, const char *uri ) {
if( http_hdr==NULL || uri==NULL ) return;
http_hdr->uri = malloc(strlen(uri)+1);
if( http_hdr->uri==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
return;
}
strcpy( http_hdr->uri, uri );
}
static int
http_add_authentication( HTTP_header_t *http_hdr, const char *username, const char *password, const char *auth_str ) {
char *auth = NULL, *usr_pass = NULL, *b64_usr_pass = NULL;
int encoded_len, pass_len=0;
size_t auth_len, usr_pass_len;
int res = -1;
if( http_hdr==NULL || username==NULL ) return -1;
if( password!=NULL ) {
pass_len = strlen(password);
}
usr_pass_len = strlen(username) + 1 + pass_len;
usr_pass = malloc(usr_pass_len + 1);
if( usr_pass==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
goto out;
}
sprintf( usr_pass, "%s:%s", username, (password==NULL)?"":password );
encoded_len = AV_BASE64_SIZE(usr_pass_len);
b64_usr_pass = malloc(encoded_len);
if( b64_usr_pass==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
goto out;
}
av_base64_encode(b64_usr_pass, encoded_len, usr_pass, usr_pass_len);
auth_len = encoded_len + 100;
auth = malloc(auth_len);
if( auth==NULL ) {
mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n");
goto out;
}
snprintf(auth, auth_len, "%s: Basic %s", auth_str, b64_usr_pass);
http_set_field( http_hdr, auth );
res = 0;
out:
free( usr_pass );
free( b64_usr_pass );
free( auth );
return res;
}
int
http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ) {
return http_add_authentication(http_hdr, username, password, "Authorization");
}
int
http_add_basic_proxy_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ) {
return http_add_authentication(http_hdr, username, password, "Proxy-Authorization");
}
void
http_debug_hdr( HTTP_header_t *http_hdr ) {
HTTP_field_t *field;
int i = 0;
if( http_hdr==NULL ) return;
mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- START ---\n");
mp_msg(MSGT_NETWORK,MSGL_V,"protocol: [%s]\n", http_hdr->protocol );
mp_msg(MSGT_NETWORK,MSGL_V,"http minor version: [%d]\n", http_hdr->http_minor_version );
mp_msg(MSGT_NETWORK,MSGL_V,"uri: [%s]\n", http_hdr->uri );
mp_msg(MSGT_NETWORK,MSGL_V,"method: [%s]\n", http_hdr->method );
mp_msg(MSGT_NETWORK,MSGL_V,"status code: [%d]\n", http_hdr->status_code );
mp_msg(MSGT_NETWORK,MSGL_V,"reason phrase: [%s]\n", http_hdr->reason_phrase );
mp_msg(MSGT_NETWORK,MSGL_V,"body size: [%zd]\n", http_hdr->body_size );
mp_msg(MSGT_NETWORK,MSGL_V,"Fields:\n");
field = http_hdr->first_field;
while( field!=NULL ) {
mp_msg(MSGT_NETWORK,MSGL_V," %d - %s\n", i++, field->field_name );
field = field->next;
}
mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- END ---\n");
}
static void print_icy_metadata(HTTP_header_t *http_hdr) {
const char *field_data;
// note: I skip icy-notice1 and 2, as they contain html <BR>
// and are IMHO useless info ::atmos
if( (field_data = http_get_field(http_hdr, "icy-name")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Name : %s\n", field_data);
if( (field_data = http_get_field(http_hdr, "icy-genre")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Genre : %s\n", field_data);
if( (field_data = http_get_field(http_hdr, "icy-url")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Website: %s\n", field_data);
// XXX: does this really mean public server? ::atmos
if( (field_data = http_get_field(http_hdr, "icy-pub")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no");
if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL )
mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data);
}
//! If this function succeeds you must closesocket stream->fd
static int http_streaming_start(stream_t *stream, int* file_format) {
HTTP_header_t *http_hdr = NULL;
int fd = stream->fd;
int res = STREAM_UNSUPPORTED;
int redirect = 0;
int auth_retry=0;
int seekable=0;
char *content_type;
const char *content_length;
char *next_url;
URL_t *url = stream->streaming_ctrl->url;
do
{
redirect = 0;
if (fd >= 0) closesocket(fd);
fd = http_send_request( url, 0 );
if( fd<0 ) {
goto err_out;
}
http_free(http_hdr);
http_hdr = http_read_response( fd );
if( http_hdr==NULL ) {
goto err_out;
}
if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) {
http_debug_hdr( http_hdr );
}
// Check if we can make partial content requests and thus seek in http-streams
if( http_hdr!=NULL && http_hdr->status_code==200 ) {
const char *accept_ranges = http_get_field(http_hdr,"Accept-Ranges");
const char *server = http_get_field(http_hdr, "Server");
if (accept_ranges)
seekable = strncmp(accept_ranges,"bytes",5)==0;
else if (server && (strcmp(server, "gvs 1.0") == 0 ||
strncmp(server, "MakeMKV", 7) == 0)) {
// HACK for youtube and MakeMKV incorrectly claiming not to support seeking
mp_msg(MSGT_NETWORK, MSGL_WARN, "Broken webserver, incorrectly claims to not support Accept-Ranges\n");
seekable = 1;
}
}
print_icy_metadata(http_hdr);
// Check if the response is an ICY status_code reason_phrase
if( !strcasecmp(http_hdr->protocol, "ICY") ||
http_get_field(http_hdr, "Icy-MetaInt") ) {
switch( http_hdr->status_code ) {
case 200: { // OK
char *field_data;
// If content-type == video/nsv we most likely have a winamp video stream
// otherwise it should be mp3. if there are more types consider adding mime type
// handling like later
if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox")))
*file_format = DEMUXER_TYPE_NSV;
else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac")))
*file_format = DEMUXER_TYPE_AAC;
else
*file_format = DEMUXER_TYPE_LAVF;
res = STREAM_ERROR;
goto out;
}
case 400: // Server Full
mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server is full, skipping!\n");
goto err_out;
case 401: // Service Unavailable
mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return service unavailable, skipping!\n");
goto err_out;
case 403: // Service Forbidden
mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return 'Service Forbidden'\n");
goto err_out;
case 404: // Resource Not Found
mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server couldn't find requested stream, skipping!\n");
goto err_out;
default:
mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: unhandled ICY-Errorcode, contact MPlayer developers!\n");
goto err_out;
}
}
// Assume standard http if not ICY
switch( http_hdr->status_code ) {
case 200: // OK
content_length = http_get_field(http_hdr, "Content-Length");
if (content_length) {
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", content_length);
stream->end_pos = atoll(content_length);
}
// Look if we can use the Content-Type
content_type = http_get_field( http_hdr, "Content-Type" );
if( content_type!=NULL ) {
unsigned int i;
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type );
// Check in the mime type table for a demuxer type
for (i = 0; mime_type_table[i].mime_type != NULL; i++) {
if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) {
*file_format = mime_type_table[i].demuxer_type;
res = seekable;
goto out;
}
}
}
// Not found in the mime type table, don't fail,
// we should try raw HTTP
res = seekable;
goto out;
// Redirect
case 301: // Permanently
case 302: // Temporarily
case 303: // See Other
case 307: // Temporarily (since HTTP/1.1)
// TODO: RFC 2616, recommand to detect infinite redirection loops
next_url = http_get_field( http_hdr, "Location" );
if( next_url!=NULL ) {
int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0;
stream->streaming_ctrl->url = url_redirect( &url, next_url );
if (url_is_protocol(url, "mms")) {
res = STREAM_REDIRECTED;
goto err_out;
}
if (!url_is_protocol(url, "http")) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"Unsupported http %d redirect to %s protocol\n", http_hdr->status_code, url->protocol);
goto err_out;
}
if (is_ultravox)
url_set_protocol(url, "unsv");
redirect = 1;
}
break;
case 401: // Authentication required
if( http_authenticate(http_hdr, url, &auth_retry)<0 )
goto err_out;
redirect = 1;
break;
default:
mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
goto err_out;
}
} while( redirect );
err_out:
if (fd >= 0) closesocket( fd );
fd = -1;
http_free( http_hdr );
http_hdr = NULL;
out:
stream->streaming_ctrl->data = http_hdr;
stream->fd = fd;
return res;
}
static int fixup_open(stream_t *stream,int seekable) {
HTTP_header_t *http_hdr = stream->streaming_ctrl->data;
int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt");
int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0;
stream->type = STREAMTYPE_STREAM;
if(!is_icy && !is_ultravox && seekable)
{
stream->flags |= MP_STREAM_SEEK;
stream->seek = http_seek;
}
stream->streaming_ctrl->bandwidth = network_bandwidth;
if ((!is_icy && !is_ultravox) || scast_streaming_start(stream))
if(nop_streaming_start( stream )) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n");
if (stream->fd >= 0)
closesocket(stream->fd);
stream->fd = -1;
streaming_ctrl_free(stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
return STREAM_OK;
}
static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) {
int seekable=0;
stream->streaming_ctrl = streaming_ctrl_new();
if( stream->streaming_ctrl==NULL ) {
return STREAM_ERROR;
}
stream->streaming_ctrl->bandwidth = network_bandwidth;
stream->streaming_ctrl->url = url_new_with_proxy(stream->url);
mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(1), URL: %s\n", stream->url);
seekable = http_streaming_start(stream, file_format);
if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) {
if (stream->fd >= 0)
closesocket(stream->fd);
stream->fd = -1;
if (seekable == STREAM_REDIRECTED)
return seekable;
streaming_ctrl_free(stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
return fixup_open(stream, seekable);
}
static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) {
int seekable=0;
stream->streaming_ctrl = streaming_ctrl_new();
if( stream->streaming_ctrl==NULL ) {
return STREAM_ERROR;
}
stream->streaming_ctrl->bandwidth = network_bandwidth;
stream->streaming_ctrl->url = url_new_with_proxy(stream->url);
mp_msg(MSGT_OPEN, MSGL_V, "STREAM_HTTP(2), URL: %s\n", stream->url);
seekable = http_streaming_start(stream, file_format);
if(seekable < 0) {
if (stream->fd >= 0)
closesocket(stream->fd);
stream->fd = -1;
streaming_ctrl_free(stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
return fixup_open(stream, seekable);
}
const stream_info_t stream_info_http1 = {
"http streaming",
"null",
"Bertrand, Albeau, Reimar Doeffinger, Arpi?",
"plain http",
open_s1,
{"mp_http", "mp_http_proxy", "unsv", "icyx", "noicyx", NULL},
NULL,
0 // Urls are an option string
};
const stream_info_t stream_info_http2 = {
"http streaming",
"null",
"Bertrand, Albeu, Arpi? who?",
"plain http, also used as fallback for many other protocols",
open_s2,
{"mp_http", "mp_http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback
NULL,
0 // Urls are an option string
};

View File

@ -1,70 +0,0 @@
/*
* HTTP Helper
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_HTTP_H
#define MPLAYER_HTTP_H
#include <sys/types.h>
typedef struct HTTP_field_type {
char *field_name;
struct HTTP_field_type *next;
} HTTP_field_t;
typedef struct {
char *protocol;
char *method;
char *uri;
unsigned int status_code;
char *reason_phrase;
unsigned int http_minor_version;
// Field variables
HTTP_field_t *first_field;
HTTP_field_t *last_field;
unsigned int field_nb;
char *field_search;
HTTP_field_t *field_search_pos;
// Body variables
char *body;
size_t body_size;
char *buffer;
size_t buffer_size;
unsigned int is_parsed;
} HTTP_header_t;
HTTP_header_t* http_new_header(void);
void http_free( HTTP_header_t *http_hdr );
int http_response_append( HTTP_header_t *http_hdr, char *data, int length );
int http_response_parse( HTTP_header_t *http_hdr );
int http_is_header_entire( HTTP_header_t *http_hdr );
char* http_build_request( HTTP_header_t *http_hdr );
char* http_get_field( HTTP_header_t *http_hdr, const char *field_name );
char* http_get_next_field( HTTP_header_t *http_hdr );
void http_set_field( HTTP_header_t *http_hdr, const char *field_name );
void http_set_method( HTTP_header_t *http_hdr, const char *method );
void http_set_uri( HTTP_header_t *http_hdr, const char *uri );
int http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password );
int http_add_basic_proxy_authentication( HTTP_header_t *http_hdr, const char *username, const char *password );
void http_debug_hdr( HTTP_header_t *http_hdr );
#endif /* MPLAYER_HTTP_H */

View File

@ -1,455 +0,0 @@
/*
* Network layer for MPlayer
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include "config.h"
#include "core/options.h"
#include "core/mp_msg.h"
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "stream.h"
#include "demux/demux.h"
#include "core/mp_common.h"
#include "network.h"
#include "tcp.h"
#include "http.h"
#include "cookies.h"
#include "url.h"
/* IPv6 options */
int network_ipv4_only_proxy = 0;
const mime_struct_t mime_type_table[] = {
// MP3 streaming, some MP3 streaming server answer with audio/mpeg
{ "audio/mpeg", DEMUXER_TYPE_LAVF },
// 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-wmv", DEMUXER_TYPE_ASF },
{ "video/x-ms-wma", DEMUXER_TYPE_ASF },
{ "application/x-mms-framed", DEMUXER_TYPE_ASF },
{ "application/vnd.ms.wms-hdr.asfv1", DEMUXER_TYPE_ASF },
// Playlists
{ "video/x-ms-wmx", DEMUXER_TYPE_PLAYLIST },
{ "video/x-ms-wvx", 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 },
{ NULL, DEMUXER_TYPE_UNKNOWN},
};
streaming_ctrl_t *
streaming_ctrl_new(void) {
streaming_ctrl_t *streaming_ctrl = calloc(1, sizeof(*streaming_ctrl));
if( streaming_ctrl==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return NULL;
}
return streaming_ctrl;
}
void
streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) {
if( streaming_ctrl==NULL ) return;
if( streaming_ctrl->url ) url_free( streaming_ctrl->url );
free(streaming_ctrl->buffer);
free(streaming_ctrl->data);
free(streaming_ctrl);
}
URL_t*
check4proxies( const URL_t *url ) {
URL_t *url_out = NULL;
if( url==NULL ) return NULL;
url_out = url_new( url->url );
if( !strcasecmp(url->protocol, "mp_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, "mp_http") ) {
char *proxy;
proxy = getenv("http_proxy");
if( proxy!=NULL ) {
// We got a proxy, build the URL to use it
char *new_url;
URL_t *tmp_url;
URL_t *proxy_url = url_new( proxy );
if( proxy_url==NULL ) {
mp_tmsg(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_tmsg(MSGT_NETWORK,MSGL_WARN,
"Could not resolve remote hostname for AF_INET. Trying without proxy.\n");
url_free(proxy_url);
return url_out;
}
#endif
mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: %s\n", proxy_url->url );
new_url = get_http_proxy_url(proxy_url, url->url);
if( new_url==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
url_free(proxy_url);
return url_out;
}
tmp_url = url_new( new_url );
if( tmp_url==NULL ) {
free( new_url );
url_free( proxy_url );
return url_out;
}
url_free( url_out );
url_out = tmp_url;
free( new_url );
url_free( proxy_url );
}
}
return url_out;
}
URL_t *url_new_with_proxy(const char *urlstr)
{
URL_t *url = url_new(urlstr);
URL_t *url_with_proxy = check4proxies(url);
url_free(url);
return url_with_proxy;
}
int
http_send_request( URL_t *url, int64_t pos ) {
HTTP_header_t *http_hdr;
URL_t *server_url;
char str[256];
int fd = -1;
int ret;
int proxy = 0; // Boolean
http_hdr = http_new_header();
if( !strcasecmp(url->protocol, "mp_http_proxy") ) {
proxy = 1;
if (!strncasecmp(url->file, "/mp_", 3))
server_url = url_new( (url->file)+4 );
else
server_url = url_new( (url->file)+1 );
if (!server_url) {
mp_msg(MSGT_NETWORK, MSGL_ERR, "Invalid URL '%s' to proxify\n", url->file+1);
goto err_out;
}
http_set_uri( http_hdr, server_url->noauth_url );
} else {
server_url = url;
http_set_uri( http_hdr, server_url->file );
}
if (server_url->port && server_url->port != 80)
snprintf(str, sizeof(str), "Host: %s:%d", server_url->hostname, server_url->port );
else
snprintf(str, sizeof(str), "Host: %s", server_url->hostname );
http_set_field( http_hdr, str);
if (network_useragent)
snprintf(str, sizeof(str), "User-Agent: %s", network_useragent);
else
snprintf(str, sizeof(str), "User-Agent: %s", mplayer_version);
http_set_field(http_hdr, str);
if (network_referrer) {
char *referrer = NULL;
size_t len = strlen(network_referrer) + 10;
// Check len to ensure we don't do something really bad in case of an overflow
if (len > 10)
referrer = malloc(len);
if (referrer == NULL) {
mp_tmsg(MSGT_NETWORK, MSGL_FATAL, "Memory allocation failed.\n");
} else {
snprintf(referrer, len, "Referer: %s", network_referrer);
http_set_field(http_hdr, referrer);
free(referrer);
}
}
if( strcasecmp(url->protocol, "noicyx") )
http_set_field(http_hdr, "Icy-MetaData: 1");
if(pos>0) {
// Extend http_send_request with possibility to do partial content retrieval
snprintf(str, sizeof(str), "Range: bytes=%"PRId64"-", (int64_t)pos);
http_set_field(http_hdr, str);
}
if (network_cookies_enabled) cookies_set( http_hdr, server_url->hostname, server_url->url );
if (network_http_header_fields) {
int i=0;
while (network_http_header_fields[i])
http_set_field(http_hdr, network_http_header_fields[i++]);
}
http_set_field( http_hdr, "Connection: close");
if (proxy)
http_add_basic_proxy_authentication(http_hdr, url->username, url->password);
http_add_basic_authentication(http_hdr, server_url->username, server_url->password);
if( http_build_request( http_hdr )==NULL ) {
goto err_out;
}
if( proxy ) {
if( url->port==0 ) url->port = 8080; // Default port for the proxy server
fd = connect2Server( url->hostname, url->port,1 );
url_free( server_url );
server_url = NULL;
} else {
if( server_url->port==0 ) server_url->port = 80; // Default port for the web server
fd = connect2Server( server_url->hostname, server_url->port,1 );
}
if( fd<0 ) {
goto err_out;
}
mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request: [%s]\n", http_hdr->buffer );
ret = send( fd, http_hdr->buffer, http_hdr->buffer_size, DEFAULT_SEND_FLAGS );
if( ret!=(int)http_hdr->buffer_size ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Error while sending HTTP request: Didn't send all the request.\n");
goto err_out;
}
http_free( http_hdr );
return fd;
err_out:
if (fd > 0) closesocket(fd);
http_free(http_hdr);
if (proxy && server_url)
url_free(server_url);
return -1;
}
HTTP_header_t *
http_read_response( int fd ) {
HTTP_header_t *http_hdr;
char response[BUFFER_SIZE];
int i;
http_hdr = http_new_header();
if( http_hdr==NULL ) {
return NULL;
}
do {
i = recv( fd, response, BUFFER_SIZE, 0 );
if( i<0 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Read failed.\n");
http_free( http_hdr );
return NULL;
}
if( i==0 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"http_read_response read 0 (i.e. EOF).\n");
http_free( http_hdr );
return NULL;
}
http_response_append( http_hdr, response, i );
} while( !http_is_header_entire( http_hdr ) );
if (http_response_parse( http_hdr ) < 0) {
http_free( http_hdr );
return NULL;
}
return http_hdr;
}
int
http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry) {
char *aut;
#define MPDEMUX_NW_AuthFailed _(\
"Authentication failed. Please use the -user and -passwd options to provide your\n"\
"username/password for a list of URLs, or form an URL like:\n"\
"http://username:password@hostname/file\n")
if( *auth_retry==1 ) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,MPDEMUX_NW_AuthFailed);
return -1;
}
if( *auth_retry>0 ) {
free(url->username);
url->username = NULL;
free(url->password);
url->password = NULL;
}
aut = http_get_field(http_hdr, "WWW-Authenticate");
if( aut!=NULL ) {
char *aut_space;
aut_space = strstr(aut, "realm=");
if( aut_space!=NULL ) aut_space += 6;
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"Authentication required for %s\n", aut_space);
} else {
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"Authentication required.\n");
}
if( network_username ) {
url->username = strdup(network_username);
if( url->username==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return -1;
}
} else {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,MPDEMUX_NW_AuthFailed);
return -1;
}
if( network_password ) {
url->password = strdup(network_password);
if( url->password==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return -1;
}
} else {
mp_tmsg(MSGT_NETWORK,MSGL_INFO,"No password provided, trying blank password.\n");
}
(*auth_retry)++;
return 0;
}
int
http_seek( stream_t *stream, int64_t pos ) {
HTTP_header_t *http_hdr = NULL;
int fd;
if( stream==NULL ) return 0;
if( stream->fd>0 ) closesocket(stream->fd); // need to reconnect to seek in http-stream
fd = http_send_request( stream->streaming_ctrl->url, pos );
if( fd<0 ) return 0;
http_hdr = http_read_response( fd );
if( http_hdr==NULL ) return 0;
if( mp_msg_test(MSGT_NETWORK,MSGL_V) )
http_debug_hdr( http_hdr );
switch( http_hdr->status_code ) {
case 200:
case 206: // OK
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") );
mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") );
if( http_hdr->body_size>0 ) {
if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) {
http_free( http_hdr );
return -1;
}
}
break;
default:
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Server returns %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
closesocket( fd );
fd = -1;
}
stream->fd = fd;
if( http_hdr ) {
http_free( http_hdr );
stream->streaming_ctrl->data = NULL;
}
stream->pos=pos;
return 1;
}
int
streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size) {
//printf("streaming_bufferize\n");
streaming_ctrl->buffer = malloc(size);
if( streaming_ctrl->buffer==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
return -1;
}
memcpy( streaming_ctrl->buffer, buffer, size );
streaming_ctrl->buffer_size = size;
return size;
}
int
nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) {
int len=0;
//printf("nop_streaming_read\n");
if( stream_ctrl->buffer_size!=0 ) {
int buffer_len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos;
//printf("%d bytes in buffer\n", stream_ctrl->buffer_size);
len = (size<buffer_len)?size:buffer_len;
memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len );
stream_ctrl->buffer_pos += len;
//printf("buffer_pos = %d\n", stream_ctrl->buffer_pos );
if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) {
free( stream_ctrl->buffer );
stream_ctrl->buffer = NULL;
stream_ctrl->buffer_size = 0;
stream_ctrl->buffer_pos = 0;
//printf("buffer cleaned\n");
}
//printf("read %d bytes from buffer\n", len );
}
if( len<size ) {
int ret;
ret = recv( fd, buffer+len, size-len, 0 );
if( ret<0 ) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : %s\n",strerror(errno));
ret = 0;
} else if (ret == 0)
stream_ctrl->status = streaming_stopped_e;
len += ret;
//printf("read %d bytes from network\n", len );
}
return len;
}
int
nop_streaming_seek( int fd, int64_t pos, streaming_ctrl_t *stream_ctrl ) {
return -1;
}

View File

@ -1,84 +0,0 @@
/*
* Network layer for MPlayer
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_NETWORK_H
#define MPLAYER_NETWORK_H
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include "config.h"
#if !HAVE_WINSOCK2_H
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
#include "stream.h"
#include "url.h"
#include "http.h"
#ifdef MSG_NOSIGNAL
#define DEFAULT_SEND_FLAGS MSG_NOSIGNAL
#else
#define DEFAULT_SEND_FLAGS 0
#endif
#if !HAVE_CLOSESOCKET
#define closesocket close
#endif
#if !HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
#define BUFFER_SIZE 2048
typedef struct {
const char *mime_type;
int demuxer_type;
} mime_struct_t;
extern const mime_struct_t mime_type_table[];
extern int network_prefer_ipv4;
extern int network_ipv4_only_proxy;
extern int reuse_socket;
streaming_ctrl_t *streaming_ctrl_new(void);
int streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size);
int nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl );
int nop_streaming_seek( int fd, int64_t pos, streaming_ctrl_t *stream_ctrl );
void streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl );
int http_send_request(URL_t *url, int64_t pos);
HTTP_header_t *http_read_response(int fd);
int http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry);
URL_t* check4proxies(const URL_t *url);
URL_t *url_new_with_proxy(const char *urlstr);
int http_seek(stream_t *stream, int64_t pos);
#endif /* MPLAYER_NETWORK_H */

View File

@ -37,14 +37,9 @@
#include "config.h"
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#include "core/bstr.h"
#include "core/mp_msg.h"
#include "osdep/timer.h"
#include "network.h"
#include "stream.h"
#include "demux/demux.h"
@ -96,12 +91,6 @@ static const stream_info_t *const auto_open_streams[] = {
#endif
&stream_info_ffmpeg, // use for rstp:// before http fallback
&stream_info_avdevice,
#ifdef CONFIG_NETWORKING
&stream_info_http1,
&stream_info_asf,
&stream_info_udp,
&stream_info_http2,
#endif
#ifdef CONFIG_DVBIN
&stream_info_dvb,
#endif
@ -174,16 +163,6 @@ static stream_t *open_stream_plugin(const stream_info_t *sinfo,
s->flags |= mode;
*ret = sinfo->open(s, mode, arg, file_format);
if ((*ret) != STREAM_OK) {
#ifdef CONFIG_NETWORKING
if (*ret == STREAM_REDIRECTED && redirected_url) {
if (s->streaming_ctrl && s->streaming_ctrl->url
&& s->streaming_ctrl->url->url)
*redirected_url = strdup(s->streaming_ctrl->url->url);
else
*redirected_url = NULL;
}
streaming_ctrl_free(s->streaming_ctrl);
#endif
free(s->url);
talloc_free(s);
return NULL;
@ -363,18 +342,10 @@ static int stream_read_unbuffered(stream_t *s, void *buf, int len)
// we will retry even if we already reached EOF previously.
switch (s->type) {
case STREAMTYPE_STREAM:
if (s->streaming_ctrl != NULL && s->streaming_ctrl->streaming_read) {
len = s->streaming_ctrl->streaming_read(s->fd, buf, len,
s->streaming_ctrl);
if (s->streaming_ctrl->status == streaming_stopped_e &&
(!s->end_pos || s->pos == s->end_pos))
s->eof = 1;
} else {
if (s->fill_buffer)
len = s->fill_buffer(s, buf, len);
else
len = read(s->fd, buf, len);
}
if (s->fill_buffer)
len = s->fill_buffer(s, buf, len);
else
len = read(s->fd, buf, len);
break;
default:
@ -508,25 +479,6 @@ static int stream_seek_unbuffered(stream_t *s, int64_t newpos)
// Some streaming protocol allow to seek backward and forward
// A function call that return -1 can tell that the protocol
// doesn't support seeking.
#ifdef CONFIG_NETWORKING
if (s->seek) {
if (!s->seek(s, newpos)) {
mp_tmsg(MSGT_STREAM, MSGL_ERR, "Seek failed\n");
return 0;
}
break;
}
if (s->streaming_ctrl != NULL &&
s->streaming_ctrl->streaming_seek) {
if (s->streaming_ctrl->streaming_seek(s->fd, newpos,
s->streaming_ctrl) < 0) {
mp_tmsg(MSGT_STREAM, MSGL_INFO, "Stream not seekable!\n");
return 1;
}
break;
}
#endif
if (newpos < s->pos) {
mp_tmsg(MSGT_STREAM, MSGL_INFO,
"Cannot seek backward in linear streams!\n");
@ -675,14 +627,6 @@ static stream_t *new_stream(size_t min_size)
stream_t *s = talloc_size(NULL, sizeof(stream_t) + min_size);
memset(s, 0, sizeof(stream_t));
#if HAVE_WINSOCK2_H
{
WSADATA wsdata;
int temp = WSAStartup(0x0202, &wsdata); // there might be a better place for this (-> later)
mp_msg(MSGT_STREAM, MSGL_V, "WINSOCK2 init: %i\n", temp);
}
#endif
s->fd = -2;
s->type = -2;
return s;
@ -695,18 +639,8 @@ void free_stream(stream_t *s)
if (s->close)
s->close(s);
if (s->fd > 0) {
/* on unix we define closesocket to close
on windows however we have to distinguish between
network socket and file */
if (s->url && strstr(s->url, "://"))
closesocket(s->fd);
else
close(s->fd);
close(s->fd);
}
#if HAVE_WINSOCK2_H
mp_msg(MSGT_STREAM, MSGL_V, "WINSOCK2 uninit\n");
WSACleanup(); // there might be a better place for this (-> later)
#endif
free(s->url);
if (s->uncached_stream)
free_stream(s->uncached_stream);

View File

@ -21,7 +21,6 @@
#include "config.h"
#include "core/mp_msg.h"
#include "url.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
@ -116,29 +115,6 @@ struct stream_dvd_info_req {
int num_subs;
};
typedef enum {
streaming_stopped_e,
streaming_playing_e
} streaming_status;
// All this is for legacy http streams (and other things using tcp/udp)
typedef struct streaming_control {
URL_t *url;
streaming_status status;
char *buffer;
unsigned int buffer_size;
unsigned int buffer_pos;
unsigned int bandwidth; // The downstream available
int (*streaming_read)(int fd, char *buffer, int buffer_size,
struct streaming_control *stream_ctrl);
int (*streaming_seek)(int fd, int64_t pos,
struct streaming_control *stream_ctrl);
void *data;
// hacks for asf
int *audio_id_ptr;
int *video_id_ptr;
} streaming_ctrl_t;
struct stream;
typedef struct stream_info_st {
const char *info;
@ -185,7 +161,6 @@ typedef struct stream {
char *mime_type; // when HTTP streaming is used
char *lavf_type; // name of expected demuxer type for lavf
struct MPOpts *opts;
streaming_ctrl_t *streaming_ctrl;
FILE *capture_file;
char *capture_filename;
@ -196,10 +171,6 @@ typedef struct stream {
unsigned char buffer[];
} stream_t;
#ifdef CONFIG_NETWORKING
#include "network.h"
#endif
int stream_fill_buffer(stream_t *s);
void stream_set_capture_file(stream_t *s, const char *filename);

View File

@ -340,11 +340,10 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
int offset = p->toc_offset;
cdrom_drive_t *cdd = NULL;
cdda_priv *priv;
cd_info_t *cd_info, *cddb_info = NULL;
cd_info_t *cd_info;
unsigned int audiolen = 0;
int last_track;
int i;
char *xmcd_file = NULL;
if (m != STREAM_READ) {
m_struct_free(&stream_opts, opts);
@ -358,18 +357,6 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
p->device = talloc_strdup(NULL, DEFAULT_CDROM_DEVICE);
}
#ifdef CONFIG_CDDB
// cdd_identify returns -1 if it cannot read the TOC,
// in which case there is no point in calling cddb_resolve
if (cdd_identify(p->device) >= 0 && strncmp(st->url, "cddb", 4) == 0) {
i = cddb_resolve(p->device, &xmcd_file);
if (i == 0) {
cddb_info = cddb_parse_xmcd(xmcd_file);
free(xmcd_file);
}
}
#endif
#if defined(__NetBSD__)
cdd = cdda_identify_scsi(p->device, p->device, 0, NULL);
#else
@ -379,7 +366,6 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
if (!cdd) {
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Can't open CDDA device.\n");
m_struct_free(&stream_opts, opts);
free(cddb_info);
return STREAM_ERROR;
}
@ -392,7 +378,6 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Can't open disc.\n");
cdda_close(cdd);
m_struct_free(&stream_opts, opts);
free(cddb_info);
return STREAM_ERROR;
}
@ -455,7 +440,6 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
free(priv);
cd_info_free(cd_info);
m_struct_free(&stream_opts, opts);
free(cddb_info);
return STREAM_ERROR;
}
@ -484,14 +468,6 @@ static int open_cdda(stream_t *st, int m, void *opts, int *file_format)
paranoia_seek(priv->cdp, priv->start_sector, SEEK_SET);
priv->sector = priv->start_sector;
#ifdef CONFIG_CDDB
if (cddb_info) {
cd_info_free(cd_info);
priv->cd_info = cddb_info;
cd_info_debug(cddb_info);
}
#endif
st->priv = priv;
st->start_pos = priv->start_sector * CDIO_CD_FRAMESIZE_RAW;
st->end_pos = (priv->end_sector + 1) * CDIO_CD_FRAMESIZE_RAW;
@ -518,11 +494,7 @@ const stream_info_t stream_info_cdda = {
"Albeu",
"",
open_cdda,
{"cdda",
#ifdef CONFIG_CDDB
"cddb",
#endif
NULL },
{"cdda", NULL },
&stream_opts,
.opts_url = 1,
};

View File

@ -1,902 +0,0 @@
/*
* CDDB HTTP protocol
*
* Copyright (C) 2002 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* Implementation follow the freedb.howto1.06.txt specification
* from http://freedb.freedb.org
*
* discid computation by Jeremy D. Zawodny
* Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include "osdep/io.h"
#if defined(__MINGW32__) || defined(__CYGWIN__)
#include <windows.h>
#if HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#else
#include <netdb.h>
#include <sys/ioctl.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "core/mp_msg.h"
#include "core/path.h"
#if defined(__linux__)
#include <linux/cdrom.h>
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#include <sys/cdio.h>
#elif defined(__MINGW32__) || defined(__CYGWIN__)
#include <ntddcdrm.h>
#elif defined(__bsdi__)
#include <dvd.h>
#elif defined(__APPLE__) || defined(__DARWIN__)
#include <IOKit/storage/IOCDTypes.h>
#include <IOKit/storage/IOCDMediaBSDClient.h>
#include "compat/mpbswap.h"
#endif
#include "cdd.h"
#include "core/mp_common.h"
#include "stream.h"
#include "network.h"
#include "libavutil/common.h"
#define DEFAULT_FREEDB_SERVER "freedb.freedb.org"
#define DEFAULT_CACHE_DIR "/.cddb/"
typedef struct {
char cddb_hello[1024];
unsigned long disc_id;
unsigned int tracks;
char *cache_dir;
char *freedb_server;
int freedb_proto_level;
int anonymous;
char category[100];
char *xmcd_file;
size_t xmcd_file_size;
void *user_data;
} cddb_data_t;
typedef struct {
unsigned int min, sec, frame;
} cd_toc_t;
static cd_toc_t cdtoc[100];
static int cdtoc_last_track;
static int read_toc(const char *dev)
{
int first = 0, last = -1;
int i;
#if defined(__MINGW32__) || defined(__CYGWIN__)
HANDLE drive;
DWORD r;
CDROM_TOC toc;
char device[10];
snprintf(device, sizeof(device), "\\\\.\\%s", dev);
drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, 0);
if (!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc,
sizeof(CDROM_TOC), &r, 0)) {
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to read TOC.\n");
return 0;
}
first = toc.FirstTrack - 1; last = toc.LastTrack;
for (i = first; i <= last; i++) {
cdtoc[i].min = toc.TrackData[i].Address[1];
cdtoc[i].sec = toc.TrackData[i].Address[2];
cdtoc[i].frame = toc.TrackData[i].Address[3];
}
CloseHandle(drive);
#else
int drive;
drive = open(dev, O_RDONLY | O_NONBLOCK);
if (drive < 0) {
return drive;
}
#if defined(__linux__) || defined(__bsdi__)
{
struct cdrom_tochdr tochdr;
ioctl(drive, CDROMREADTOCHDR, &tochdr);
first = tochdr.cdth_trk0 - 1; last = tochdr.cdth_trk1;
}
for (i = first; i <= last; i++) {
struct cdrom_tocentry tocentry;
tocentry.cdte_track = (i == last) ? 0xAA : i + 1;
tocentry.cdte_format = CDROM_MSF;
ioctl(drive, CDROMREADTOCENTRY, &tocentry);
cdtoc[i].min = tocentry.cdte_addr.msf.minute;
cdtoc[i].sec = tocentry.cdte_addr.msf.second;
cdtoc[i].frame = tocentry.cdte_addr.msf.frame;
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
{
struct ioc_toc_header tochdr;
ioctl(drive, CDIOREADTOCHEADER, &tochdr);
first = tochdr.starting_track - 1; last = tochdr.ending_track;
}
for (i = first; i <= last; i++) {
struct ioc_read_toc_single_entry tocentry;
tocentry.track = (i == last) ? 0xAA : i + 1;
tocentry.address_format = CD_MSF_FORMAT;
ioctl(drive, CDIOREADTOCENTRY, &tocentry);
cdtoc[i].min = tocentry.entry.addr.msf.minute;
cdtoc[i].sec = tocentry.entry.addr.msf.second;
cdtoc[i].frame = tocentry.entry.addr.msf.frame;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
{
struct ioc_toc_header tochdr;
ioctl(drive, CDIOREADTOCHEADER, &tochdr);
first = tochdr.starting_track - 1; last = tochdr.ending_track;
}
for (i = first; i <= last; i++) {
struct ioc_read_toc_entry tocentry;
struct cd_toc_entry toc_buffer;
tocentry.starting_track = (i == last) ? 0xAA : i + 1;
tocentry.address_format = CD_MSF_FORMAT;
tocentry.data = &toc_buffer;
tocentry.data_len = sizeof(toc_buffer);
ioctl(drive, CDIOREADTOCENTRYS, &tocentry);
cdtoc[i].min = toc_buffer.addr.msf.minute;
cdtoc[i].sec = toc_buffer.addr.msf.second;
cdtoc[i].frame = toc_buffer.addr.msf.frame;
}
#elif defined(__APPLE__) || defined(__DARWIN__)
{
dk_cd_read_toc_t tochdr;
uint8_t buf[4];
uint8_t buf2[100 * sizeof(CDTOCDescriptor) + sizeof(CDTOC)];
memset(&tochdr, 0, sizeof(tochdr));
tochdr.bufferLength = sizeof(buf);
tochdr.buffer = &buf;
if (!ioctl(drive, DKIOCCDREADTOC, &tochdr)
&& tochdr.bufferLength == sizeof(buf)) {
first = buf[2] - 1;
last = buf[3];
}
if (last >= 0) {
memset(&tochdr, 0, sizeof(tochdr));
tochdr.bufferLength = sizeof(buf2);
tochdr.buffer = &buf2;
tochdr.format = kCDTOCFormatTOC;
if (ioctl(drive, DKIOCCDREADTOC, &tochdr)
|| tochdr.bufferLength < sizeof(CDTOC))
last = -1;
}
if (last >= 0) {
CDTOC *cdToc = (CDTOC *)buf2;
CDTrackInfo lastTrack;
dk_cd_read_track_info_t trackInfoParams;
for (i = first; i < last; ++i) {
CDMSF msf = CDConvertTrackNumberToMSF(i + 1, cdToc);
cdtoc[i].min = msf.minute;
cdtoc[i].sec = msf.second;
cdtoc[i].frame = msf.frame;
}
memset(&trackInfoParams, 0, sizeof(trackInfoParams));
trackInfoParams.addressType = kCDTrackInfoAddressTypeTrackNumber;
trackInfoParams.bufferLength = sizeof(lastTrack);
trackInfoParams.address = last;
trackInfoParams.buffer = &lastTrack;
if (!ioctl(drive, DKIOCCDREADTRACKINFO, &trackInfoParams)) {
CDMSF msf = CDConvertLBAToMSF(be2me_32(lastTrack.trackStartAddress)
+ be2me_32(lastTrack.trackSize));
cdtoc[last].min = msf.minute;
cdtoc[last].sec = msf.second;
cdtoc[last].frame = msf.frame;
}
}
}
#endif
close(drive);
#endif
for (i = first; i <= last; i++)
cdtoc[i].frame += (cdtoc[i].min * 60 + cdtoc[i].sec) * 75;
return last;
}
/**
\brief Reads TOC from CD in the given device and prints the number of tracks
and the length of each track in minute:second:frame format.
\param *dev the device to analyse
\return if the command line -identify is given, returns the last track of
the TOC or -1 if the TOC can't be read,
otherwise just returns 0 and let cddb_resolve the TOC
*/
int cdd_identify(const char *dev)
{
cdtoc_last_track = 0;
if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) {
int i, min, sec, frame;
cdtoc_last_track = read_toc(dev);
if (cdtoc_last_track < 0) {
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s device.\n", dev);
return -1;
}
mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_CDDA_TRACKS=%d\n", cdtoc_last_track);
for (i = 1; i <= cdtoc_last_track; i++) {
frame = cdtoc[i].frame - cdtoc[i-1].frame;
sec = frame / 75;
frame -= sec * 75;
min = sec / 60;
sec -= min * 60;
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_CDDA_TRACK_%d_MSF=%02d:%02d:%02d\n", i, min, sec, frame);
}
}
return cdtoc_last_track;
}
static unsigned int cddb_sum(int n)
{
unsigned int ret;
ret = 0;
while (n > 0) {
ret += (n % 10);
n /= 10;
}
return ret;
}
static unsigned long cddb_discid(int tot_trks)
{
unsigned int i, t = 0, n = 0;
i = 0;
while (i < (unsigned int)tot_trks) {
n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
i++;
}
t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
((cdtoc[0].min * 60) + cdtoc[0].sec);
return (n % 0xff) << 24 | t << 8 | tot_trks;
}
static int cddb_http_request(char *command,
int (*reply_parser)(HTTP_header_t*, cddb_data_t*),
cddb_data_t *cddb_data)
{
char request[4096];
int fd, ret = 0;
URL_t *url;
HTTP_header_t *http_hdr;
if (reply_parser == NULL || command == NULL || cddb_data == NULL)
return -1;
snprintf(request, sizeof(request), "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d",
cddb_data->freedb_server, command, cddb_data->cddb_hello,
cddb_data->freedb_proto_level);
mp_msg(MSGT_OPEN, MSGL_INFO,"Request[%s]\n", request);
url = url_new(request);
if (url == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "not a valid URL\n");
return -1;
}
fd = http_send_request(url,0);
if (fd < 0) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Failed to send the HTTP request.\n");
return -1;
}
http_hdr = http_read_response(fd);
if (http_hdr == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Failed to read the HTTP response.\n");
return -1;
}
http_debug_hdr(http_hdr);
mp_msg(MSGT_OPEN, MSGL_INFO,"body=[%s]\n", http_hdr->body);
switch (http_hdr->status_code) {
case 200:
ret = reply_parser(http_hdr, cddb_data);
break;
case 400:
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Not Found.\n");
break;
default:
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "unknown error code\n");
}
http_free(http_hdr);
url_free(url);
return ret;
}
static int cddb_read_cache(cddb_data_t *cddb_data)
{
char file_name[100];
struct stat stats;
int file_fd, ret;
size_t file_size;
if (cddb_data == NULL || cddb_data->cache_dir == NULL)
return -1;
snprintf(file_name, sizeof(file_name), "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
file_fd = open(file_name, O_RDONLY | O_BINARY);
if (file_fd < 0) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "No cache found.\n");
return -1;
}
ret = fstat(file_fd, &stats);
if (ret < 0) {
perror("fstat");
file_size = 4096;
} else {
file_size = stats.st_size < UINT_MAX ? stats.st_size : UINT_MAX - 1;
}
cddb_data->xmcd_file = malloc(file_size + 1);
if (cddb_data->xmcd_file == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Memory allocation failed.\n");
close(file_fd);
return -1;
}
cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size);
if (cddb_data->xmcd_file_size != file_size) {
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "Not all the xmcd file has been read.\n");
close(file_fd);
return -1;
}
cddb_data->xmcd_file[cddb_data->xmcd_file_size] = 0;
close(file_fd);
return 0;
}
static int cddb_write_cache(cddb_data_t *cddb_data)
{
// We have the file, save it for cache.
char file_name[100];
int file_fd, ret;
int wrote = 0;
if (cddb_data == NULL || cddb_data->cache_dir == NULL)
return -1;
// Check if the CDDB cache dir exist
if (!mp_path_exists(cddb_data->cache_dir)) {
// Directory not present, create it.
ret = mkdir(cddb_data->cache_dir, 0755);
#ifdef __MINGW32__
if (ret < 0 && errno != EEXIST) {
#else
if (ret < 0) {
#endif
perror("mkdir");
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Failed to create directory %s.\n",
cddb_data->cache_dir);
return -1;
}
}
snprintf(file_name, sizeof(file_name), "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id);
file_fd = creat(file_name, S_IRUSR | S_IWUSR);
if (file_fd < 0) {
perror("create");
return -1;
}
wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size);
if (wrote < 0) {
perror("write");
close(file_fd);
return -1;
}
if ((unsigned int) wrote != cddb_data->xmcd_file_size) {
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "Not all of the xmcd file has been written.\n");
close(file_fd);
return -1;
}
close(file_fd);
return 0;
}
static int cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data)
{
unsigned long disc_id;
char category[100];
char *ptr = NULL, *ptr2 = NULL;
int ret, status;
if (http_hdr == NULL || cddb_data == NULL)
return -1;
ret = sscanf(http_hdr->body, "%d ", &status);
if (ret != 1) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
switch (status) {
case 210:
ret = sscanf(http_hdr->body, "%d %99s %08lx", &status,
category, &disc_id);
if (ret != 3) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
// Check if it's a xmcd database file
ptr = strstr(http_hdr->body, "# xmcd");
if (ptr == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR,
"Invalid xmcd database file returned.\n");
return -1;
}
ptr = strdup(ptr);
// Ok found the beginning of the file
// look for the end
ptr2 = strstr(ptr, "\n.\r\n");
if (!ptr2)
ptr2 = strstr(ptr, "\n.\n");
if (ptr2) {
ptr2++;
} else {
mp_msg(MSGT_DEMUX, MSGL_FIXME, "Unable to find '.'\n");
ptr2 = ptr + strlen(ptr); //return -1;
}
// Ok found the end
// do a sanity check
if (http_hdr->body_size < (unsigned int)(ptr2 - ptr)) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "unexpected FIXME\n");
return -1;
}
cddb_data->xmcd_file = ptr;
cddb_data->xmcd_file_size = ptr2 - ptr;
cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0';
return cddb_write_cache(cddb_data);
default:
mp_tmsg(MSGT_DEMUX, MSGL_FIXME, "unhandled code\n");
}
return 0;
}
static int cddb_request_titles(cddb_data_t *cddb_data)
{
char command[1024];
snprintf(command, sizeof(command), "cddb+read+%s+%08lx",
cddb_data->category, cddb_data->disc_id);
return cddb_http_request(command, cddb_read_parse, cddb_data);
}
static int cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data)
{
char album_title[100];
char *ptr = NULL;
int ret;
ptr = strstr(http_hdr->body, "\n");
if (ptr == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Unable to find end of line.\n");
return -1;
}
ptr++;
// We have a list of exact/inexact matches, so which one do we use?
// So let's take the first one.
ret = sscanf(ptr, "%99s %08lx %99s", cddb_data->category,
&(cddb_data->disc_id), album_title);
if (ret != 3) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
ptr = strstr(http_hdr->body, album_title);
if (ptr != NULL) {
char *ptr2;
int len;
ptr2 = strstr(ptr, "\n");
if (ptr2 == NULL) {
len = (http_hdr->body_size)-(ptr-(http_hdr->body));
} else {
len = ptr2-ptr+1;
}
len = FFMIN(sizeof(album_title) - 1, len);
strncpy(album_title, ptr, len);
album_title[len]='\0';
}
mp_tmsg(MSGT_DEMUX, MSGL_STATUS, "Parse OK, found: %s\n", album_title);
return 0;
}
static int cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data)
{
char album_title[100];
char *ptr = NULL;
int ret, status;
ret = sscanf(http_hdr->body, "%d ", &status);
if (ret != 1) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
switch (status) {
case 200:
// Found exact match
ret = sscanf(http_hdr->body, "%d %99s %08lx %99s", &status,
cddb_data->category, &(cddb_data->disc_id), album_title);
if (ret != 4) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
ptr = strstr(http_hdr->body, album_title);
if (ptr != NULL) {
char *ptr2;
int len;
ptr2 = strstr(ptr, "\n");
if (ptr2 == NULL) {
len = (http_hdr->body_size)-(ptr-(http_hdr->body));
} else {
len = ptr2-ptr+1;
}
len = FFMIN(sizeof(album_title) - 1, len);
strncpy(album_title, ptr, len);
album_title[len]='\0';
}
mp_tmsg(MSGT_DEMUX, MSGL_STATUS, "Parse OK, found: %s\n", album_title);
return cddb_request_titles(cddb_data);
case 202:
// No match found
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "Album not found.\n");
break;
case 210:
// Found exact matches, list follows
cddb_parse_matches_list(http_hdr, cddb_data);
return cddb_request_titles(cddb_data);
/*
body=[210 Found exact matches, list follows (until terminating `.')
misc c711930d Santana / Supernatural
rock c711930d Santana / Supernatural
blues c711930d Santana / Supernatural
.]
*/
case 211:
// Found inexact matches, list follows
cddb_parse_matches_list(http_hdr, cddb_data);
return cddb_request_titles(cddb_data);
case 500:
mp_tmsg(MSGT_DEMUX, MSGL_FIXME,
"Server returns: Command syntax error\n");
break;
default:
mp_tmsg(MSGT_DEMUX, MSGL_FIXME, "unhandled code\n");
}
return -1;
}
static int cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data)
{
int max;
int ret, status;
char *ptr;
ret = sscanf(http_hdr->body, "%d ", &status);
if (ret != 1) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
switch (status) {
case 210:
ptr = strstr(http_hdr->body, "max proto:");
if (ptr == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
ret = sscanf(ptr, "max proto: %d", &max);
if (ret != 1) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "parse error");
return -1;
}
cddb_data->freedb_proto_level = max;
return 0;
default:
mp_tmsg(MSGT_DEMUX, MSGL_FIXME, "unhandled code\n");
}
return -1;
}
static int cddb_get_proto_level(cddb_data_t *cddb_data)
{
return cddb_http_request("stat", cddb_proto_level_parse, cddb_data);
}
static void cddb_create_hello(cddb_data_t *cddb_data)
{
char host_name[51];
char *user_name;
if (cddb_data->anonymous) { // Default is anonymous
/* Note from Eduardo Pérez Ureta <eperez@it.uc3m.es> :
* We don't send current user/host name in hello to prevent spam.
* Software that sends this is considered spyware
* that most people don't like.
*/
user_name = "anonymous";
strcpy(host_name, "localhost");
} else {
if (gethostname(host_name, 50) < 0) {
strcpy(host_name, "localhost");
}
user_name = getenv("LOGNAME");
}
snprintf(cddb_data->cddb_hello, sizeof(cddb_data->cddb_hello),
"&hello=%s+%s+%s",
user_name, host_name, mplayer_version);
}
static int cddb_retrieve(cddb_data_t *cddb_data)
{
char offsets[1024], command[1024];
char *ptr;
unsigned int i, time_len;
int ret;
ptr = offsets;
for (i = 0; i < cddb_data->tracks ; i++) {
unsigned space = sizeof(offsets) - (ptr - offsets);
if (space < 40) break;
ptr += snprintf(ptr, space, "%d+", cdtoc[i].frame);
}
ptr[0] = 0;
time_len = (cdtoc[cddb_data->tracks].frame)/75;
cddb_data->freedb_server = DEFAULT_FREEDB_SERVER;
cddb_data->freedb_proto_level = 1;
cddb_data->xmcd_file = NULL;
cddb_create_hello(cddb_data);
if (cddb_get_proto_level(cddb_data) < 0) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Failed to get the protocol level.\n");
return -1;
}
snprintf(command, sizeof(command), "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id,
cddb_data->tracks, offsets, time_len);
ret = cddb_http_request(command, cddb_query_parse, cddb_data);
if (ret < 0)
return -1;
free(cddb_data->cache_dir);
return 0;
}
int cddb_resolve(const char *dev, char **xmcd_file)
{
char cddb_cache_dir[] = DEFAULT_CACHE_DIR;
char *home_dir = NULL;
cddb_data_t cddb_data;
void *talloc_ctx = talloc_new(NULL);
if (cdtoc_last_track <= 0) {
cdtoc_last_track = read_toc(dev);
if (cdtoc_last_track < 0) {
mp_tmsg(MSGT_OPEN, MSGL_ERR, "Failed to open %s device.\n", dev);
return -1;
}
}
cddb_data.tracks = cdtoc_last_track;
cddb_data.disc_id = cddb_discid(cddb_data.tracks);
cddb_data.anonymous = 1; // Don't send user info by default
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDB_DISCID=%08lx\n",
cddb_data.disc_id);
// Check if there is a CD in the drive
// FIXME: That's not really a good way to check
if (cddb_data.disc_id == 0) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "No CD in the drive.\n");
return -1;
}
home_dir = getenv("HOME");
#ifdef __MINGW32__
if (home_dir == NULL)
home_dir = getenv("USERPROFILE");
if (home_dir == NULL)
home_dir = getenv("HOMEPATH");
// Last resort, store the cddb cache in the mplayer directory
if (home_dir == NULL)
home_dir = (char *)talloc_steal(talloc_ctx,
mp_find_user_config_file(""));
#endif
if (home_dir == NULL) {
cddb_data.cache_dir = NULL;
} else {
unsigned len = strlen(home_dir) + strlen(cddb_cache_dir) + 1;
cddb_data.cache_dir = malloc(len);
if (cddb_data.cache_dir == NULL) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR, "Memory allocation failed.\n");
talloc_free(talloc_ctx);
return -1;
}
snprintf(cddb_data.cache_dir, len, "%s%s", home_dir, cddb_cache_dir);
}
talloc_free(talloc_ctx);
// Check for a cached file
if (cddb_read_cache(&cddb_data) < 0) {
// No Cache found
if (cddb_retrieve(&cddb_data) < 0) {
return -1;
}
}
if (cddb_data.xmcd_file != NULL) {
// printf("%s\n", cddb_data.xmcd_file);
*xmcd_file = cddb_data.xmcd_file;
return 0;
}
return -1;
}
/***************
* xmcd parser *
***************/
static char *xmcd_parse_dtitle(cd_info_t *cd_info, char *line)
{
char *ptr, *album;
ptr = strstr(line, "DTITLE=");
if (ptr != NULL) {
ptr += 7;
album = strstr(ptr, "/");
if (album == NULL)
return NULL;
cd_info->album = malloc(strlen(album + 2) + 1);
if (cd_info->album == NULL) {
return NULL;
}
strcpy(cd_info->album, album + 2);
album--;
album[0] = '\0';
cd_info->artist = malloc(strlen(ptr) + 1);
if (cd_info->artist == NULL) {
return NULL;
}
strcpy(cd_info->artist, ptr);
}
return ptr;
}
static char *xmcd_parse_dgenre(cd_info_t *cd_info, char *line)
{
char *ptr;
ptr = strstr(line, "DGENRE=");
if (ptr != NULL) {
ptr += 7;
cd_info->genre = malloc(strlen(ptr)+1);
if (cd_info->genre == NULL) {
return NULL;
}
strcpy(cd_info->genre, ptr);
}
return ptr;
}
static char *xmcd_parse_ttitle(cd_info_t *cd_info, char *line)
{
unsigned int track_nb;
unsigned long sec, off;
char *ptr;
ptr = strstr(line, "TTITLE");
if (ptr != NULL) {
ptr += 6;
// Here we point to the track number
track_nb = atoi(ptr);
ptr = strstr(ptr, "=");
if (ptr == NULL)
return NULL;
ptr++;
sec = cdtoc[track_nb].frame;
off = cdtoc[track_nb + 1].frame - sec + 1;
cd_info_add_track(cd_info, ptr, track_nb + 1,
(unsigned int) (off / (60 * 75)),
(unsigned int) ((off / 75) % 60),
(unsigned int) (off % 75),
sec, off);
}
return ptr;
}
cd_info_t *cddb_parse_xmcd(char *xmcd_file)
{
cd_info_t *cd_info = NULL;
int length, pos = 0;
char *ptr, *ptr2;
if (xmcd_file == NULL)
return NULL;
cd_info = cd_info_new();
if (cd_info == NULL) {
return NULL;
}
length = strlen(xmcd_file);
ptr = xmcd_file;
while (ptr != NULL && pos < length) {
// Read a line
ptr2 = ptr;
while(ptr2[0] != '\0' && ptr2[0] != '\r' && ptr2[0] != '\n')
ptr2++;
if (ptr2[0] == '\0') {
break;
}
ptr2[0] = '\0';
// Ignore comments
if (ptr[0] != '#') {
// Search for the album title
if (!xmcd_parse_dtitle(cd_info, ptr)) {
// Search for the genre
if (!xmcd_parse_dgenre(cd_info, ptr)) {
// Search for a track title
xmcd_parse_ttitle(cd_info, ptr);
}
}
}
if (ptr2[1] == '\n')
ptr2++;
pos = (ptr2 + 1) - ptr;
ptr = ptr2 + 1;
}
unsigned int audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame;
cd_info->min = (unsigned int) (audiolen / (60 * 75));
cd_info->sec = (unsigned int) ((audiolen / 75) % 60);
cd_info->msec = (unsigned int) (audiolen % 75);
return cd_info;
}

View File

@ -1,520 +0,0 @@
/*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#if !HAVE_WINSOCK2_H
#include <sys/socket.h>
#else
#include <winsock2.h>
#endif
#include <libavutil/common.h>
#include "core/mp_msg.h"
#include "network.h"
#include "stream.h"
#include "core/m_option.h"
#include "core/m_struct.h"
#include "tcp.h"
static struct stream_priv_s {
char* user;
char* pass;
char* host;
int port;
char* filename;
char *cput,*cget;
int handle;
int cavail,cleft;
char *buf;
char *cmd_buf;
} stream_priv_dflts = {
.user = "anonymous",
.pass = "no@spam",
.port = 21,
.handle = -1,
};
#define CMD_BUFSIZE 8192
#define BUFSIZE 2048
#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
/// URL definition
static const m_option_t stream_opts_fields[] = {
{"username", ST_OFF(user), CONF_TYPE_STRING, 0, 0 ,0, NULL},
{"password", ST_OFF(pass), CONF_TYPE_STRING, 0, 0 ,0, NULL},
{"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL},
{"port", ST_OFF(port), CONF_TYPE_INT, 0, 0 ,65635, NULL},
{"filename", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL},
{ NULL, NULL, 0, 0, 0, 0, NULL }
};
static const struct m_struct_st stream_opts = {
"ftp",
sizeof(struct stream_priv_s),
&stream_priv_dflts,
stream_opts_fields
};
#define TELNET_IAC 255 /* interpret as command: */
#define TELNET_IP 244 /* interrupt process--permanently */
#define TELNET_SYNCH 242 /* for telfunc calls */
// Check if there is something to read on a fd. This avoid hanging
// forever if the network stop responding.
static int fd_can_read(int fd,int timeout) {
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd,&fds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
return select(fd+1, &fds, NULL, NULL, &tv) > 0;
}
/*
* read a line of text
*
* If the line is too long to fit in the buffer, provided via parameters
* buf and max, the remaining characters are skipped. So the next call to
* this function is synchronized to the start of the following response
* line.
*
* The parameter buf will always be initialized as long as max is bigger
* then 1. If nothing is read it will contain an empty string.
*
* return -1 on error or bytecount
*/
static int readline(char *buf,int max,struct stream_priv_s *ctl)
{
int x,retval = 0;
char *end,*bp=buf;
int eof = 0;
if (max <= 0) {
return -1;
}
*bp = '\0';
do {
if (ctl->cavail > 0) {
x = FFMIN(ctl->cavail, max-1);
end = memccpy(bp,ctl->cget,'\n',x);
if (end != NULL)
x = end - bp;
retval += x;
bp += x;
*bp = '\0';
max -= x;
ctl->cget += x;
ctl->cavail -= x;
if (end != NULL) {
bp -= 2;
if (strcmp(bp,"\r\n") == 0) {
*bp++ = '\n';
*bp++ = '\0';
--retval;
}
break;
}
}
if (max == 1) {
char *q = memchr(ctl->cget, '\n', ctl->cavail);
if (q) { // found EOL: update state and return
++q;
ctl->cavail -= q - ctl->cget;
ctl->cget = q;
break;
}
// receive more data to find end of current line
ctl->cget = ctl->cput;
}
if (ctl->cput == ctl->cget) {
ctl->cput = ctl->cget = ctl->buf;
ctl->cavail = 0;
ctl->cleft = BUFSIZE;
}
if(eof) {
if (retval == 0)
retval = -1;
break;
}
if(!fd_can_read(ctl->handle, 15)) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n");
retval = -1;
break;
}
if ((x = recv(ctl->handle,ctl->cput,ctl->cleft,0)) == -1) {
mp_msg(MSGT_STREAM,MSGL_ERR, "[ftp] read error: %s\n",strerror(errno));
retval = -1;
break;
}
if (x == 0)
eof = 1;
ctl->cleft -= x;
ctl->cavail += x;
ctl->cput += x;
} while (1);
return retval;
}
/*
* read a response from the server
*
* return 0 if first char doesn't match
* return 1 if first char matches
*/
static int readresp(struct stream_priv_s* ctl,char* rsp)
{
static char response[256];
char match[5];
int r, len;
len = readline(response,256,ctl);
if (rsp) strcpy(rsp,response);
if (len == -1)
return 0;
r = atoi(response)/100;
mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response);
if (response[3] == '-') {
strncpy(match,response,3);
match[3] = ' ';
match[4] = '\0';
do {
if (readline(response,256,ctl) == -1) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Control socket read failed\n");
return 0;
}
mp_msg(MSGT_OPEN,MSGL_V, "[ftp] < %s",response);
} while (strncmp(response,match,4));
}
return r;
}
static int FtpSendCmd(const char *cmd, struct stream_priv_s *nControl,char* rsp)
{
int l = strlen(cmd);
int hascrlf = cmd[l - 2] == '\r' && cmd[l - 1] == '\n';
if(hascrlf && l == 2) mp_msg(MSGT_STREAM,MSGL_V, "\n");
else mp_msg(MSGT_STREAM,MSGL_V, "[ftp] > %s",cmd);
while(l > 0) {
int s = send(nControl->handle,cmd,l,DEFAULT_SEND_FLAGS);
if(s <= 0) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] write error: %s\n",strerror(errno));
return 0;
}
cmd += s;
l -= s;
}
if (hascrlf)
return readresp(nControl,rsp);
else
return FtpSendCmd("\r\n", nControl, rsp);
}
static int FtpOpenPort(struct stream_priv_s* p) {
int resp,fd;
char rsp_txt[256];
char* par,str[128];
int num[6];
resp = FtpSendCmd("PASV",p,rsp_txt);
if(resp != 2) {
mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'PASV' failed: %s\n",rsp_txt);
return 0;
}
par = strchr(rsp_txt,'(');
if(!par || !par[0] || !par[1]) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] invalid server response: %s ??\n",rsp_txt);
return 0;
}
sscanf(par+1,"%u,%u,%u,%u,%u,%u",&num[0],&num[1],&num[2],
&num[3],&num[4],&num[5]);
snprintf(str,sizeof(str),"%d.%d.%d.%d",num[0],num[1],num[2],num[3]);
fd = connect2Server(str,(num[4]<<8)+num[5],0);
if(fd < 0)
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] failed to create data connection\n");
return fd;
}
static int FtpOpenData(stream_t* s,int64_t newpos) {
struct stream_priv_s* p = s->priv;
int resp;
char rsp_txt[256];
// Open a new connection
s->fd = FtpOpenPort(p);
if(s->fd < 0) return 0;
if(newpos > 0) {
snprintf(p->cmd_buf,CMD_BUFSIZE,"REST %"PRId64, (int64_t)newpos);
resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 3) {
mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
newpos = 0;
}
}
// Get the file
snprintf(p->cmd_buf,CMD_BUFSIZE,"RETR %s",p->filename);
resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 1) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
return 0;
}
s->pos = newpos;
return 1;
}
static int fill_buffer(stream_t *s, char* buffer, int max_len){
int r;
if(s->fd < 0 && !FtpOpenData(s,s->pos))
return -1;
if(!fd_can_read(s->fd, 15)) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n");
return -1;
}
r = recv(s->fd,buffer,max_len,0);
return (r <= 0) ? -1 : r;
}
static int seek(stream_t *s,int64_t newpos) {
struct stream_priv_s* p = s->priv;
int resp;
char rsp_txt[256];
if(s->pos > s->end_pos) {
return 0;
}
// Check to see if the server did not already terminate the transfer
if(fd_can_read(p->handle, 0)) {
if(readresp(p,rsp_txt) != 2)
mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] Warning the server didn't finished the transfer correctly: %s\n",rsp_txt);
closesocket(s->fd);
s->fd = -1;
}
// Close current download
if(s->fd >= 0) {
static const char pre_cmd[]={TELNET_IAC,TELNET_IP,TELNET_IAC,TELNET_SYNCH};
//int fl;
// First close the fd
closesocket(s->fd);
s->fd = -1;
// Send send the telnet sequence needed to make the server react
// Dunno if this is really needed, lftp have it. I let
// it here in case it turn out to be needed on some other OS
//fl=fcntl(p->handle,F_GETFL);
//fcntl(p->handle,F_SETFL,fl&~O_NONBLOCK);
// send only first byte as OOB due to OOB braindamage in many unices
send(p->handle,pre_cmd,1,MSG_OOB|DEFAULT_SEND_FLAGS);
send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,DEFAULT_SEND_FLAGS);
//fcntl(p->handle,F_SETFL,fl);
// Get the 426 Transfer aborted
// Or the 226 Transfer complete
resp = readresp(p,rsp_txt);
if(resp != 4 && resp != 2) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Server didn't abort correctly: %s\n",rsp_txt);
return 0;
}
// Send the ABOR command
// Ignore the return code as sometimes it fail with "nothing to abort"
FtpSendCmd("ABOR",p,rsp_txt);
}
return FtpOpenData(s,newpos);
}
static void close_f(stream_t *s) {
struct stream_priv_s* p = s->priv;
if(!p) return;
if(s->fd >= 0) {
closesocket(s->fd);
s->fd = -1;
}
if (p->handle >= 0) {
FtpSendCmd("QUIT", p, NULL);
closesocket(p->handle);
}
free(p->buf);
free(p->cmd_buf);
m_struct_free(&stream_opts,p);
}
static int open_f(stream_t *stream,int mode, void* opts, av_unused int* file_format) {
int resp;
int64_t len = 0;
struct stream_priv_s* p = opts;
char rsp_txt[256];
if(mode != STREAM_READ) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode);
m_struct_free(&stream_opts,opts);
return STREAM_UNSUPPORTED;
}
if(!p->filename || !p->host) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Bad url\n");
m_struct_free(&stream_opts,opts);
return STREAM_ERROR;
}
// Allocate buffers
p->buf = malloc(BUFSIZE);
p->cmd_buf = malloc(CMD_BUFSIZE);
if (!p->buf || !p->cmd_buf) {
close_f(stream);
m_struct_free(&stream_opts,opts);
return STREAM_ERROR;
}
// Open the control connection
p->handle = connect2Server(p->host,p->port,1);
if(p->handle < 0) {
m_struct_free(&stream_opts,opts);
return STREAM_ERROR;
}
// We got a connection, let's start serious things
stream->fd = -1;
stream->priv = p;
if (readresp(p, NULL) == 0) {
close_f(stream);
return STREAM_ERROR;
}
// Login
snprintf(p->cmd_buf,CMD_BUFSIZE,"USER %s",p->user);
resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
// password needed
if(resp == 3) {
snprintf(p->cmd_buf,CMD_BUFSIZE,"PASS %s",p->pass);
resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 2) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
close_f(stream);
return STREAM_ERROR;
}
} else if(resp != 2) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
close_f(stream);
return STREAM_ERROR;
}
// Set the transfer type
resp = FtpSendCmd("TYPE I",p,rsp_txt);
if(resp != 2) {
mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'TYPE I' failed: %s\n",rsp_txt);
close_f(stream);
return STREAM_ERROR;
}
// Get the filesize
snprintf(p->cmd_buf,CMD_BUFSIZE,"SIZE %s",p->filename);
resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 2) {
mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
} else {
int dummy;
sscanf(rsp_txt,"%d %"SCNd64,&dummy,&len);
}
if(len > 0) {
stream->seek = seek;
stream->end_pos = len;
}
// The data connection is really opened only at the first
// read/seek. This must be done when the cache is used
// because the connection would stay open in the main process,
// preventing correct abort with many servers.
stream->fd = -1;
stream->priv = p;
stream->fill_buffer = fill_buffer;
stream->close = close_f;
stream->type = STREAMTYPE_STREAM;
return STREAM_OK;
}
const stream_info_t stream_info_ftp = {
"File Transfer Protocol",
"ftp",
"Albeu",
"reuse a bit of code from ftplib written by Thomas Pfau",
open_f,
{ "ftp", NULL },
&stream_opts,
1 // Urls are an option string
};

View File

@ -28,7 +28,6 @@
#include "core/m_struct.h"
#include "demux/demux.h"
#include "network.h"
#include "cookies.h"
#include "core/bstr.h"
@ -317,7 +316,7 @@ const stream_info_t stream_info_ffmpeg = {
"",
open_f,
{ "lavf", "ffmpeg", "rtmp", "rtsp", "http", "https", "mms", "mmst", "mmsh",
"mmshttp", NULL },
"mmshttp", "udp", "ftp", NULL },
NULL,
1 // Urls are an option string
};

View File

@ -1,105 +0,0 @@
/*
* stream layer for MPEG over UDP, based on previous work from Dave Chapman
*
* Copyright (C) 2006 Benjamin Zores
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "core/options.h"
#include "stream.h"
#include "url.h"
#include "udp.h"
static int
udp_streaming_start (stream_t *stream)
{
streaming_ctrl_t *streaming_ctrl;
int fd;
if (!stream)
return -1;
streaming_ctrl = stream->streaming_ctrl;
fd = stream->fd;
if (fd < 0)
{
fd = udp_open_socket (streaming_ctrl->url);
if (fd < 0)
return -1;
stream->fd = fd;
}
streaming_ctrl->streaming_read = nop_streaming_read;
streaming_ctrl->streaming_seek = nop_streaming_seek;
streaming_ctrl->status = streaming_playing_e;
stream->streaming = false;
return 0;
}
static int
udp_stream_open (stream_t *stream, int mode, void *opts, int *file_format)
{
mp_msg (MSGT_OPEN, MSGL_INFO, "STREAM_UDP, URL: %s\n", stream->url);
stream->streaming_ctrl = streaming_ctrl_new ();
if (!stream->streaming_ctrl)
return STREAM_ERROR;
stream->streaming_ctrl->bandwidth = network_bandwidth;
stream->streaming_ctrl->url = url_new(stream->url);
if (stream->streaming_ctrl->url->port == 0)
{
mp_msg (MSGT_NETWORK, MSGL_ERR,
"You must enter a port number for UDP streams!\n");
streaming_ctrl_free (stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
if (udp_streaming_start (stream) < 0)
{
mp_msg (MSGT_NETWORK, MSGL_ERR, "udp_streaming_start failed\n");
streaming_ctrl_free (stream->streaming_ctrl);
stream->streaming_ctrl = NULL;
return STREAM_UNSUPPORTED;
}
stream->type = STREAMTYPE_STREAM;
return STREAM_OK;
}
const stream_info_t stream_info_udp = {
"MPEG over UDP streaming",
"udp",
"Dave Chapman, Benjamin Zores",
"native udp support",
udp_stream_open,
{ "udp", NULL},
NULL,
0 // Urls are an option string
};

View File

@ -1,279 +0,0 @@
/*
* Network layer for MPlayer
*
* Copyright (C) 2001 Bertrand BAUDET <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include "config.h"
#include "core/mp_msg.h"
#if !HAVE_WINSOCK2_H
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "network.h"
#include "stream.h"
#include "tcp.h"
#include "libavutil/avstring.h"
/* IPv6 options */
int network_prefer_ipv4 = 0;
// Converts an address family constant to a string
static const char *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 port
static int
connect2Server_with_af(char *host, int port, int af,int verb) {
int socket_server_fd;
int err;
socklen_t 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];
#if HAVE_WINSOCK2_H
unsigned long val;
int to;
#else
struct timeval to;
#endif
#if HAVE_WINSOCK2_H && defined(HAVE_AF_INET6)
// our winsock name resolution code can not handle IPv6
if (af == AF_INET6) {
mp_msg(MSGT_NETWORK, MSGL_WARN, "IPv6 not supported for winsock2\n");
return TCP_ERROR_FATAL;
}
#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 TCP_ERROR_FATAL;
}
#if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
#if HAVE_WINSOCK2_H
/* timeout in milliseconds */
to = 10 * 1000;
#else
to.tv_sec = 10;
to.tv_usec = 0;
#endif
setsockopt(socket_server_fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
setsockopt(socket_server_fd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
#endif
switch (af) {
case AF_INET: our_s_addr = &server_address.four.sin_addr; break;
#ifdef HAVE_AF_INET6
case AF_INET6: our_s_addr = &server_address.six.sin6_addr; break;
#endif
default:
mp_tmsg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d\n", af);
return TCP_ERROR_FATAL;
}
memset(&server_address, 0, sizeof(server_address));
#if HAVE_INET_PTON
if (inet_pton(af, host, our_s_addr)!=1)
#elif HAVE_INET_ATON
if (inet_aton(host, our_s_addr)!=1)
#elif HAVE_WINSOCK2_H
if ( inet_addr(host)==INADDR_NONE )
#endif
{
if(verb) mp_tmsg(MSGT_NETWORK,MSGL_STATUS,"Resolving %s for %s...\n", host, af2String(af));
#ifdef HAVE_GETHOSTBYNAME2
hp=gethostbyname2( host, af );
#else
hp=gethostbyname( host );
#endif
if( hp==NULL ) {
if(verb) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Couldn't resolve name for %s: %s\n", af2String(af), host);
return TCP_ERROR_FATAL;
}
memcpy( our_s_addr, hp->h_addr_list[0], hp->h_length );
}
#if HAVE_WINSOCK2_H
else {
unsigned long addr = inet_addr(host);
memcpy( our_s_addr, &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_tmsg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d\n", af);
return TCP_ERROR_FATAL;
}
#if HAVE_INET_PTON
inet_ntop(af, our_s_addr, buf, 255);
#elif HAVE_INET_ATON || defined(HAVE_WINSOCK2_H)
av_strlcpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);
#endif
if(verb) mp_tmsg(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
#if !HAVE_WINSOCK2_H
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 ) {
#if !HAVE_WINSOCK2_H
if( errno!=EINPROGRESS ) {
#else
if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
#endif
if(verb) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server with %s\n", af2String(af));
closesocket(socket_server_fd);
return TCP_ERROR_PORT;
}
}
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 writeable fd
while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
if(count > 30 || stream_check_interrupt(500)) {
if(count > 30)
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"connection timeout\n");
else
mp_msg(MSGT_NETWORK,MSGL_V,"Connection interrupted by user\n");
return TCP_ERROR_TIMEOUT;
}
count++;
FD_ZERO( &set );
FD_SET( socket_server_fd, &set );
tv.tv_sec = 0;
tv.tv_usec = 500000;
}
if (ret < 0) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Select failed.\n");
// Turn back the socket as blocking
#if !HAVE_WINSOCK2_H
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 errors
err_len = sizeof(int);
ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
if(ret < 0) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"getsockopt failed: %s\n",strerror(errno));
return TCP_ERROR_FATAL;
}
if(err > 0) {
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"connect error: %s\n",strerror(err));
return TCP_ERROR_PORT;
}
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 port
int
connect2Server(char *host, int port, int verb) {
#ifdef HAVE_AF_INET6
int r;
int s = TCP_ERROR_FATAL;
r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb);
if (r >= 0) return r;
s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb);
if (s == TCP_ERROR_FATAL) return r;
return s;
#else
return connect2Server_with_af(host, port, AF_INET,verb);
#endif
}

View File

@ -1,35 +0,0 @@
/*
* network helpers for TCP connections
* (originally borrowed from network.c,
* by Bertrand BAUDET <bertrand_baudet@yahoo.com>)
*
* Copyright (C) 2001 Bertrand BAUDET, 2006 Benjamin Zores
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_TCP_H
#define MPLAYER_TCP_H
/* Connect to a server using a TCP connection */
int connect2Server (char *host, int port, int verb);
#define TCP_ERROR_TIMEOUT -3 /* connection timeout */
#define TCP_ERROR_FATAL -2 /* unable to resolve name */
#define TCP_ERROR_PORT -1 /* unable to connect to a particular port */
#endif /* MPLAYER_TCP_H */

View File

@ -1,201 +0,0 @@
/*
* network helpers for UDP connections (originally borrowed from rtp.c)
*
* Copyright (C) 2006 Benjamin Zores
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#if !HAVE_WINSOCK2_H
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include "core/mp_msg.h"
#include "network.h"
#include "url.h"
#include "udp.h"
int reuse_socket=0;
/* Start listening on a UDP port. If multicast, join the group. */
int
udp_open_socket (URL_t *url)
{
int socket_server_fd, rxsockbufsz;
int err;
socklen_t err_len;
fd_set set;
struct sockaddr_in server_address;
struct ip_mreq mcast;
struct timeval tv;
struct hostent *hp;
int reuse=reuse_socket;
mp_msg (MSGT_NETWORK, MSGL_V,
"Listening for traffic on %s:%d ...\n", url->hostname, url->port);
socket_server_fd = socket (AF_INET, SOCK_DGRAM, 0);
if (socket_server_fd == -1)
{
mp_msg (MSGT_NETWORK, MSGL_ERR, "Failed to create socket\n");
return -1;
}
memset(&server_address, 0, sizeof(server_address));
if (isalpha (url->hostname[0]))
{
#if !HAVE_WINSOCK2_H
hp = gethostbyname (url->hostname);
if (!hp)
{
mp_msg (MSGT_NETWORK, MSGL_ERR,
"Counldn't resolve name: %s\n", url->hostname);
closesocket (socket_server_fd);
return -1;
}
memcpy (&server_address.sin_addr.s_addr,
hp->h_addr_list[0], hp->h_length);
#else
server_address.sin_addr.s_addr = htonl (INADDR_ANY);
#endif /* HAVE_WINSOCK2_H */
}
else
{
#if HAVE_INET_PTON
inet_pton (AF_INET, url->hostname, &server_address.sin_addr);
#elif HAVE_INET_ATON
inet_aton (url->hostname, &server_address.sin_addr);
#elif !HAVE_WINSOCK2_H
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
#endif
}
server_address.sin_family = AF_INET;
server_address.sin_port = htons (url->port);
if(reuse_socket && setsockopt(socket_server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
mp_msg(MSGT_NETWORK, MSGL_ERR, "SO_REUSEADDR failed! ignore.\n");
if (bind (socket_server_fd, (struct sockaddr *) &server_address,
sizeof (server_address)) == -1)
{
#if !HAVE_WINSOCK2_H
if (errno != EINPROGRESS)
#else
if (WSAGetLastError () != WSAEINPROGRESS)
#endif /* HAVE_WINSOCK2_H */
{
mp_msg (MSGT_NETWORK, MSGL_ERR, "Failed to connect to server\n");
closesocket (socket_server_fd);
return -1;
}
}
#if HAVE_WINSOCK2_H
if (isalpha (url->hostname[0]))
{
hp = gethostbyname (url->hostname);
if (!hp)
{
mp_msg (MSGT_NETWORK, MSGL_ERR,
"Could not resolve name: %s\n", url->hostname);
closesocket (socket_server_fd);
return -1;
}
memcpy (&server_address.sin_addr.s_addr,
hp->h_addr, hp->h_length);
}
else
{
unsigned int addr = inet_addr (url->hostname);
memcpy (&server_address.sin_addr, &addr, sizeof (addr));
}
#endif /* HAVE_WINSOCK2_H */
/* Increase the socket rx buffer size to maximum -- this is UDP */
rxsockbufsz = 240 * 1024;
if (setsockopt (socket_server_fd, SOL_SOCKET, SO_RCVBUF,
&rxsockbufsz, sizeof (rxsockbufsz)))
{
mp_msg (MSGT_NETWORK, MSGL_ERR,
"Couldn't set receive socket buffer size\n");
}
if ((ntohl (server_address.sin_addr.s_addr) >> 28) == 0xe)
{
mcast.imr_multiaddr.s_addr = server_address.sin_addr.s_addr;
mcast.imr_interface.s_addr = 0;
if (setsockopt (socket_server_fd, IPPROTO_IP,
IP_ADD_MEMBERSHIP, &mcast, sizeof (mcast)))
{
mp_msg (MSGT_NETWORK, MSGL_ERR, "IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?)\n");
closesocket (socket_server_fd);
return -1;
}
}
tv.tv_sec = 1; /* 1 second timeout */
tv.tv_usec = 0;
FD_ZERO (&set);
FD_SET (socket_server_fd, &set);
err = select (socket_server_fd + 1, &set, NULL, NULL, &tv);
if (err < 0)
{
mp_msg (MSGT_NETWORK, MSGL_FATAL,
"Select failed: %s\n", strerror (errno));
closesocket (socket_server_fd);
return -1;
}
if (err == 0)
{
mp_msg (MSGT_NETWORK, MSGL_ERR,
"Timeout! No data from host %s\n", url->hostname);
closesocket (socket_server_fd);
return -1;
}
err_len = sizeof (err);
getsockopt (socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
if (err)
{
mp_msg (MSGT_NETWORK, MSGL_DBG2, "Socket error: %d\n", err);
closesocket (socket_server_fd);
return -1;
}
return socket_server_fd;
}

View File

@ -1,30 +0,0 @@
/*
* network helpers for UDP connections (originally borrowed from rtp.c)
*
* Copyright (C) 2006 Benjamin Zores
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_UDP_H
#define MPLAYER_UDP_H
#include "url.h"
int udp_open_socket (URL_t *url);
#endif /* MPLAYER_UDP_H */

View File

@ -1,506 +0,0 @@
/*
* URL Helper
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <inttypes.h>
#include "url.h"
#include "core/mp_msg.h"
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif
static char *mp_asprintf(const char *fmt, ...)
{
char *p = NULL;
va_list va, va_bak;
int len;
va_start(va, fmt);
va_copy(va_bak, va);
len = vsnprintf(NULL, 0, fmt, va);
if (len < 0)
goto end;
p = malloc(len + 1);
if (!p)
goto end;
len = vsnprintf(p, len + 1, fmt, va_bak);
if (len < 0)
free(p), p = NULL;
end:
va_end(va);
return p;
}
static int is_proxy(const URL_t *url) {
return !strcasecmp(url->protocol, "mp_http_proxy") && url->file && strstr(url->file, "://");
}
int url_is_protocol(const URL_t *url, const char *proto) {
int proxy = is_proxy(url);
if (proxy) {
URL_t *tmp = url_new(url->file + 1);
int res = !strcasecmp(tmp->protocol, proto);
url_free(tmp);
return res;
}
return !strcasecmp(url->protocol, proto);
}
void url_set_protocol(URL_t *url, const char *proto) {
int proxy = is_proxy(url);
if (proxy) {
char *dst = url->file + 1;
int oldlen = strstr(dst, "://") - dst;
int newlen = strlen(proto);
if (newlen != oldlen) {
mp_msg(MSGT_NETWORK, MSGL_ERR, "Setting protocol not implemented!\n");
return;
}
memcpy(dst, proto, newlen);
return;
}
free(url->protocol);
url->protocol = strdup(proto);
}
URL_t *url_redirect(URL_t **url, const char *redir) {
URL_t *u = *url;
int proxy = is_proxy(u);
const char *oldurl = proxy ? u->file + 1 : u->url;
const char *newurl = redir;
char *buffer = NULL;
URL_t *res;
if (!strchr(redir, '/') || *redir == '/') {
char *tmp;
newurl = buffer = malloc(strlen(oldurl) + strlen(redir) + 1);
strcpy(buffer, oldurl);
if (*redir == '/') {
redir++;
tmp = strstr(buffer, "://");
if (tmp) tmp = strchr(tmp + 3, '/');
} else
tmp = strrchr(buffer, '/');
if (tmp) tmp[1] = 0;
strcat(buffer, redir);
}
if (proxy) {
char *tmp = get_http_proxy_url(u, newurl);
free(buffer);
newurl = buffer = tmp;
}
res = url_new(newurl);
free(buffer);
url_free(u);
*url = res;
return res;
}
static char *get_noauth_url(const URL_t *url)
{
if (url->port)
return mp_asprintf("%s://%s:%d%s",
url->protocol, url->hostname, url->port, url->file);
else
return mp_asprintf("%s://%s%s",
url->protocol, url->hostname, url->file);
}
char *get_http_proxy_url(const URL_t *proxy, const char *host_url)
{
if (proxy->username)
return mp_asprintf("mp_http_proxy://%s:%s@%s:%d/%s",
proxy->username,
proxy->password ? proxy->password : "",
proxy->hostname, proxy->port, host_url);
else
return mp_asprintf("mp_http_proxy://%s:%d/%s",
proxy->hostname, proxy->port, host_url);
}
URL_t*
url_new(const char* url) {
int pos1, pos2,v6addr = 0;
URL_t* Curl = NULL;
char *escfilename=NULL;
char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL;
int jumpSize = 3;
if( url==NULL ) return NULL;
if (strlen(url) > (SIZE_MAX / 3 - 1)) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
escfilename=malloc(strlen(url)*3+1);
if (!escfilename ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
// Create the URL container
Curl = calloc(1, sizeof(*Curl));
if( Curl==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
url_escape_string(escfilename,url);
// Copy the url in the URL container
Curl->url = strdup(escfilename);
if( Curl->url==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
mp_msg(MSGT_OPEN,MSGL_V,"Filename for url is now %s\n",escfilename);
// extract the protocol
ptr1 = strstr(escfilename, "://");
if( ptr1==NULL ) {
// Check for a special case: "sip:" (without "//"):
if (strstr(escfilename, "sip:") == escfilename) {
ptr1 = (char *)&url[3]; // points to ':'
jumpSize = 1;
} else {
mp_msg(MSGT_NETWORK,MSGL_V,"Not an URL!\n");
goto err_out;
}
}
pos1 = ptr1-escfilename;
Curl->protocol = malloc(pos1+1);
if( Curl->protocol==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
strncpy(Curl->protocol, escfilename, pos1);
Curl->protocol[pos1] = '\0';
// jump the "://"
ptr1 += jumpSize;
pos1 += jumpSize;
// check if a username:password is given
ptr2 = strstr(ptr1, "@");
ptr3 = strstr(ptr1, "/");
if( ptr3!=NULL && ptr3<ptr2 ) {
// it isn't really a username but rather a part of the path
ptr2 = NULL;
}
if( ptr2!=NULL ) {
// We got something, at least a username...
int len = ptr2-ptr1;
Curl->username = malloc(len+1);
if( Curl->username==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
strncpy(Curl->username, ptr1, len);
Curl->username[len] = '\0';
ptr3 = strstr(ptr1, ":");
if( ptr3!=NULL && ptr3<ptr2 ) {
// We also have a password
int len2 = ptr2-ptr3-1;
Curl->username[ptr3-ptr1]='\0';
Curl->password = malloc(len2+1);
if( Curl->password==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
strncpy( Curl->password, ptr3+1, len2);
Curl->password[len2]='\0';
url_unescape_string(Curl->password, Curl->password);
}
url_unescape_string(Curl->username, Curl->username);
ptr1 = ptr2+1;
pos1 = ptr1-escfilename;
}
// before looking for a port number check if we have an IPv6 type numeric address
// in IPv6 URL the numeric address should be inside square braces.
ptr2 = strstr(ptr1, "[");
ptr3 = strstr(ptr1, "]");
ptr4 = strstr(ptr1, "/");
if( ptr2!=NULL && ptr3!=NULL && ptr2 < ptr3 && (!ptr4 || ptr4 > ptr3)) {
// we have an IPv6 numeric address
ptr1++;
pos1++;
ptr2 = ptr3;
v6addr = 1;
} else {
ptr2 = ptr1;
}
// look if the port is given
ptr2 = strstr(ptr2, ":");
// If the : is after the first / it isn't the port
ptr3 = strstr(ptr1, "/");
if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL;
if( ptr2==NULL ) {
// No port is given
// Look if a path is given
if( ptr3==NULL ) {
// No path/filename
// So we have an URL like http://www.hostname.com
pos2 = strlen(escfilename);
} else {
// We have an URL like http://www.hostname.com/file.txt
pos2 = ptr3-escfilename;
}
} else {
// We have an URL beginning like http://www.hostname.com:1212
// Get the port number
Curl->port = atoi(ptr2+1);
pos2 = ptr2-escfilename;
}
if( v6addr ) pos2--;
// copy the hostname in the URL container
Curl->hostname = malloc(pos2-pos1+1);
if( Curl->hostname==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
strncpy(Curl->hostname, ptr1, pos2-pos1);
Curl->hostname[pos2-pos1] = '\0';
// Look if a path is given
ptr2 = strstr(ptr1, "/");
if( ptr2!=NULL ) {
// A path/filename is given
// check if it's not a trailing '/'
if( strlen(ptr2)>1 ) {
// copy the path/filename in the URL container
Curl->file = strdup(ptr2);
if( Curl->file==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
}
}
// Check if a filename was given or set, else set it with '/'
if( Curl->file==NULL ) {
Curl->file = malloc(2);
if( Curl->file==NULL ) {
mp_tmsg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed.\n");
goto err_out;
}
strcpy(Curl->file, "/");
}
Curl->noauth_url = get_noauth_url(Curl);
if (!Curl->noauth_url) {
mp_msg(MSGT_NETWORK, MSGL_FATAL, "Memory allocation failed.\n");
goto err_out;
}
free(escfilename);
return Curl;
err_out:
free(escfilename);
if (Curl) url_free(Curl);
return NULL;
}
void
url_free(URL_t* url) {
if(!url) return;
free(url->url);
free(url->protocol);
free(url->hostname);
free(url->file);
free(url->username);
free(url->password);
free(url);
}
/* Replace escape sequences in an URL (or a part of an URL) */
/* works like strcpy(), but without return argument,
except that outbuf == inbuf is allowed */
void
url_unescape_string(char *outbuf, const char *inbuf)
{
unsigned char c,c1,c2;
int i,len=strlen(inbuf);
for (i=0;i<len;i++){
c = inbuf[i];
if (c == '%' && i<len-2) { //must have 2 more chars
c1 = toupper(inbuf[i+1]); // we need uppercase characters
c2 = toupper(inbuf[i+2]);
if ( ((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) &&
((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) ) {
if (c1>='0' && c1<='9') c1-='0';
else c1-='A'-10;
if (c2>='0' && c2<='9') c2-='0';
else c2-='A'-10;
c = (c1<<4) + c2;
i=i+2; //only skip next 2 chars if valid esc
}
}
*outbuf++ = c;
}
*outbuf++='\0'; //add nullterm to string
}
static void
url_escape_string_part(char *outbuf, const char *inbuf) {
unsigned char c,c1,c2;
int i,len=strlen(inbuf);
for (i=0;i<len;i++) {
c = inbuf[i];
if ((c=='%') && i<len-2 ) { //need 2 more characters
c1=toupper(inbuf[i+1]); c2=toupper(inbuf[i+2]); // need uppercase chars
} else {
c1=129; c2=129; //not escape chars
}
if( (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9')) {
*outbuf++ = c;
} else if ( c=='%' && ((c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'F')) &&
((c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'F'))) {
// check if part of an escape sequence
*outbuf++=c; // already
// dont escape again
mp_tmsg(MSGT_NETWORK,MSGL_ERR,"String appears to be already escaped in url_escape %c%c1%c2\n",c,c1,c2);
// error as this should not happen against RFC 2396
// to escape a string twice
} else {
/* all others will be escaped */
c1 = ((c & 0xf0) >> 4);
c2 = (c & 0x0f);
if (c1 < 10) c1+='0';
else c1+='A'-10;
if (c2 < 10) c2+='0';
else c2+='A'-10;
*outbuf++ = '%';
*outbuf++ = c1;
*outbuf++ = c2;
}
}
*outbuf++='\0';
}
/* Replace specific characters in the URL string by an escape sequence */
/* works like strcpy(), but without return argument */
void
url_escape_string(char *outbuf, const char *inbuf) {
unsigned char c;
int i = 0,j,len = strlen(inbuf);
char* tmp,*unesc = NULL, *in;
// Look if we have an ip6 address, if so skip it there is
// no need to escape anything in there.
tmp = strstr(inbuf,"://[");
if(tmp) {
tmp = strchr(tmp+4,']');
if(tmp && (tmp[1] == '/' || tmp[1] == ':' ||
tmp[1] == '\0')) {
i = tmp+1-inbuf;
strncpy(outbuf,inbuf,i);
outbuf += i;
tmp = NULL;
}
}
tmp = NULL;
while(i < len) {
// look for the next char that must be kept
for (j=i;j<len;j++) {
c = inbuf[j];
if(c=='-' || c=='_' || c=='.' || c=='!' || c=='~' || /* mark characters */
c=='*' || c=='\'' || c=='(' || c==')' || /* do not touch escape character */
c==';' || c=='/' || c=='?' || c==':' || c=='@' || /* reserved characters */
c=='&' || c=='=' || c=='+' || c=='$' || c==',') /* see RFC 2396 */
break;
}
// we are on a reserved char, write it out
if(j == i) {
*outbuf++ = c;
i++;
continue;
}
// we found one, take that part of the string
if(j < len) {
if(!tmp) tmp = malloc(len+1);
strncpy(tmp,inbuf+i,j-i);
tmp[j-i] = '\0';
in = tmp;
} else // take the rest of the string
in = (char*)inbuf+i;
if(!unesc) unesc = malloc(len+1);
// unescape first to avoid escaping escape
url_unescape_string(unesc,in);
// then escape, including mark and other reserved chars
// that can come from escape sequences
url_escape_string_part(outbuf,unesc);
outbuf += strlen(outbuf);
i += strlen(in);
}
*outbuf = '\0';
free(tmp);
free(unesc);
}
#ifdef URL_DEBUG
void
url_debug(const URL_t *url) {
if( url==NULL ) {
printf("URL pointer NULL\n");
return;
}
if( url->url!=NULL ) {
printf("url=%s\n", url->url );
}
if( url->protocol!=NULL ) {
printf("protocol=%s\n", url->protocol );
}
if( url->hostname!=NULL ) {
printf("hostname=%s\n", url->hostname );
}
printf("port=%d\n", url->port );
if( url->file!=NULL ) {
printf("file=%s\n", url->file );
}
if( url->username!=NULL ) {
printf("username=%s\n", url->username );
}
if( url->password!=NULL ) {
printf("password=%s\n", url->password );
}
}
#endif /* URL_DEBUG */

View File

@ -1,55 +0,0 @@
/*
* URL Helper
*
* Copyright (C) 2001 Bertrand Baudet <bertrand_baudet@yahoo.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_URL_H
#define MPLAYER_URL_H
//#define URL_DEBUG
typedef struct {
char *url;
char *noauth_url;
char *protocol;
char *hostname;
char *file;
unsigned int port;
char *username;
char *password;
} URL_t;
int url_is_protocol(const URL_t *url, const char *proto);
void url_set_protocol(URL_t *url, const char *proto);
URL_t *url_redirect(URL_t **url, const char *redir);
char *get_http_proxy_url(const URL_t *proxy, const char *host_url);
URL_t* url_new(const char* url);
void url_free(URL_t* url);
void url_unescape_string(char *outbuf, const char *inbuf);
void url_escape_string(char *outbuf, const char *inbuf);
#ifdef URL_DEBUG
void url_debug(const URL_t* url);
#endif /* URL_DEBUG */
#endif /* MPLAYER_URL_H */