mirror of
http://mpg123.de/trunk/.git
synced 2025-08-06 10:02:38 +03:00
merge in multinet to trunk
git-svn-id: svn://scm.orgis.org/mpg123/trunk@5161 35dc7657-300d-0410-a2e5-dc2837fedb53
This commit is contained in:
14
NEWS
14
NEWS
@@ -1,18 +1,22 @@
|
||||
1.31.0
|
||||
------
|
||||
|
||||
TODO: Let curl handle redirects again, or make this an option somehow.
|
||||
Right now this eases testing of redirect code in streamdump.c.
|
||||
|
||||
- mpg123:
|
||||
-- TODO: Revert to internal network code for plain HTTP to ensure continued
|
||||
support for original shoutcast servers that do not talk proper HTTP.
|
||||
-- Revert to internal network code for plain HTTP to ensure continued
|
||||
support for original shoutcast servers that do not talk proper HTTP.
|
||||
External backends are built at the same time and can be enforced using
|
||||
--network <backend>.
|
||||
-- Try-witout-port for internal network code is gone. We do not need to
|
||||
keep each ancient hack for specific hosts.
|
||||
-- Handle redirections independently of the backend behind net123.
|
||||
-- Set proxy environment variables when --proxy is specified, for net123
|
||||
backends to use.
|
||||
-- Continue reading for long commands in generic control, avoiding
|
||||
unnecessary unfinished command errors.
|
||||
-- Change error message from 'unknown command' to
|
||||
'unknown command with arguments' to avoid confusion why 'help foo'
|
||||
is unknown, as opposed to 'help'.
|
||||
- some build fixes for compiler pickyness
|
||||
|
||||
1.30.3
|
||||
------
|
||||
|
54
configure.ac
54
configure.ac
@@ -9,7 +9,7 @@ dnl 2.69 at least.
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
dnl ############# Initialisation
|
||||
AC_INIT([mpg123], [1.30.3], [maintainer@mpg123.org])
|
||||
AC_INIT([mpg123], [1.31.0], [maintainer@mpg123.org])
|
||||
dnl Increment API_VERSION when the API gets changes (new functions).
|
||||
|
||||
dnl libmpg123
|
||||
@@ -1218,7 +1218,7 @@ if test "x$ac_cv_sys_posix_termios" = "xyes"; then
|
||||
term_type=posix
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS( random )
|
||||
AC_CHECK_FUNCS( random setenv unsetenv )
|
||||
|
||||
# Check for sched_setscheduler
|
||||
AC_CHECK_FUNCS( sched_setscheduler setuid getuid)
|
||||
@@ -2577,7 +2577,10 @@ AC_ARG_ENABLE(network,
|
||||
|
||||
AC_MSG_CHECKING([for preferred network support])
|
||||
AC_ARG_WITH([network],
|
||||
[AS_HELP_STRING([--with-network=<type>], [Available options, depending on platform, are auto, none, internal, winhttp, wininet, and exec (wget or curl binaries).])],
|
||||
[AS_HELP_STRING([--with-network=<type>],
|
||||
[Available options, depending on platform, are auto, none, internal, winhttp, wininet (or wininethttp for both), and exec (wget or curl binaries).
|
||||
The internal code is always built in addition to external options for plain HTTP (esp. Shoutcast v1) support.
|
||||
The external option is for HTTPS by default, but can be used for HTTP, too.])],
|
||||
[
|
||||
case "$withval" in
|
||||
exec)
|
||||
@@ -2592,6 +2595,10 @@ AC_ARG_WITH([network],
|
||||
network_type="wininet"
|
||||
AC_MSG_RESULT([wininet])
|
||||
;;
|
||||
wininethttp)
|
||||
network_type="wininethttp"
|
||||
AC_MSG_RESULT([wininethttp])
|
||||
;;
|
||||
internal)
|
||||
network_type="internal"
|
||||
AC_MSG_RESULT([internal])
|
||||
@@ -2619,7 +2626,7 @@ if test x$network_type = xauto; then
|
||||
if test "x$have_fork" = "xyes"; then
|
||||
network_type=exec
|
||||
elif test "x$win32_specific_codes" = "xenabled"; then
|
||||
network_type=wininet
|
||||
network_type=wininethttp
|
||||
elif test "x$have_network" = "xyes"; then
|
||||
network_type="internal"
|
||||
else
|
||||
@@ -2635,7 +2642,7 @@ fi
|
||||
if test x$network_type = xexec -a x$have_fork != xyes; then
|
||||
AC_MSG_ERROR([exec network support selected but fork not available])
|
||||
fi
|
||||
if test x$network_type = xwininet -o x$network_type = xwinhttp && test x$win32_specific_codes != xenabled; then
|
||||
if test x$network_type = xwininet -o x$network_type = xwinhttp -o x$network_type = xwininethttp && test x$win32_specific_codes != xenabled; then
|
||||
AC_MSG_ERROR([wininet or winhttp is currently only for Windows])
|
||||
fi
|
||||
|
||||
@@ -2644,7 +2651,7 @@ AM_CONDITIONAL([WIN32_CODES], [ test "x$win32_specific_codes" = xenabled ])
|
||||
|
||||
if test x"$ipv6" = xauto; then
|
||||
AC_MSG_CHECKING([IPv6 use])
|
||||
if test x"$have_ipv6" = xyes -a x"$network_type" = xinternal; then
|
||||
if test x"$have_ipv6" = xyes -a x"$network_type" != xdisabled; then
|
||||
ipv6=enabled
|
||||
else
|
||||
ipv6=disabled
|
||||
@@ -2652,14 +2659,31 @@ if test x"$ipv6" = xauto; then
|
||||
AC_MSG_RESULT([$ipv6])
|
||||
fi
|
||||
|
||||
if test x$network_type = xinternal -a x$network_internal = xwinsock2; then
|
||||
if test x$network_type != xdisabled -a x$network_internal = xwinsock2; then
|
||||
AC_DEFINE([WANT_WIN32_SOCKETS], [1], [ Define to use Win32 sockets ])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([NETWORK_WINSOCK], [ test x$network_type = xinternal -a x$network_internal = xwinsock2 ])
|
||||
AM_CONDITIONAL([NETWORK_WINSOCK], [ test x$network_type != xdisabled -a x$network_internal = xwinsock2 ])
|
||||
AM_CONDITIONAL([NET123], [ test x$network_type != xdisabled ])
|
||||
AM_CONDITIONAL([NET123_EXEC], [ test x$network_type = xexec ])
|
||||
AM_CONDITIONAL([NET123_WINHTTP], [ test x$network_type = xwinhttp ])
|
||||
AM_CONDITIONAL([NET123_WININET], [ test x$network_type = xwininet ])
|
||||
AM_CONDITIONAL([NET123_WINHTTP], [ test x$network_type = xwinhttp || test x$network_type = xwininethttp ])
|
||||
AM_CONDITIONAL([NET123_WININET], [ test x$network_type = xwininet || test x$network_type = xwininethttp ])
|
||||
|
||||
case "$network_type" in
|
||||
exec)
|
||||
AC_DEFINE(NET123_EXEC, 1, [ Define for executable-based networking (for HTTPS). ])
|
||||
;;
|
||||
winhttp)
|
||||
AC_DEFINE(NET123_WINHTTP, 1, [ Define for winhttp networking (for HTTPS). ])
|
||||
;;
|
||||
wininet)
|
||||
AC_DEFINE(NET123_WININET, 1, [ Define for wininet networking (for HTTPS). ])
|
||||
;;
|
||||
wininethttp)
|
||||
AC_DEFINE(NET123_WININET, 1, [ Define for wininet networking (for HTTPS). ])
|
||||
AC_DEFINE(NET123_WINHTTP, 1, [ Define for winhttp networking (for HTTPS). ])
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl ############## Terminal choice
|
||||
|
||||
@@ -2685,7 +2709,7 @@ if test x"$fifo" = xenabled; then
|
||||
fi
|
||||
|
||||
dnl ############## Network enable
|
||||
if test x"$network_type" = xinternal; then
|
||||
if test x"$network_type" != xdisabled; then
|
||||
AC_DEFINE(NETWORK, 1, [ Define if network support is enabled. ])
|
||||
if test x"$have_network" = xno; then
|
||||
AC_MSG_WARN( [ You forced network code while I think there is support missing! ] )
|
||||
@@ -2742,9 +2766,11 @@ echo "
|
||||
Extreme debugging ....... $xdebugging
|
||||
Seek table size ......... $seektable
|
||||
FIFO support ............ $fifo
|
||||
Buffer .................. $buffer
|
||||
Network (http streams) .. $network_type"
|
||||
if test x$network_type = xinternal; then
|
||||
Buffer .................. $buffer"
|
||||
if test x$network_type != xdisabled; then
|
||||
if test x$network_type != xinternal; then
|
||||
echo " External network ........ $network_type"
|
||||
fi
|
||||
echo " Internal network type ... $network_internal
|
||||
IPv6 (getaddrinfo) ...... $ipv6"
|
||||
fi
|
||||
|
@@ -46,6 +46,8 @@ check_function_exists(mkfifo HAVE_MKFIFO)
|
||||
check_function_exists(mmap HAVE_MMAP)
|
||||
check_function_exists(nl_langinfo HAVE_NL_LANGINFO)
|
||||
check_function_exists(random HAVE_RANDOM)
|
||||
check_function_exists(setenv HAVE_SETENV)
|
||||
check_function_exists(unsetenv HAVE_UNSETENV)
|
||||
check_function_exists(setlocale HAVE_SETLOCALE)
|
||||
check_function_exists(setpriority HAVE_SETPRIORITY)
|
||||
check_function_exists(shmget HAVE_SHMGET)
|
||||
|
@@ -118,17 +118,21 @@ if TERM_NONE
|
||||
src_mpg123_SOURCES += src/term_none.c
|
||||
endif
|
||||
|
||||
if NET123
|
||||
src_mpg123_SOURCES += src/net123.h
|
||||
endif
|
||||
|
||||
if NET123_EXEC
|
||||
src_mpg123_SOURCES += src/net123.h src/net123_exec.c
|
||||
src_mpg123_SOURCES += src/net123_exec.c
|
||||
endif
|
||||
|
||||
if NET123_WINHTTP
|
||||
src_mpg123_SOURCES += src/net123.h src/net123_winhttp.c
|
||||
src_mpg123_SOURCES += src/net123_winhttp.c
|
||||
src_mpg123_LDADD += -lwinhttp
|
||||
endif
|
||||
|
||||
if NET123_WININET
|
||||
src_mpg123_SOURCES += src/net123.h src/net123_wininet.c
|
||||
src_mpg123_SOURCES += src/net123_wininet.c
|
||||
src_mpg123_LDADD += -lwininet
|
||||
endif
|
||||
|
||||
|
@@ -179,7 +179,6 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
|
||||
off_t rframes;
|
||||
int spf;
|
||||
double basevol, realvol;
|
||||
char *icy;
|
||||
long rate;
|
||||
int framesize;
|
||||
struct mpg123_frameinfo mi;
|
||||
|
@@ -751,7 +751,6 @@ int control_generic (mpg123_handle *fr)
|
||||
/* Simple EQ: SEQ <BASS> <MID> <TREBLE> */
|
||||
if (!strcasecmp(cmd, "SEQ")) {
|
||||
double b,m,t;
|
||||
int cn;
|
||||
if(sscanf(arg, "%lf %lf %lf", &b, &m, &t) == 3)
|
||||
{
|
||||
mpg123_eq_bands(fr, MPG123_LR, 0, 0, b);
|
||||
|
287
src/httpget.c
287
src/httpget.c
@@ -153,74 +153,6 @@ debunk_result:
|
||||
|
||||
|
||||
#ifdef NETWORK
|
||||
#if !defined (WANT_WIN32_SOCKETS)
|
||||
static int writestring (int fd, mpg123_string *string)
|
||||
{
|
||||
size_t result, bytes;
|
||||
char *ptr = string->p;
|
||||
bytes = string->fill ? string->fill-1 : 0;
|
||||
|
||||
while(bytes)
|
||||
{
|
||||
result = write(fd, ptr, bytes);
|
||||
if(result < 0 && errno != EINTR)
|
||||
{
|
||||
merror("writing http string: %s", strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
else if(result == 0)
|
||||
{
|
||||
error("write: socket closed unexpectedly");
|
||||
return FALSE;
|
||||
}
|
||||
ptr += result;
|
||||
bytes -= result;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static size_t readstring (mpg123_string *string, size_t maxlen, int fd)
|
||||
{
|
||||
int err;
|
||||
debug2("Attempting readstring on %d for %"SIZE_P" bytes", fd, (size_p)maxlen);
|
||||
string->fill = 0;
|
||||
while(maxlen == 0 || string->fill < maxlen)
|
||||
{
|
||||
if(string->size-string->fill < 1)
|
||||
if(!mpg123_grow_string(string, string->fill+4096))
|
||||
{
|
||||
error("Cannot allocate memory for reading.");
|
||||
string->fill = 0;
|
||||
return 0;
|
||||
}
|
||||
err = read(fd,string->p+string->fill,1);
|
||||
/* Whoa... reading one byte at a time... one could ensure the line break in another way, but more work. */
|
||||
if( err == 1)
|
||||
{
|
||||
string->fill++;
|
||||
if(string->p[string->fill-1] == '\n') break;
|
||||
}
|
||||
else if(errno != EINTR)
|
||||
{
|
||||
error("Error reading from socket or unexpected EOF.");
|
||||
string->fill = 0;
|
||||
/* bail out to prevent endless loop */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mpg123_grow_string(string, string->fill+1))
|
||||
{
|
||||
string->fill=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
string->p[string->fill] = 0;
|
||||
string->fill++;
|
||||
}
|
||||
return string->fill;
|
||||
}
|
||||
#endif /* WANT_WIN32_SOCKETS */
|
||||
|
||||
void encode64 (char *source,char *destination)
|
||||
{
|
||||
@@ -383,11 +315,10 @@ int translate_url(const char *url, mpg123_string *purl)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, int *try_without_port)
|
||||
int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, const char * const *client_head)
|
||||
{
|
||||
char* ttemp;
|
||||
int ret = TRUE;
|
||||
const char *icy = param.talk_icy ? icy_yes : icy_no;
|
||||
|
||||
/* hm, my test redirection had troubles with line break before HTTP/1.0 */
|
||||
if((ttemp = strchr(request->p,'\r')) != NULL){ *ttemp = 0; request->fill = ttemp-request->p+1; }
|
||||
@@ -405,26 +336,14 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por
|
||||
if(host->fill)
|
||||
{ /* Give virtual hosting a chance... adding the "Host: ... " line. */
|
||||
debug2("Host: %s:%s", host->p, port->p);
|
||||
if( mpg123_add_string(request, "Host: ")
|
||||
if(!( mpg123_add_string(request, "Host: ")
|
||||
&& mpg123_add_string(request, host->p)
|
||||
&& ( *try_without_port || (
|
||||
mpg123_add_string(request, ":")
|
||||
&& mpg123_add_string(request, port->p) ))
|
||||
&& mpg123_add_string(request, "\r\n") )
|
||||
{
|
||||
if(*try_without_port) *try_without_port = 0;
|
||||
}
|
||||
else return FALSE;
|
||||
&& mpg123_add_string(request, ":")
|
||||
&& mpg123_add_string(request, port->p)
|
||||
&& mpg123_add_string(request, "\r\n") ))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Acceptance, stream setup. */
|
||||
if( !append_accept(request)
|
||||
|| !mpg123_add_string(request, "\r\n")
|
||||
|| !mpg123_add_string(request, CONN_HEAD)
|
||||
|| !mpg123_add_string(request, icy)
|
||||
|| !mpg123_add_string(request, "\r\n") )
|
||||
return FALSE;
|
||||
|
||||
/* Authorization. */
|
||||
if (httpauth1->fill || param.httpauth) {
|
||||
char *buf;
|
||||
@@ -456,72 +375,30 @@ int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *por
|
||||
|
||||
free(buf); /* Watch out for leaking if you introduce returns before this line. */
|
||||
}
|
||||
while(ret && *client_head)
|
||||
{
|
||||
ret = mpg123_add_string(request, *client_head);
|
||||
if(ret)
|
||||
ret = mpg123_add_string(request, "\r\n");
|
||||
++client_head;
|
||||
}
|
||||
if(ret) ret = mpg123_add_string(request, "\r\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#if !defined (WANT_WIN32_SOCKETS)
|
||||
static int resolve_redirect(mpg123_string *response, mpg123_string *request_url, mpg123_string *purl)
|
||||
{
|
||||
debug1("request_url:%s", request_url->p);
|
||||
/* initialized with full old url */
|
||||
if(!mpg123_copy_string(request_url, purl)) return FALSE;
|
||||
|
||||
/* We may strip it down to a prefix ot totally. */
|
||||
if(strncasecmp(response->p, "Location: http://", 17))
|
||||
{ /* OK, only partial strip, need prefix for relative path. */
|
||||
char* ptmp = NULL;
|
||||
/* though it's not RFC (?), accept relative URIs as wget does */
|
||||
fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n");
|
||||
/* not absolute uri, could still be server-absolute */
|
||||
/* I prepend a part of the request... out of the request */
|
||||
if(response->p[10] == '/')
|
||||
{
|
||||
/* only prepend http://server/ */
|
||||
/* I null the first / after http:// */
|
||||
ptmp = strchr(purl->p+7,'/');
|
||||
if(ptmp != NULL){ purl->fill = ptmp-purl->p+1; purl->p[purl->fill-1] = 0; }
|
||||
}
|
||||
else
|
||||
{
|
||||
/* prepend http://server/path/ */
|
||||
/* now we want the last / */
|
||||
ptmp = strrchr(purl->p+7, '/');
|
||||
if(ptmp != NULL){ purl->fill = ptmp-purl->p+2; purl->p[purl->fill-1] = 0; }
|
||||
}
|
||||
}
|
||||
else purl->fill = 0;
|
||||
|
||||
debug1("prefix=%s", purl->fill ? purl->p : "");
|
||||
if(!mpg123_add_string(purl, response->p+10)) return FALSE;
|
||||
|
||||
debug1(" purl: %s", purl->p);
|
||||
debug1("old request_url: %s", request_url->p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int http_open(const char* url, struct httpdata *hd)
|
||||
int http_open(const char* url, struct httpdata *hd, const char * const *client_head)
|
||||
{
|
||||
mpg123_string purl, host, port, path;
|
||||
mpg123_string request, response, request_url;
|
||||
mpg123_string request, request_url;
|
||||
mpg123_string httpauth1;
|
||||
int sock = -1;
|
||||
int oom = 0;
|
||||
int relocate, numrelocs = 0;
|
||||
int got_location = FALSE;
|
||||
/*
|
||||
workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls
|
||||
this site's apache gives me a relocation to the same place when I give the port in Host request field
|
||||
for the record: Apache/2.0.51 (Fedora)
|
||||
*/
|
||||
int try_without_port = 0;
|
||||
mpg123_init_string(&purl);
|
||||
mpg123_init_string(&host);
|
||||
mpg123_init_string(&port);
|
||||
mpg123_init_string(&path);
|
||||
mpg123_init_string(&request);
|
||||
mpg123_init_string(&response);
|
||||
mpg123_init_string(&request_url);
|
||||
mpg123_init_string(&httpauth1);
|
||||
|
||||
@@ -533,26 +410,6 @@ int http_open(const char* url, struct httpdata *hd)
|
||||
/* Don't confuse the different auth strings... */
|
||||
if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; }
|
||||
|
||||
/* "GET http://" 11
|
||||
* " HTTP/1.0\r\nUser-Agent: <PACKAGE_NAME>/<PACKAGE_VERSION>\r\n"
|
||||
* 26 + PACKAGE_NAME + PACKAGE_VERSION
|
||||
* accept header + accept_length()
|
||||
* "Authorization: Basic \r\n" 23
|
||||
* "\r\n" 2
|
||||
* ... plus the other predefined header lines
|
||||
*/
|
||||
/* Just use this estimate as first guess to reduce malloc calls in string library. */
|
||||
{
|
||||
size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION)
|
||||
+ accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill;
|
||||
if( !mpg123_grow_string(&request, length_estimate)
|
||||
|| !mpg123_grow_string(&response,4096) )
|
||||
{
|
||||
oom=1; goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Storing the request url, with http:// prepended if needed. */
|
||||
/* used to be url here... seemed wrong to me (when loop advanced...) */
|
||||
@@ -585,7 +442,7 @@ int http_open(const char* url, struct httpdata *hd)
|
||||
}
|
||||
}
|
||||
|
||||
if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; }
|
||||
if(!fill_request(&request, &host, &port, &httpauth1, client_head)){ oom=1; goto exit; }
|
||||
|
||||
httpauth1.fill = 0; /* We use the auth data from the URL only once. */
|
||||
if (hd->proxystate >= PROXY_HOST)
|
||||
@@ -599,105 +456,27 @@ int http_open(const char* url, struct httpdata *hd)
|
||||
}
|
||||
}
|
||||
debug2("attempting to open_connection to %s:%s", host.p, port.p);
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
sock = win32_net_open_connection(&host, &port);
|
||||
#else
|
||||
sock = open_connection(&host, &port);
|
||||
#endif
|
||||
if(sock < 0)
|
||||
{
|
||||
error1("Unable to establish connection to %s", host.fill ? host.p : "");
|
||||
goto exit;
|
||||
}
|
||||
#define http_failure close(sock); sock=-1; goto exit;
|
||||
|
||||
|
||||
if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p);
|
||||
if(!writestring(sock, &request)){ http_failure; }
|
||||
relocate = FALSE;
|
||||
/* Arbitrary length limit here... */
|
||||
#define safe_readstring \
|
||||
readstring(&response, SIZE_MAX/16, sock); \
|
||||
if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \
|
||||
{ \
|
||||
error("HTTP response line exceeds max. length"); \
|
||||
http_failure; \
|
||||
} \
|
||||
else if(response.fill == 0) \
|
||||
{ \
|
||||
error("readstring failed"); \
|
||||
http_failure; \
|
||||
} \
|
||||
if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p);
|
||||
safe_readstring;
|
||||
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if(!win32_net_writestring (sock, &request))
|
||||
#else
|
||||
if(unintr_write(sock, request.p, request.fill-1) != request.fill-1)
|
||||
#endif
|
||||
{
|
||||
char *sptr;
|
||||
if((sptr = strchr(response.p, ' ')))
|
||||
{
|
||||
if(response.fill > sptr-response.p+2)
|
||||
switch (sptr[1])
|
||||
{
|
||||
case '3':
|
||||
relocate = TRUE;
|
||||
case '2':
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */
|
||||
http_failure;
|
||||
}
|
||||
else{ error("Too short response,"); http_failure; }
|
||||
}
|
||||
http_failure;
|
||||
}
|
||||
|
||||
/* If we are relocated, we need to look out for a Location header. */
|
||||
got_location = FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */
|
||||
if (!strncasecmp(response.p, "Location: ", 10))
|
||||
{ /* It is a redirection! */
|
||||
if(!resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; }
|
||||
|
||||
if(!strcmp(purl.p, request_url.p))
|
||||
{
|
||||
warning("relocated to very same place! trying request again without host port");
|
||||
try_without_port = 1;
|
||||
}
|
||||
got_location = TRUE;
|
||||
}
|
||||
else
|
||||
{ /* We got a header line (or the closing empty line). */
|
||||
char *tmp;
|
||||
debug1("searching for header values... %s", response.p);
|
||||
/* Not sure if I want to bail out on error here. */
|
||||
/* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */
|
||||
get_header_string(&response, "content-type", &hd->content_type);
|
||||
get_header_string(&response, "icy-name", &hd->icy_name);
|
||||
get_header_string(&response, "icy-url", &hd->icy_url);
|
||||
|
||||
/* watch out for icy-metaint */
|
||||
if((tmp = get_header_val("icy-metaint", &response)))
|
||||
{
|
||||
hd->icy_interval = (off_t) atol(tmp); /* atoll ? */
|
||||
debug1("got icy-metaint %li", (long int)hd->icy_interval);
|
||||
}
|
||||
}
|
||||
} while(response.p[0] != '\r' && response.p[0] != '\n');
|
||||
if(relocate)
|
||||
{
|
||||
close(sock);
|
||||
sock = -1;
|
||||
/* Forget content type, might just relate to a displayed error page,
|
||||
not the resource being redirected to. */
|
||||
mpg123_free_string(&hd->content_type);
|
||||
mpg123_init_string(&hd->content_type);
|
||||
}
|
||||
} while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS);
|
||||
if(relocate)
|
||||
{
|
||||
if(!got_location)
|
||||
error("Server meant to redirect but failed to provide a location!");
|
||||
else
|
||||
error1("Too many HTTP relocations (%i).", numrelocs);
|
||||
|
||||
http_failure;
|
||||
}
|
||||
|
||||
exit: /* The end as well as the exception handling point... */
|
||||
@@ -708,22 +487,10 @@ exit: /* The end as well as the exception handling point... */
|
||||
mpg123_free_string(&port);
|
||||
mpg123_free_string(&path);
|
||||
mpg123_free_string(&request);
|
||||
mpg123_free_string(&response);
|
||||
mpg123_free_string(&request_url);
|
||||
mpg123_free_string(&httpauth1);
|
||||
return sock;
|
||||
}
|
||||
#endif /*WANT_WIN32_SOCKETS*/
|
||||
|
||||
#else /* NETWORK */
|
||||
|
||||
/* stub */
|
||||
int http_open (const char* url, struct httpdata *hd)
|
||||
{
|
||||
if(!param.quiet)
|
||||
error("HTTP support not built in.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
|
@@ -49,20 +49,17 @@ int debunk_mime(const char* mime);
|
||||
int proxy_init(struct httpdata *hd);
|
||||
int translate_url(const char *url, mpg123_string *purl);
|
||||
size_t accept_length(void);
|
||||
int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, int *try_without_port);
|
||||
int fill_request(mpg123_string *request, mpg123_string *host, mpg123_string *port, mpg123_string *httpauth1, const char * const *client_head);
|
||||
void get_header_string(mpg123_string *response, const char *fieldname, mpg123_string *store);
|
||||
char *get_header_val(const char *hname, mpg123_string *response);
|
||||
|
||||
/* needed for HTTP/1.1 non-pipelining mode */
|
||||
/* #define CONN_HEAD "Connection: close\r\n" */
|
||||
#define CONN_HEAD ""
|
||||
#define icy_yes "Icy-MetaData: 1"
|
||||
#define icy_no "Icy-MetaData: 0"
|
||||
|
||||
// Append an accept header line to the string, without line end.
|
||||
int append_accept(mpg123_string *s);
|
||||
|
||||
/* takes url and content type string address, opens resource, returns fd for data, allocates and sets content type */
|
||||
extern int http_open (const char* url, struct httpdata *hd);
|
||||
// Open HTTP URL with internal network code.
|
||||
int http_open(const char* url, struct httpdata *hd, const char * const *client_head);
|
||||
|
||||
#endif
|
||||
|
@@ -45,7 +45,7 @@ int utf8force = 0; // enforce UTF-8 workings
|
||||
int utf8env = 0; // produce UTF-8 text output
|
||||
int utf8loc = 0; // have actual UTF-8 locale (so that mbstowcs() works)
|
||||
|
||||
static int term_is_fun = -1;
|
||||
//static int term_is_fun = -1;
|
||||
|
||||
static const char joker_symbol = '?';
|
||||
static const char *uni_repl = "\xef\xbf\xbd";
|
||||
|
10
src/mpg123.c
10
src/mpg123.c
@@ -483,7 +483,7 @@ static void set_appflag(char *arg, topt *opts)
|
||||
#if defined(NETWORK) || defined(NET123)
|
||||
static void set_httpauth(char *arg, topt *opts)
|
||||
{
|
||||
param.httpauth = strdup(arg);
|
||||
param.httpauth = compat_strdup(arg);
|
||||
// Do not advertise the password for all system users.
|
||||
memset(arg, 'x', strlen(arg));
|
||||
}
|
||||
@@ -1599,14 +1599,13 @@ static void long_usage(int err)
|
||||
fprintf(o," -y --no-resync DISABLES resync on error (--resync is deprecated)\n");
|
||||
fprintf(o," -F --no-frankenstein disable support for Frankenstein streams\n");
|
||||
#if defined(NETWORK) || defined(NET123)
|
||||
#ifdef NETWORK
|
||||
fprintf(o," -p <f> --proxy <f> set WWW proxy\n");
|
||||
#else
|
||||
fprintf(o," -p <f> --proxy <f> override proxy environemnt variable for plain HTTP\n");
|
||||
fprintf(o," --network <b> select network backend, available: auto");
|
||||
const char **nb = net123_backends;
|
||||
while(*nb){ fprintf(o, " %s", *nb++); }
|
||||
fprintf(o, "\n");
|
||||
#endif
|
||||
fprintf(o," (auto meaning internal code for plain HTTP and the\n");
|
||||
fprintf(o," first external option for HTTPS)\n");
|
||||
fprintf(o," -u --auth set auth values for HTTP access\n");
|
||||
fprintf(o," --auth-file set auth values for HTTP access from given file\n");
|
||||
fprintf(o," --ignore-mime ignore HTTP MIME types (content-type)\n");
|
||||
@@ -1635,6 +1634,7 @@ static void long_usage(int err)
|
||||
fprintf(o," --list-devices list the available output devices for given output module\n");
|
||||
fprintf(o," -a <d> --audiodevice <d> select audio device (depending on chosen module)\n");
|
||||
fprintf(o," -s --stdout write raw audio to stdout (host native format)\n");
|
||||
fprintf(o," -O <f> --outfile <f> write raw audio to given file (- is stdout)\n");
|
||||
fprintf(o," -w <f> --wav <f> write samples as WAV file in <f> (- is stdout)\n");
|
||||
fprintf(o," --au <f> write samples as Sun AU file in <f> (- is stdout)\n");
|
||||
fprintf(o," --cdr <f> write samples as raw CD audio file in <f> (- is stdout)\n");
|
||||
|
33
src/net123.h
33
src/net123.h
@@ -39,12 +39,17 @@
|
||||
#ifndef _MPG123_NET123_H_
|
||||
#define _MPG123_NET123_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
// The network implementation defines the struct for private use.
|
||||
// The purpose is just to keep enough context to be able to
|
||||
// call net123_read() and net123_close() afterwards.
|
||||
struct net123_handle_struct;
|
||||
// stream handle for differing implementations, build-time plugins
|
||||
struct net123_handle_struct
|
||||
{
|
||||
void *parts; // custom internal data
|
||||
// callbacks
|
||||
size_t (*read)(struct net123_handle_struct *nh, void *buf, size_t bufsize);
|
||||
void (*close)(struct net123_handle_struct *nh);
|
||||
};
|
||||
typedef struct net123_handle_struct net123_handle;
|
||||
|
||||
extern const char *net123_backends[];
|
||||
@@ -54,16 +59,16 @@ extern const char *net123_backends[];
|
||||
// and then the raw data.
|
||||
// client_head contains header lines to send with the request, without
|
||||
// line ending
|
||||
net123_handle *net123_open(const char *url, const char * const *client_head);
|
||||
|
||||
// Read data into buffer, return bytes read.
|
||||
// This handles interrupts (EAGAIN, EINTR, ..) internally and only returns
|
||||
// a short byte count on EOF or error. End of file or error is not distinguished:
|
||||
// For the user, it only matters if there will be more bytes or not.
|
||||
// Feel free to communicate errors via error() / merror() functions inside.
|
||||
size_t net123_read(net123_handle *nh, void *buf, size_t bufsize);
|
||||
|
||||
// Call that to free up resources, end processes.
|
||||
void net123_close(net123_handle *nh);
|
||||
// Variant for the external binding.
|
||||
#ifdef NET123_EXEC
|
||||
net123_handle *net123_open_exec(const char *url, const char * const *client_head);
|
||||
#endif
|
||||
#ifdef NET123_WININET
|
||||
net123_handle *net123_open_wininet(const char *url, const char * const *client_head);
|
||||
#endif
|
||||
#ifdef NET123_WINHTTP
|
||||
net123_handle *net123_open_winhttp(const char *url, const char * const *client_head);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -8,6 +8,9 @@
|
||||
specifically if param.network_backend is set accordingly.
|
||||
*/
|
||||
|
||||
// kill
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#include "config.h"
|
||||
#include "net123.h"
|
||||
@@ -34,18 +37,11 @@
|
||||
// wget --user=... --password=...
|
||||
// Alternatively: Have them in .netrc.
|
||||
|
||||
const char *net123_backends[] =
|
||||
{
|
||||
"wget"
|
||||
, "curl"
|
||||
, NULL
|
||||
};
|
||||
|
||||
struct net123_handle_struct
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
pid_t worker;
|
||||
};
|
||||
} exec_handle;
|
||||
|
||||
// Combine two given strings into one newly allocated one.
|
||||
// Use: (--parameter=, value) -> --parameter=value
|
||||
@@ -198,8 +194,6 @@ static char **curl_argv(const char *url, const char * const * client_head)
|
||||
, "--silent"
|
||||
, "--show-error"
|
||||
#endif
|
||||
, "--max-redirs"
|
||||
, "0"
|
||||
, "--dump-header"
|
||||
, "-"
|
||||
};
|
||||
@@ -241,7 +235,36 @@ static char **curl_argv(const char *url, const char * const * client_head)
|
||||
return argv;
|
||||
}
|
||||
|
||||
net123_handle *net123_open(const char *url, const char * const * client_head)
|
||||
|
||||
static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize)
|
||||
{
|
||||
if(!nh || (bufsize && !buf))
|
||||
return 0;
|
||||
return unintr_read(((exec_handle*)nh->parts)->fd, buf, bufsize);
|
||||
}
|
||||
|
||||
static void net123_close(net123_handle *nh)
|
||||
{
|
||||
if(!nh)
|
||||
return;
|
||||
exec_handle *eh = nh->parts;
|
||||
if(eh->worker)
|
||||
{
|
||||
kill(eh->worker, SIGKILL);
|
||||
errno = 0;
|
||||
if(waitpid(eh->worker, NULL, 0) < 0)
|
||||
merror("failed to wait for worker process: %s", strerror(errno));
|
||||
else if(param.verbose > 1)
|
||||
fprintf(stderr, "Note: network helper %"PRIiMAX" finished\n", (intmax_t)eh->worker);
|
||||
}
|
||||
if(eh->fd > -1)
|
||||
close(eh->fd);
|
||||
free(nh->parts);
|
||||
free(nh);
|
||||
}
|
||||
|
||||
|
||||
net123_handle *net123_open_exec(const char *url, const char * const * client_head)
|
||||
{
|
||||
int use_curl = 0;
|
||||
char * const curl_check_argv[] = { "curl", "--help", "all", NULL };
|
||||
@@ -278,12 +301,21 @@ net123_handle *net123_open(const char *url, const char * const * client_head)
|
||||
}
|
||||
|
||||
int fd[2];
|
||||
int hi = -1; // index of header value that might get a continuation line
|
||||
net123_handle *nh = malloc(sizeof(net123_handle));
|
||||
if(!nh)
|
||||
exec_handle *eh = malloc(sizeof(exec_handle));
|
||||
if(!nh || !eh)
|
||||
{
|
||||
if(nh)
|
||||
free(nh);
|
||||
if(eh)
|
||||
free(eh);
|
||||
return NULL;
|
||||
nh->fd = -1;
|
||||
nh->worker = 0;
|
||||
}
|
||||
nh->parts = eh;
|
||||
nh->read = net123_read;
|
||||
nh->close = net123_close;
|
||||
eh->fd = -1;
|
||||
eh->worker = 0;
|
||||
errno = 0;
|
||||
if(pipe(fd))
|
||||
{
|
||||
@@ -295,15 +327,15 @@ net123_handle *net123_open(const char *url, const char * const * client_head)
|
||||
compat_binmode(fd[0], TRUE);
|
||||
compat_binmode(fd[1], TRUE);
|
||||
|
||||
nh->worker = fork();
|
||||
if(nh->worker == -1)
|
||||
eh->worker = fork();
|
||||
if(eh->worker == -1)
|
||||
{
|
||||
merror("fork failed: %s", strerror(errno));
|
||||
free(nh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(nh->worker == 0)
|
||||
if(eh->worker == 0)
|
||||
{
|
||||
close(fd[0]);
|
||||
dup2(fd[1], STDOUT_FILENO);
|
||||
@@ -311,7 +343,6 @@ net123_handle *net123_open(const char *url, const char * const * client_head)
|
||||
dup2(infd, STDIN_FILENO);
|
||||
// child
|
||||
// Proxy environment variables can just be set in the user and inherited here, right?
|
||||
int argc;
|
||||
|
||||
char **argv = use_curl ? curl_argv(url, client_head) : wget_argv(url, client_head);
|
||||
if(!argv)
|
||||
@@ -340,35 +371,9 @@ net123_handle *net123_open(const char *url, const char * const * client_head)
|
||||
}
|
||||
// parent
|
||||
if(param.verbose > 1)
|
||||
fprintf(stderr, "Note: started network helper with PID %"PRIiMAX"\n", (intmax_t)nh->worker);
|
||||
fprintf(stderr, "Note: started network helper with PID %"PRIiMAX"\n", (intmax_t)eh->worker);
|
||||
errno = 0;
|
||||
close(fd[1]);
|
||||
nh->fd = fd[0];
|
||||
eh->fd = fd[0];
|
||||
return nh;
|
||||
}
|
||||
|
||||
size_t net123_read(net123_handle *nh, void *buf, size_t bufsize)
|
||||
{
|
||||
if(!nh || (bufsize && !buf))
|
||||
return 0;
|
||||
return unintr_read(nh->fd, buf, bufsize);
|
||||
}
|
||||
|
||||
void net123_close(net123_handle *nh)
|
||||
{
|
||||
if(!nh)
|
||||
return;
|
||||
if(nh->worker)
|
||||
{
|
||||
kill(nh->worker, SIGKILL);
|
||||
errno = 0;
|
||||
if(waitpid(nh->worker, NULL, 0) < 0)
|
||||
merror("failed to wait for worker process: %s", strerror(errno));
|
||||
else if(param.verbose > 1)
|
||||
fprintf(stderr, "Note: network helper %"PRIiMAX" finished\n", (intmax_t)nh->worker);
|
||||
}
|
||||
if(nh->fd > -1)
|
||||
close(nh->fd);
|
||||
free(nh);
|
||||
}
|
||||
|
||||
|
@@ -5,13 +5,11 @@
|
||||
#include <ws2tcpip.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
const char *net123_backends[] = { "(always winhttp)", NULL };
|
||||
|
||||
// The network implementation defines the struct for private use.
|
||||
// The purpose is just to keep enough context to be able to
|
||||
// call net123_read() and net123_close() afterwards.
|
||||
#define URL_COMPONENTS_LENGTH 255
|
||||
struct net123_handle_struct {
|
||||
typedef struct {
|
||||
HINTERNET session;
|
||||
HINTERNET connect;
|
||||
HINTERNET request;
|
||||
@@ -26,7 +24,7 @@ struct net123_handle_struct {
|
||||
size_t headers_pos, headers_len;
|
||||
DWORD internetStatus, internetStatusLength;
|
||||
LPVOID additionalInfo;
|
||||
};
|
||||
} winhttp_handle;
|
||||
|
||||
#define MPG123CONCAT_(x,y) x ## y
|
||||
#define MPG123CONCAT(x,y) MPG123CONCAT_(x,y)
|
||||
@@ -34,7 +32,7 @@ struct net123_handle_struct {
|
||||
#define MPG123STRINGIFY(x) MPG123STRINGIFY_(x)
|
||||
#define MPG123WSTR(x) MPG123CONCAT(L,MPG123STRINGIFY(x))
|
||||
|
||||
static DWORD wrap_auth(net123_handle *nh){
|
||||
static DWORD wrap_auth(winhttp_handle *nh){
|
||||
DWORD mode;
|
||||
DWORD ret;
|
||||
|
||||
@@ -81,13 +79,16 @@ static void debug_crack(URL_COMPONENTS *comps){}
|
||||
|
||||
static
|
||||
void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){
|
||||
net123_handle *nh = (net123_handle *)dwContext;
|
||||
winhttp_handle *nh = (winhttp_handle *)dwContext;
|
||||
nh->internetStatus = dwInternetStatus;
|
||||
nh->additionalInfo = lpvStatusInformation;
|
||||
nh->internetStatusLength = dwStatusInformationLength;
|
||||
}
|
||||
|
||||
net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize);
|
||||
static void net123_close(net123_handle *nh);
|
||||
|
||||
net123_handle *net123_open_winhttp(const char *url, const char * const *client_head){
|
||||
LPWSTR urlW = NULL, headers = NULL;
|
||||
size_t ii;
|
||||
WINBOOL res;
|
||||
@@ -101,8 +102,18 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
win32_utf8_wide(url, &urlW, NULL);
|
||||
if(urlW == NULL) goto cleanup;
|
||||
|
||||
net123_handle *ret = calloc(1, sizeof(net123_handle));
|
||||
if (!ret) return ret;
|
||||
winhttp_handle *ret = calloc(1, sizeof(winhttp_handle));
|
||||
if (!ret) goto cleanup;
|
||||
|
||||
net123_handle *handle = calloc(1, sizeof(net123_handle));
|
||||
if (!handle) {
|
||||
free(ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
handle->parts = ret;
|
||||
handle->read = net123_read;
|
||||
handle->close = net123_close;
|
||||
|
||||
ret->comps.dwStructSize = sizeof(ret->comps);
|
||||
ret->comps.dwSchemeLength = 0;
|
||||
@@ -206,13 +217,13 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
}
|
||||
debug("net123_open OK");
|
||||
|
||||
return ret;
|
||||
return handle;
|
||||
cleanup:
|
||||
debug("net123_open error");
|
||||
if (urlW) free(urlW);
|
||||
net123_close(ret);
|
||||
ret = NULL;
|
||||
return ret;
|
||||
net123_close(handle);
|
||||
handle = NULL;
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Read data into buffer, return bytes read.
|
||||
@@ -221,20 +232,21 @@ cleanup:
|
||||
// For the user, it only matters if there will be more bytes or not.
|
||||
// Feel free to communicate errors via error() / merror() functions inside.
|
||||
size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
|
||||
winhttp_handle *h = nh->parts;
|
||||
size_t ret;
|
||||
size_t to_copy = nh->headers_len - nh->headers_pos;
|
||||
size_t to_copy = h->headers_len - h->headers_pos;
|
||||
DWORD bytesread = 0;
|
||||
|
||||
if(to_copy){
|
||||
ret = to_copy <= bufsize ? to_copy : bufsize;
|
||||
memcpy(buf, nh->headers + nh->headers_pos, ret);
|
||||
nh->headers_pos += ret;
|
||||
memcpy(buf, h->headers + h->headers_pos, ret);
|
||||
h->headers_pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* is this needed? */
|
||||
to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize;
|
||||
if(!WinHttpReadData(nh->request, buf, to_copy, &bytesread)){
|
||||
if(!WinHttpReadData(h->request, buf, to_copy, &bytesread)){
|
||||
return EOF;
|
||||
}
|
||||
return bytesread;
|
||||
@@ -242,21 +254,26 @@ size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
|
||||
|
||||
// Call that to free up resources, end processes.
|
||||
void net123_close(net123_handle *nh){
|
||||
if(nh->headers) {
|
||||
free(nh->headers);
|
||||
nh->headers = NULL;
|
||||
}
|
||||
if(nh->request) {
|
||||
WinHttpCloseHandle(nh->request);
|
||||
nh->request = NULL;
|
||||
}
|
||||
if(nh->connect) {
|
||||
WinHttpCloseHandle(nh->connect);
|
||||
nh->connect = NULL;
|
||||
}
|
||||
if(nh->session) {
|
||||
WinHttpCloseHandle(nh->session);
|
||||
nh->session = NULL;
|
||||
if (!nh) return;
|
||||
winhttp_handle *h = nh->parts;
|
||||
if(h) {
|
||||
if(h->headers) {
|
||||
free(h->headers);
|
||||
h->headers = NULL;
|
||||
}
|
||||
if(h->request) {
|
||||
WinHttpCloseHandle(h->request);
|
||||
h->request = NULL;
|
||||
}
|
||||
if(h->connect) {
|
||||
WinHttpCloseHandle(h->connect);
|
||||
h->connect = NULL;
|
||||
}
|
||||
if(h->session) {
|
||||
WinHttpCloseHandle(h->session);
|
||||
h->session = NULL;
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
free(nh);
|
||||
}
|
||||
|
@@ -5,13 +5,11 @@
|
||||
#include <ws2tcpip.h>
|
||||
#include <wininet.h>
|
||||
|
||||
const char *net123_backends[] = { "(always wininet)", NULL };
|
||||
|
||||
// The network implementation defines the struct for private use.
|
||||
// The purpose is just to keep enough context to be able to
|
||||
// call net123_read() and net123_close() afterwards.
|
||||
#define URL_COMPONENTS_LENGTH 255
|
||||
struct net123_handle_struct {
|
||||
typedef struct {
|
||||
HINTERNET session;
|
||||
HINTERNET connect;
|
||||
HINTERNET request;
|
||||
@@ -28,7 +26,7 @@ struct net123_handle_struct {
|
||||
DWORD HttpQueryInfoIndex;
|
||||
DWORD internetStatus, internetStatusLength;
|
||||
LPVOID additionalInfo;
|
||||
};
|
||||
} wininet_handle;
|
||||
|
||||
#define MPG123CONCAT_(x,y) x ## y
|
||||
#define MPG123CONCAT(x,y) MPG123CONCAT_(x,y)
|
||||
@@ -60,13 +58,17 @@ static void debug_crack(URL_COMPONENTSW *comps){}
|
||||
|
||||
static
|
||||
void WINAPI net123_ssl_errors(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength){
|
||||
net123_handle *nh = (net123_handle *)dwContext;
|
||||
debug("In net123_ssl_errors");
|
||||
wininet_handle *nh = (wininet_handle *)(dwContext);
|
||||
nh->internetStatus = dwInternetStatus;
|
||||
nh->additionalInfo = lpvStatusInformation;
|
||||
nh->internetStatusLength = dwStatusInformationLength;
|
||||
}
|
||||
|
||||
net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize);
|
||||
static void net123_close(net123_handle *nh);
|
||||
|
||||
net123_handle *net123_open_wininet(const char *url, const char * const *client_head){
|
||||
LPWSTR urlW = NULL, headers = NULL;
|
||||
size_t ii;
|
||||
WINBOOL res;
|
||||
@@ -78,51 +80,63 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
if(urlW == NULL) goto cleanup;
|
||||
|
||||
net123_handle *ret = calloc(1, sizeof(net123_handle));
|
||||
if (!ret) return ret;
|
||||
wininet_handle *wh = calloc(1, sizeof(wininet_handle));
|
||||
if(!ret || !wh)
|
||||
{
|
||||
if(ret)
|
||||
free(ret);
|
||||
if(wh)
|
||||
free(wh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->comps.dwStructSize = sizeof(ret->comps);
|
||||
ret->comps.dwSchemeLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.dwUserNameLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.dwPasswordLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.dwHostNameLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.dwUrlPathLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.dwExtraInfoLength = URL_COMPONENTS_LENGTH - 1;
|
||||
ret->comps.lpszHostName = ret->lpszHostName;
|
||||
ret->comps.lpszUserName = ret->lpszUserName;
|
||||
ret->comps.lpszPassword = ret->lpszPassword;
|
||||
ret->comps.lpszUrlPath = ret->lpszUrlPath;
|
||||
ret->comps.lpszExtraInfo = ret->lpszExtraInfo;
|
||||
ret->comps.lpszScheme = ret->lpszScheme;
|
||||
ret->parts = wh;
|
||||
ret->read = net123_read;
|
||||
ret->close = net123_close;
|
||||
|
||||
wh->comps.dwStructSize = sizeof(wh->comps);
|
||||
wh->comps.dwSchemeLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.dwUserNameLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.dwPasswordLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.dwHostNameLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.dwUrlPathLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.dwExtraInfoLength = URL_COMPONENTS_LENGTH - 1;
|
||||
wh->comps.lpszHostName = wh->lpszHostName;
|
||||
wh->comps.lpszUserName = wh->lpszUserName;
|
||||
wh->comps.lpszPassword = wh->lpszPassword;
|
||||
wh->comps.lpszUrlPath = wh->lpszUrlPath;
|
||||
wh->comps.lpszExtraInfo = wh->lpszExtraInfo;
|
||||
wh->comps.lpszScheme = wh->lpszScheme;
|
||||
|
||||
debug1("net123_open start crack %S", urlW);
|
||||
|
||||
if(!(res = InternetCrackUrlW(urlW, 0, 0, &ret->comps))) {
|
||||
if(!(res = InternetCrackUrlW(urlW, 0, 0, &wh->comps))) {
|
||||
debug1("net123_open crack fail %lu", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
debug("net123_open crack OK");
|
||||
debug_crack(&ret->comps);
|
||||
debug_crack(&wh->comps);
|
||||
|
||||
ret->session = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
||||
wh->session = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
||||
free(urlW);
|
||||
urlW = NULL;
|
||||
debug("net123_open InternetOpenW OK");
|
||||
if(!ret->session) goto cleanup;
|
||||
if(!wh->session) goto cleanup;
|
||||
|
||||
debug2("net123_open InternetConnectW %S %u", ret->comps.lpszHostName, ret->comps.nPort);
|
||||
ret->connect = InternetConnectW(ret->session, ret->comps.lpszHostName, ret->comps.nPort,
|
||||
ret->comps.dwUserNameLength ? ret->comps.lpszUserName : NULL, ret->comps.dwPasswordLength ? ret->comps.lpszPassword : NULL,
|
||||
debug2("net123_open InternetConnectW %S %u", wh->comps.lpszHostName, wh->comps.nPort);
|
||||
wh->connect = InternetConnectW(wh->session, wh->comps.lpszHostName, wh->comps.nPort,
|
||||
wh->comps.dwUserNameLength ? wh->comps.lpszUserName : NULL, wh->comps.dwPasswordLength ? wh->comps.lpszPassword : NULL,
|
||||
INTERNET_SERVICE_HTTP, 0, 0);
|
||||
if(!ret->connect) goto cleanup;
|
||||
if(!wh->connect) goto cleanup;
|
||||
debug("net123_open InternetConnectW OK");
|
||||
|
||||
debug1("HttpOpenRequestW GET %S", ret->comps.lpszUrlPath);
|
||||
ret->request = HttpOpenRequestW(ret->connect, L"GET", ret->comps.lpszUrlPath, NULL, NULL, NULL, ret->comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)ret);
|
||||
if(!ret->request) goto cleanup;
|
||||
debug1("HttpOpenRequestW GET %S", wh->comps.lpszUrlPath);
|
||||
wh->request = HttpOpenRequestW(wh->connect, L"GET", wh->comps.lpszUrlPath, NULL, NULL, NULL, wh->comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, (DWORD_PTR)wh);
|
||||
if(!wh->request) goto cleanup;
|
||||
debug("HttpOpenRequestW GET OK");
|
||||
|
||||
cb = InternetSetStatusCallback(ret->request, (INTERNET_STATUS_CALLBACK)net123_ssl_errors);
|
||||
cb = InternetSetStatusCallback(wh->request, (INTERNET_STATUS_CALLBACK)net123_ssl_errors);
|
||||
if(cb != NULL){
|
||||
error1("InternetSetStatusCallback failed to install callback, errors might not be reported properly! (%lu)", GetLastError());
|
||||
}
|
||||
@@ -132,7 +146,7 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
if(!headers)
|
||||
goto cleanup;
|
||||
debug1("HttpAddRequestHeadersW add %S", headers);
|
||||
res = HttpAddRequestHeadersW(ret->request, headers, (DWORD) -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
|
||||
res = HttpAddRequestHeadersW(wh->request, headers, (DWORD) -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
|
||||
debug2("HttpAddRequestHeadersW returns %u %lu", res, res ? 0 : GetLastError());
|
||||
free(headers);
|
||||
headers = NULL;
|
||||
@@ -140,13 +154,14 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
|
||||
debug("net123_open ADD HEADERS OK");
|
||||
|
||||
res = HttpSendRequestW(ret->request, NULL, 0, NULL, 0);
|
||||
res = HttpSendRequestW(wh->request, NULL, 0, NULL, 0);
|
||||
|
||||
if (!res) {
|
||||
res = GetLastError();
|
||||
error1("HttpSendRequestW failed with %lu", res);
|
||||
goto cleanup;
|
||||
}
|
||||
debug("HttpSendRequestW OK");
|
||||
|
||||
// dummy, cannot be null
|
||||
headers = calloc(1,1);
|
||||
@@ -155,18 +170,20 @@ net123_handle *net123_open(const char *url, const char * const *client_head){
|
||||
error("Cannot allocate dummy buffer for HttpQueryInfoW");
|
||||
goto cleanup;
|
||||
}
|
||||
res = HttpQueryInfoW(ret->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &ret->HttpQueryInfoIndex);
|
||||
debug("Try HttpQueryInfoW pass 1");
|
||||
res = HttpQueryInfoW(wh->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &wh->HttpQueryInfoIndex);
|
||||
free(headers);
|
||||
debug("HttpQueryInfoW pass 1 OK");
|
||||
|
||||
if(!res && GetLastError() == ERROR_INSUFFICIENT_BUFFER && headerlen > 0) {
|
||||
/* buffer size is in bytes, not including terminator */
|
||||
headers = calloc(1, headerlen + sizeof(*headers));
|
||||
if (!headers) goto cleanup;
|
||||
res = HttpQueryInfoW(ret->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &ret->HttpQueryInfoIndex);
|
||||
res = HttpQueryInfoW(wh->request, HTTP_QUERY_RAW_HEADERS_CRLF, headers, &headerlen, &wh->HttpQueryInfoIndex);
|
||||
debug3("HttpQueryInfoW returned %u, err %u : %S", res, GetLastError(), headers ? headers : L"null");
|
||||
win32_wide_utf7(headers, &ret->headers, &ret->headers_len);
|
||||
win32_wide_utf7(headers, &wh->headers, &wh->headers_len);
|
||||
/* bytes written, skip the terminating null, we want to stop at the \r\n\r\n */
|
||||
ret->headers_len --;
|
||||
wh->headers_len --;
|
||||
free(headers);
|
||||
headers = NULL;
|
||||
} else {
|
||||
@@ -184,21 +201,24 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
|
||||
static size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
|
||||
if(!nh || !nh->parts)
|
||||
return 0;
|
||||
wininet_handle *wh = nh->parts;
|
||||
size_t ret;
|
||||
size_t to_copy = nh->headers_len - nh->headers_pos;
|
||||
size_t to_copy = wh->headers_len - wh->headers_pos;
|
||||
DWORD bytesread = 0;
|
||||
|
||||
if(to_copy){
|
||||
ret = to_copy <= bufsize ? to_copy : bufsize;
|
||||
memcpy(buf, nh->headers + nh->headers_pos, ret);
|
||||
nh->headers_pos += ret;
|
||||
memcpy(buf, wh->headers + wh->headers_pos, ret);
|
||||
wh->headers_pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* is this needed? */
|
||||
to_copy = bufsize > ULONG_MAX ? ULONG_MAX : bufsize;
|
||||
if(!InternetReadFile(nh->request, buf, to_copy, &bytesread)){
|
||||
if(!InternetReadFile(wh->request, buf, to_copy, &bytesread)){
|
||||
error1("InternetReadFile exited with %d", GetLastError());
|
||||
return EOF;
|
||||
}
|
||||
@@ -206,22 +226,28 @@ size_t net123_read(net123_handle *nh, void *buf, size_t bufsize){
|
||||
}
|
||||
|
||||
// Call that to free up resources, end processes.
|
||||
void net123_close(net123_handle *nh){
|
||||
if(nh->headers) {
|
||||
free(nh->headers);
|
||||
nh->headers = NULL;
|
||||
static void net123_close(net123_handle *nh){
|
||||
if(!nh)
|
||||
return;
|
||||
wininet_handle *wh = nh->parts;
|
||||
if(!wh) /*???*/
|
||||
return;
|
||||
if(wh->headers) {
|
||||
free(wh->headers);
|
||||
wh->headers = NULL;
|
||||
}
|
||||
if(nh->request) {
|
||||
InternetCloseHandle(nh->request);
|
||||
nh->request = NULL;
|
||||
if(wh->request) {
|
||||
InternetCloseHandle(wh->request);
|
||||
wh->request = NULL;
|
||||
}
|
||||
if(nh->connect) {
|
||||
InternetCloseHandle(nh->connect);
|
||||
nh->connect = NULL;
|
||||
if(wh->connect) {
|
||||
InternetCloseHandle(wh->connect);
|
||||
wh->connect = NULL;
|
||||
}
|
||||
if(nh->session) {
|
||||
InternetCloseHandle(nh->session);
|
||||
nh->session = NULL;
|
||||
if(wh->session) {
|
||||
InternetCloseHandle(wh->session);
|
||||
wh->session = NULL;
|
||||
}
|
||||
free(nh);
|
||||
free(wh);
|
||||
}
|
||||
|
@@ -357,7 +357,8 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
}
|
||||
}
|
||||
pl.entry = 0;
|
||||
if(pl.file && pl.file->network)
|
||||
#ifdef NET123
|
||||
if(pl.file && pl.file->nh)
|
||||
{
|
||||
debug1("htd.content_type.p: %p", (void*) pl.file->htd.content_type.p);
|
||||
if(!APPFLAG(MPG123APP_IGNORE_MIME) && pl.file->htd.content_type.p != NULL)
|
||||
@@ -402,6 +403,7 @@ static int add_next_file (int argc, char *argv[], int args_utf8)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(!pl.file)
|
||||
{
|
||||
param.listname = NULL; // why?
|
||||
|
281
src/streamdump.c
281
src/streamdump.c
@@ -4,11 +4,15 @@
|
||||
This evolved into the generic I/O interposer for direct file or http stream
|
||||
access, with explicit buffering for getline.
|
||||
|
||||
copyright 2010-2019 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
copyright 2010-2022 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Michael Hipp
|
||||
*/
|
||||
|
||||
// setenv
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#include "streamdump.h"
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -22,6 +26,139 @@
|
||||
#define HTTP_MAX_RELOCATIONS 20
|
||||
#endif
|
||||
|
||||
#if defined(NETWORK) && !defined(NET123)
|
||||
#error "NETWORK only with NET123 from now on!"
|
||||
#endif
|
||||
#if !defined(NETWORK) && defined(NET123)
|
||||
#error "NET123 only with NETWORK from now on!"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NETWORK
|
||||
|
||||
const char *net123_backends[] =
|
||||
{
|
||||
"internal"
|
||||
#ifdef NET123_EXEC
|
||||
, "wget"
|
||||
, "curl"
|
||||
#endif
|
||||
#ifdef NET123_WINHTTP
|
||||
, "winhttp"
|
||||
#endif
|
||||
#ifdef NET123_WININET
|
||||
, "wininet"
|
||||
#endif
|
||||
, NULL
|
||||
};
|
||||
|
||||
// Net123 variant for our internal code that has safer legacy support for HTTP shoutcast.
|
||||
|
||||
static size_t net123_read_internal( struct net123_handle_struct *nh,
|
||||
void *buf, size_t bufsize )
|
||||
{
|
||||
if(!nh)
|
||||
return 0;
|
||||
int *fdp = nh->parts;
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
return win32_net_read(*fdp, buf, bufsize);
|
||||
#else
|
||||
return unintr_read(*fdp, buf, bufsize);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void net123_close_internal(struct net123_handle_struct *nh)
|
||||
{
|
||||
if(nh)
|
||||
return;
|
||||
int *fdp = nh->parts;
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if(*fdp != SOCKET_ERROR)
|
||||
win32_net_close(*fdp);
|
||||
#else
|
||||
close(*fdp);
|
||||
#endif
|
||||
free(fdp);
|
||||
free(nh);
|
||||
}
|
||||
|
||||
static net123_handle *net123_open_internal( const char *url
|
||||
, const char * const *client_head, struct httpdata *hd )
|
||||
{
|
||||
net123_handle *nh = malloc(sizeof(net123_handle));
|
||||
if(!nh)
|
||||
return NULL;
|
||||
int *fdp = malloc(sizeof(int));
|
||||
if(!fdp)
|
||||
{
|
||||
free(nh);
|
||||
return NULL;
|
||||
}
|
||||
nh->parts = fdp;
|
||||
nh->read = net123_read_internal;
|
||||
nh->close = net123_close_internal;
|
||||
// Handles win32_net internally.
|
||||
*fdp = http_open(url, hd, client_head);
|
||||
if(*fdp >= 0)
|
||||
return nh;
|
||||
free(fdp);
|
||||
free(nh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Decide which backend to load.
|
||||
static net123_handle *net123_open( const char *url
|
||||
, const char * const *client_head, struct httpdata *hd )
|
||||
{
|
||||
int autochoose = !strcmp("auto", param.network_backend);
|
||||
int https = !strncasecmp("https://", url, 8);
|
||||
if(param.proxyurl)
|
||||
{
|
||||
if(strcmp(param.proxyurl, "none"))
|
||||
{
|
||||
#ifdef HAVE_SETENV
|
||||
setenv("http_proxy", param.proxyurl, 1);
|
||||
setenv("HTTP_PROXY", param.proxyurl, 1);
|
||||
setenv("https_proxy", param.proxyurl, 1);
|
||||
setenv("HTTPS_PROXY", param.proxyurl, 1);
|
||||
#endif
|
||||
} else
|
||||
{
|
||||
#ifdef HAVE_UNSETENV
|
||||
unsetenv("http_proxy");
|
||||
unsetenv("HTTP_PROXY");
|
||||
unsetenv("https_proxy");
|
||||
unsetenv("HTTPS_PROXY");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if( (autochoose && !https)
|
||||
|| !strcmp("internal", param.network_backend) )
|
||||
{
|
||||
if(https && !param.quiet)
|
||||
fprintf(stderr, "Note: HTTPS will fail with internal network code.\n");
|
||||
return net123_open_internal(url, client_head, hd);
|
||||
}
|
||||
#ifdef NET123_EXEC
|
||||
if( autochoose
|
||||
|| !strcmp("wget", param.network_backend)
|
||||
|| !strcmp("curl", param.network_backend) )
|
||||
return net123_open_exec(url, client_head);
|
||||
#endif
|
||||
#ifdef NET123_WINHTTP
|
||||
if(autochoose || !strcmp("winhttp", param.network_backend))
|
||||
return net123_open_winhttp(url, client_head);
|
||||
#endif
|
||||
#ifdef NET123_WININET
|
||||
if(autochoose || !strcmp("wininet", param.network_backend))
|
||||
return net123_open_wininet(url, client_head);
|
||||
#endif
|
||||
merror("no network backend for %s", https ? "HTTPS" : "HTTP");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stream dump descriptor. */
|
||||
static int dump_fd = -1;
|
||||
|
||||
@@ -31,13 +168,9 @@ static int dump_fd = -1;
|
||||
static ssize_t stream_read_raw(struct stream *sd, void *buf, size_t count)
|
||||
{
|
||||
ssize_t ret = -1;
|
||||
#ifdef NET123
|
||||
#ifdef NETWORK
|
||||
if(sd->nh)
|
||||
ret = net123_read(sd->nh, buf, count);
|
||||
#endif
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if(sd->fd >= 0 && sd->network)
|
||||
ret = win32_net_read(sd->fd, buf, count);
|
||||
ret = (ssize_t) sd->nh->read(sd->nh, buf, count);
|
||||
#endif
|
||||
if(sd->fd >= 0) // plain file or network socket
|
||||
ret = (ssize_t) unintr_read(sd->fd, buf, count);
|
||||
@@ -79,8 +212,12 @@ static ssize_t stream_read(struct stream *sd, void *buf, size_t count)
|
||||
|
||||
static off_t stream_seek(struct stream *sd, off_t pos, int whence)
|
||||
{
|
||||
if(!sd || sd->network)
|
||||
if(!sd)
|
||||
return -1;
|
||||
#ifdef NET123
|
||||
if(sd->nh)
|
||||
return -1;
|
||||
#endif
|
||||
return lseek(sd->fd, pos, whence);
|
||||
}
|
||||
|
||||
@@ -151,6 +288,7 @@ ssize_t stream_getline(struct stream *sd, mpg123_string *line)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NETWORK
|
||||
// Return 0 on success, non-zero when there is an error or more work to do.
|
||||
// -1: error, 1: redirection to given location
|
||||
static int stream_parse_headers(struct stream *sd, mpg123_string *location)
|
||||
@@ -278,11 +416,84 @@ static int stream_parse_headers(struct stream *sd, mpg123_string *location)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// resolve relative locations given the initial full URL
|
||||
// full URL ensured to either start with http:// or https://
|
||||
// (case-insensitive), location non-empty
|
||||
static void relocate_url(mpg123_string *location, const char *url)
|
||||
{
|
||||
if(!strncasecmp(location->p, "http://", 7) || !strncasecmp(location->p, "https://", 8))
|
||||
return;
|
||||
if(!url || (strncasecmp(url, "http://", 7) && strncasecmp(url, "https://", 8)))
|
||||
{
|
||||
mpg123_resize_string(location, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!param.quiet)
|
||||
fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n");
|
||||
|
||||
mpg123_string purl;
|
||||
mpg123_string workbuf;
|
||||
mpg123_init_string(&purl);
|
||||
mpg123_init_string(&workbuf);
|
||||
|
||||
if(mpg123_set_string(&purl, url) && mpg123_move_string(location, &workbuf))
|
||||
{
|
||||
debug1("relocate request_url: %s", purl.p);
|
||||
// location somewhat relative, either /some/path or even just some/path
|
||||
char* ptmp = NULL;
|
||||
// Though it's not RFC (?), accept relative URIs as wget does.
|
||||
if(workbuf.p[0] == '/')
|
||||
{
|
||||
// server-absolute only prepend http://server/
|
||||
// I null the first / after http:// or https://
|
||||
size_t off = (purl.p[4] == 's') ? 8 : 7;
|
||||
ptmp = strchr(purl.p+off,'/');
|
||||
if(ptmp != NULL)
|
||||
{
|
||||
purl.fill = ptmp-purl.p+1;
|
||||
purl.p[purl.fill-1] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// relative to current directory
|
||||
// prepend http://server/path/
|
||||
// first cutting off parameter stuff from URL
|
||||
for(size_t i=0; i<purl.fill; ++i)
|
||||
{
|
||||
if(purl.p[i] == '?' || purl.p[i] == '#')
|
||||
{
|
||||
purl.p[i] = 0;
|
||||
purl.fill = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now the last slash, keeping it
|
||||
ptmp = strrchr(purl.p, '/');
|
||||
if(ptmp != NULL)
|
||||
{
|
||||
purl.fill = ptmp-purl.p+2;
|
||||
purl.p[purl.fill-1] = 0;
|
||||
}
|
||||
}
|
||||
// only the prefix left
|
||||
debug1("prefix=%s", purl.p);
|
||||
mpg123_add_string(location, purl.p);
|
||||
}
|
||||
|
||||
mpg123_add_string(location, workbuf.p);
|
||||
|
||||
mpg123_free_string(&workbuf);
|
||||
mpg123_free_string(&purl);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void stream_init(struct stream *sd)
|
||||
{
|
||||
sd->bufp = sd->buf;
|
||||
sd->fill = 0;
|
||||
sd->network = 0;
|
||||
sd->fd = -1;
|
||||
#ifdef NET123
|
||||
sd->nh = NULL;
|
||||
@@ -296,15 +507,8 @@ static void stream_reset(struct stream *sd)
|
||||
{
|
||||
#ifdef NET123
|
||||
if(sd->nh)
|
||||
net123_close(sd->nh);
|
||||
sd->nh->close(sd->nh);
|
||||
sd->nh = NULL;
|
||||
#endif
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if(sd->fd >= 0 && sd->network)
|
||||
{
|
||||
if(sd->fd != SOCKET_ERROR)
|
||||
win32_net_close(sd->fd);
|
||||
}
|
||||
#endif
|
||||
if(sd->fd >= 0) // plain file or network socket
|
||||
close(sd->fd);
|
||||
@@ -327,10 +531,9 @@ struct stream *stream_open(const char *url)
|
||||
sd->fd = STDIN_FILENO;
|
||||
compat_binmode(STDIN_FILENO, TRUE);
|
||||
}
|
||||
#ifdef NET123
|
||||
#ifdef NETWORK
|
||||
else if(!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8))
|
||||
{
|
||||
sd->network = 1;
|
||||
// Network stream with header parsing.
|
||||
const char *client_head[] = { NULL, NULL, NULL };
|
||||
client_head[0] = param.talk_icy ? icy_yes : icy_no;
|
||||
@@ -339,15 +542,18 @@ struct stream *stream_open(const char *url)
|
||||
append_accept(&accept);
|
||||
client_head[1] = accept.p;
|
||||
mpg123_string location;
|
||||
mpg123_string urlcopy;
|
||||
mpg123_init_string(&location);
|
||||
mpg123_init_string(&urlcopy);
|
||||
int numrelocs = 0;
|
||||
while(sd)
|
||||
{
|
||||
sd->nh = net123_open(url, client_head);
|
||||
sd->nh = net123_open(url, client_head, &sd->htd);
|
||||
if(!sd->nh)
|
||||
{
|
||||
stream_close(sd);
|
||||
sd = NULL;
|
||||
break;
|
||||
}
|
||||
location.fill = 0;
|
||||
if(stream_parse_headers(sd, &location))
|
||||
@@ -358,35 +564,29 @@ struct stream *stream_open(const char *url)
|
||||
if(++numrelocs > HTTP_MAX_RELOCATIONS)
|
||||
{
|
||||
merror("too many HTTP redirections: %i", numrelocs);
|
||||
stream_close(sd);
|
||||
sd = NULL;
|
||||
url = NULL;
|
||||
} else
|
||||
url = location.p; // Used one time, then possibly overwritten.
|
||||
{
|
||||
relocate_url(&location, url); // resolve relative locations
|
||||
mpg123_copy_string(&location, &urlcopy);
|
||||
url = urlcopy.p;
|
||||
}
|
||||
} else
|
||||
{
|
||||
url = NULL;
|
||||
}
|
||||
if(!url)
|
||||
{
|
||||
stream_close(sd);
|
||||
sd = NULL;
|
||||
}
|
||||
} else break; // Successful end.
|
||||
}
|
||||
mpg123_free_string(&urlcopy);
|
||||
mpg123_free_string(&location);
|
||||
mpg123_free_string(&accept);
|
||||
// Either sd is NULL or we got a stream ready.
|
||||
}
|
||||
#elif defined(NETWORK)
|
||||
else if(!strncasecmp("http://", url, 7))
|
||||
{
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
sd->fd = win32_net_http_open(url, &sd->htd);
|
||||
#else
|
||||
sd->fd = http_open(url, &sd->htd);
|
||||
#endif
|
||||
if(sd->fd < 0)
|
||||
{
|
||||
stream_close(sd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
@@ -482,12 +682,7 @@ int dump_setup(struct stream *sd, mpg123_handle *mh)
|
||||
ret = mpg123_open_handle(mh, sd);
|
||||
} else
|
||||
{
|
||||
#ifdef WANT_WIN32_SOCKETS
|
||||
if(sd->network)
|
||||
win32_net_replace(mh);
|
||||
else // ensure libmpg123 is using its own reader otherwise
|
||||
#endif
|
||||
mpg123_replace_reader(mh, NULL, NULL);
|
||||
mpg123_replace_reader(mh, NULL, NULL);
|
||||
ret = mpg123_open_fd(mh, sd->fd);
|
||||
}
|
||||
if(ret != MPG123_OK)
|
||||
|
@@ -18,6 +18,9 @@
|
||||
#ifdef NET123
|
||||
#include "net123.h"
|
||||
#endif
|
||||
#ifdef NETWORK
|
||||
#include "httpget.h"
|
||||
#endif
|
||||
|
||||
// The stream is either addressed via file descriptor or net123 handle.
|
||||
struct stream
|
||||
@@ -25,7 +28,6 @@ struct stream
|
||||
char buf[256]; // buffer for getline
|
||||
char *bufp; // read pointer in buffer
|
||||
int fill; // bytes in buffer
|
||||
int network; // flag to mark network streams (with httpdata)
|
||||
int fd; // if > 0: plain file descriptor or win32 net socket
|
||||
struct httpdata htd;
|
||||
#ifdef NET123
|
||||
|
@@ -232,8 +232,9 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
|
||||
case MPG123_QUIT_KEY:
|
||||
debug("QUIT");
|
||||
if(stopped)
|
||||
{ if(param.verbose)
|
||||
print_stat(fr,0,ao,0,¶m);
|
||||
{
|
||||
if(param.verbose)
|
||||
print_stat(fr,0,ao,0,¶m);
|
||||
|
||||
stopped = 0;
|
||||
out123_pause(ao); /* no chance for annoying underrun warnings */
|
||||
|
@@ -8,6 +8,10 @@
|
||||
initially written by Thomas Orgis
|
||||
*/
|
||||
|
||||
// ctermid
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __OS2__
|
||||
|
341
src/win32_net.c
341
src/win32_net.c
@@ -1,14 +1,7 @@
|
||||
#include "config.h"
|
||||
#include "mpg123.h"
|
||||
#include "win32_support.h"
|
||||
#include "mpg123app.h"
|
||||
#include "httpget.h"
|
||||
#include "resolver.h"
|
||||
#include "compat.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#if defined (WANT_WIN32_SOCKETS)
|
||||
#ifdef DEBUG
|
||||
#define msgme(x) win32_net_msg(x,__FILE__,__LINE__)
|
||||
#define msgme1 win32_net_msg(1,__FILE__,__LINE__)
|
||||
@@ -115,28 +108,6 @@ static int get_sock_ch (int sock)
|
||||
return (((int) c)&0xff);
|
||||
return -1;
|
||||
}
|
||||
/* Addapted from from newlib*/
|
||||
char *win32_net_fgets(char *s, int n, int stream)
|
||||
{
|
||||
char c = 0;
|
||||
char *buf;
|
||||
buf = s;
|
||||
debug1("Pseudo net fgets attempts to read %d bytes from network.", n - 1);
|
||||
while (--n > 0 && (c = get_sock_ch (stream)) != -1)
|
||||
{
|
||||
*s++ = c;
|
||||
if (c == '\n' || c == '\r')
|
||||
break;
|
||||
}
|
||||
debug1("Pseudo net fgets got %"SIZE_P" bytes.", (size_p)(s - buf));
|
||||
if (c == -1 && s == buf)
|
||||
{
|
||||
debug("Pseudo net fgets met a premature end.");
|
||||
return NULL;
|
||||
}
|
||||
*s = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte)
|
||||
{
|
||||
@@ -148,18 +119,6 @@ ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte)
|
||||
return ret;
|
||||
}
|
||||
|
||||
off_t win32_net_lseek (int a, off_t b, int c)
|
||||
{
|
||||
debug("lseek on a socket called!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void win32_net_replace (mpg123_handle *fr)
|
||||
{
|
||||
debug("win32_net_replace ran");
|
||||
mpg123_replace_reader(fr, win32_net_read, win32_net_lseek);
|
||||
}
|
||||
|
||||
static int win32_net_timeout_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
|
||||
{
|
||||
debug("win32_net_timeout_connect ran");
|
||||
@@ -239,7 +198,7 @@ static int win32_net_timeout_connect(int sockfd, const struct sockaddr *serv_add
|
||||
}
|
||||
}
|
||||
|
||||
static int win32_net_open_connection(mpg123_string *host, mpg123_string *port)
|
||||
int win32_net_open_connection(mpg123_string *host, mpg123_string *port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *addr, *addrlist;
|
||||
@@ -286,52 +245,10 @@ static int win32_net_open_connection(mpg123_string *host, mpg123_string *port)
|
||||
}
|
||||
|
||||
freeaddrinfo(addrlist);
|
||||
return 1;
|
||||
return ws.local_socket == SOCKET_ERROR ? -1 : 1;
|
||||
}
|
||||
|
||||
static size_t win32_net_readstring (mpg123_string *string, size_t maxlen, int fd)
|
||||
{
|
||||
debug2("Attempting readstring on %d for %"SIZE_P" bytes", fd, (size_p)maxlen);
|
||||
int err;
|
||||
string->fill = 0;
|
||||
while(maxlen == 0 || string->fill < maxlen)
|
||||
{
|
||||
if(string->size-string->fill < 1)
|
||||
if(!mpg123_grow_string(string, string->fill+4096))
|
||||
{
|
||||
error("Cannot allocate memory for reading.");
|
||||
string->fill = 0;
|
||||
return 0;
|
||||
}
|
||||
err = win32_net_read(0,string->p+string->fill,1); /*fd is ignored */
|
||||
/* Whoa... reading one byte at a time... one could ensure the line break in another way, but more work. */
|
||||
if( err == 1)
|
||||
{
|
||||
string->fill++;
|
||||
if(string->p[string->fill-1] == '\n') break;
|
||||
}
|
||||
else if(errno != EINTR)
|
||||
{
|
||||
error("Error reading from socket or unexpected EOF.");
|
||||
string->fill = 0;
|
||||
/* bail out to prevent endless loop */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mpg123_grow_string(string, string->fill+1))
|
||||
{
|
||||
string->fill=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
string->p[string->fill] = 0;
|
||||
string->fill++;
|
||||
}
|
||||
return string->fill;
|
||||
}
|
||||
|
||||
static int win32_net_writestring (int fd, mpg123_string *string)
|
||||
int win32_net_writestring (int fd, mpg123_string *string)
|
||||
{
|
||||
size_t result, bytes;
|
||||
char *ptr = string->p;
|
||||
@@ -355,253 +272,3 @@ static int win32_net_writestring (int fd, mpg123_string *string)
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int win32_net_resolve_redirect(mpg123_string *response, mpg123_string *request_url, mpg123_string *purl)
|
||||
{
|
||||
debug1("request_url:%s", request_url->p);
|
||||
/* initialized with full old url */
|
||||
if(!mpg123_copy_string(request_url, purl)) return FALSE;
|
||||
|
||||
/* We may strip it down to a prefix ot totally. */
|
||||
if(strncasecmp(response->p, "Location: http://", 17))
|
||||
{ /* OK, only partial strip, need prefix for relative path. */
|
||||
char* ptmp = NULL;
|
||||
/* though it's not RFC (?), accept relative URIs as wget does */
|
||||
fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n");
|
||||
/* not absolute uri, could still be server-absolute */
|
||||
/* I prepend a part of the request... out of the request */
|
||||
if(response->p[10] == '/')
|
||||
{
|
||||
/* only prepend http://server/ */
|
||||
/* I null the first / after http:// */
|
||||
ptmp = strchr(purl->p+7,'/');
|
||||
if(ptmp != NULL){ purl->fill = ptmp-purl->p+1; purl->p[purl->fill-1] = 0; }
|
||||
}
|
||||
else
|
||||
{
|
||||
/* prepend http://server/path/ */
|
||||
/* now we want the last / */
|
||||
ptmp = strrchr(purl->p+7, '/');
|
||||
if(ptmp != NULL){ purl->fill = ptmp-purl->p+2; purl->p[purl->fill-1] = 0; }
|
||||
}
|
||||
}
|
||||
else purl->fill = 0;
|
||||
|
||||
debug1("prefix=%s", purl->fill ? purl->p : "");
|
||||
if(!mpg123_add_string(purl, response->p+10)) return FALSE;
|
||||
|
||||
debug1(" purl: %s", purl->p);
|
||||
debug1("old request_url: %s", request_url->p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int win32_net_http_open(const char* url, struct httpdata *hd)
|
||||
{
|
||||
mpg123_string purl, host, port, path;
|
||||
mpg123_string request, response, request_url;
|
||||
mpg123_string httpauth1;
|
||||
ws.local_socket = SOCKET_ERROR;
|
||||
int oom = 0;
|
||||
int relocate, numrelocs = 0;
|
||||
int got_location = FALSE;
|
||||
/*
|
||||
workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls
|
||||
this site's apache gives me a relocation to the same place when I give the port in Host request field
|
||||
for the record: Apache/2.0.51 (Fedora)
|
||||
*/
|
||||
int try_without_port = 0;
|
||||
mpg123_init_string(&purl);
|
||||
mpg123_init_string(&host);
|
||||
mpg123_init_string(&port);
|
||||
mpg123_init_string(&path);
|
||||
mpg123_init_string(&request);
|
||||
mpg123_init_string(&response);
|
||||
mpg123_init_string(&request_url);
|
||||
mpg123_init_string(&httpauth1);
|
||||
|
||||
/* Get initial info for proxy server. Once. */
|
||||
if(hd->proxystate == PROXY_UNKNOWN && !proxy_init(hd)) goto exit;
|
||||
|
||||
if(!translate_url(url, &purl)){ oom=1; goto exit; }
|
||||
|
||||
/* Don't confuse the different auth strings... */
|
||||
if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; }
|
||||
|
||||
/* "GET http://" 11
|
||||
* " HTTP/1.0\r\nUser-Agent: <PACKAGE_NAME>/<PACKAGE_VERSION>\r\n"
|
||||
* 26 + PACKAGE_NAME + PACKAGE_VERSION
|
||||
* accept header + accept_length()
|
||||
* "Authorization: Basic \r\n" 23
|
||||
* "\r\n" 2
|
||||
* ... plus the other predefined header lines
|
||||
*/
|
||||
/* Just use this estimate as first guess to reduce malloc calls in string library. */
|
||||
{
|
||||
size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION)
|
||||
+ accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill;
|
||||
if( !mpg123_grow_string(&request, length_estimate)
|
||||
|| !mpg123_grow_string(&response,4096) )
|
||||
{
|
||||
oom=1; goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Storing the request url, with http:// prepended if needed. */
|
||||
/* used to be url here... seemed wrong to me (when loop advanced...) */
|
||||
if(strncasecmp(purl.p, "http://", 7) != 0) mpg123_set_string(&request_url, "http://");
|
||||
else mpg123_set_string(&request_url, "");
|
||||
|
||||
mpg123_add_string(&request_url, purl.p);
|
||||
|
||||
if(!split_url(&purl, NULL, &host, &port, &path)){ oom=1; goto exit; }
|
||||
if (hd->proxystate >= PROXY_HOST)
|
||||
{
|
||||
/* We will connect to proxy, full URL goes into the request. */
|
||||
if( !mpg123_set_string(&request, "GET ")
|
||||
|| !mpg123_add_string(&request, request_url.p) )
|
||||
{
|
||||
oom=1; goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We will connect to the host from the URL and only the path goes into the request. */
|
||||
if( !mpg123_set_string(&request, "GET ")
|
||||
|| !mpg123_add_string(&request, path.p) )
|
||||
{
|
||||
oom=1; goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; }
|
||||
|
||||
httpauth1.fill = 0; /* We use the auth data from the URL only once. */
|
||||
if (hd->proxystate >= PROXY_HOST)
|
||||
{
|
||||
if( !mpg123_copy_string(&hd->proxyhost, &host)
|
||||
|| !mpg123_copy_string(&hd->proxyport, &port) )
|
||||
{
|
||||
oom=1; goto exit;
|
||||
}
|
||||
}
|
||||
debug2("attempting to open_connection to %s:%s", host.p, port.p);
|
||||
win32_net_open_connection(&host, &port);
|
||||
if(ws.local_socket == SOCKET_ERROR)
|
||||
{
|
||||
error1("Unable to establish connection to %s", host.fill ? host.p : "");
|
||||
goto exit;
|
||||
}
|
||||
debug("win32_net_open_connection succeed");
|
||||
#define http_failure win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; goto exit;
|
||||
|
||||
if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p);
|
||||
if(!win32_net_writestring(ws.local_socket, &request)){ http_failure; }
|
||||
debug("Skipping fdopen for WSA sockets");
|
||||
relocate = FALSE;
|
||||
/* Arbitrary length limit here... */
|
||||
#define safe_readstring \
|
||||
win32_net_readstring(&response, SIZE_MAX/16, -1); \
|
||||
if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \
|
||||
{ \
|
||||
error("HTTP response line exceeds max. length"); \
|
||||
http_failure; \
|
||||
} \
|
||||
else if(response.fill == 0) \
|
||||
{ \
|
||||
error("readstring failed"); \
|
||||
http_failure; \
|
||||
} \
|
||||
if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p);
|
||||
safe_readstring;
|
||||
|
||||
{
|
||||
char *sptr;
|
||||
if((sptr = strchr(response.p, ' ')))
|
||||
{
|
||||
if(response.fill > sptr-response.p+2)
|
||||
switch (sptr[1])
|
||||
{
|
||||
case '3':
|
||||
relocate = TRUE;
|
||||
case '2':
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */
|
||||
http_failure;
|
||||
}
|
||||
else{ error("Too short response,"); http_failure; }
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are relocated, we need to look out for a Location header. */
|
||||
got_location = FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */
|
||||
if (!strncasecmp(response.p, "Location: ", 10))
|
||||
{ /* It is a redirection! */
|
||||
if(!win32_net_resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; }
|
||||
|
||||
if(!strcmp(purl.p, request_url.p))
|
||||
{
|
||||
warning("relocated to very same place! trying request again without host port");
|
||||
try_without_port = 1;
|
||||
}
|
||||
got_location = TRUE;
|
||||
}
|
||||
else
|
||||
{ /* We got a header line (or the closing empty line). */
|
||||
char *tmp;
|
||||
debug1("searching for header values... %s", response.p);
|
||||
/* Not sure if I want to bail out on error here. */
|
||||
/* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */
|
||||
get_header_string(&response, "content-type", &hd->content_type);
|
||||
get_header_string(&response, "icy-name", &hd->icy_name);
|
||||
get_header_string(&response, "icy-url", &hd->icy_url);
|
||||
|
||||
/* watch out for icy-metaint */
|
||||
if((tmp = get_header_val("icy-metaint", &response)))
|
||||
{
|
||||
hd->icy_interval = (off_t) atol(tmp); /* atoll ? */
|
||||
debug1("got icy-metaint %li", (long int)hd->icy_interval);
|
||||
}
|
||||
}
|
||||
} while(response.p[0] != '\r' && response.p[0] != '\n');
|
||||
if (relocate) { win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; }
|
||||
} while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS);
|
||||
if(relocate)
|
||||
{
|
||||
if(!got_location)
|
||||
error("Server meant to redirect but failed to provide a location!");
|
||||
else
|
||||
error1("Too many HTTP relocations (%i).", numrelocs);
|
||||
|
||||
http_failure;
|
||||
}
|
||||
|
||||
exit: /* The end as well as the exception handling point... */
|
||||
if(oom) error("Apparently, I ran out of memory or had some bad input data...");
|
||||
|
||||
mpg123_free_string(&purl);
|
||||
mpg123_free_string(&host);
|
||||
mpg123_free_string(&port);
|
||||
mpg123_free_string(&path);
|
||||
mpg123_free_string(&request);
|
||||
mpg123_free_string(&response);
|
||||
mpg123_free_string(&request_url);
|
||||
mpg123_free_string(&httpauth1);
|
||||
if (ws.local_socket == SOCKET_ERROR || oom)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int win32_net_http_open(const char* url, struct httpdata *hd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif /*WANT_WIN32_SOCKETS */
|
||||
|
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "mpg123.h"
|
||||
#include "httpget.h"
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
@@ -32,15 +31,18 @@
|
||||
Note: Do not treat return values as valid file/socket handles, they only indicate success/failure.
|
||||
file descriptors are ignored, only the local ws.local_socket is used for storing socket handle,
|
||||
so the socket handle is always associated with the last call to win32_net_http_open
|
||||
|
||||
TODO: Move the socket descriptor/state struct into streamdump.c, which wraps all network
|
||||
connections. Stored in in nh->parts, it enables multiple sockets being opened.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opens an http URL
|
||||
* @param[in] url URL to open
|
||||
* @param[out] hd http data info
|
||||
* @param[in] host to connect to
|
||||
* @param[in] port to use
|
||||
* @return -1 for failure, 1 for success
|
||||
*/
|
||||
int win32_net_http_open(const char* url, struct httpdata *hd);
|
||||
int win32_net_open_connection(mpg123_string *host, mpg123_string *port);
|
||||
|
||||
/**
|
||||
* Reads from network socket
|
||||
@@ -61,13 +63,12 @@ ssize_t win32_net_read (int fildes, void *buf, size_t nbyte);
|
||||
ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte);
|
||||
|
||||
/**
|
||||
* Similar to fgets - get a string from a stream
|
||||
* @param[out] s buffer to Write to
|
||||
* @param[in] n bytes of data to read.
|
||||
* @param[in] stream ignored for compatiblity, last open connection is used.
|
||||
* @return pointer to s if successful, NULL if failture
|
||||
* Writes a whole mpg123_string to the network socket
|
||||
* @param[in] filedes Value is ignored, last open connection is used.
|
||||
* @param[in] string the string to write
|
||||
* @return TRUE if successful, FALS on error
|
||||
*/
|
||||
char *win32_net_fgets(char *s, int n, int stream);
|
||||
int win32_net_writestring (int filedes, mpg123_string *string);
|
||||
|
||||
/**
|
||||
* Initialize Winsock 2.2.
|
||||
@@ -84,12 +85,6 @@ void win32_net_deinit (void);
|
||||
* @param[in] sock value is ignored.
|
||||
*/
|
||||
void win32_net_close (int sock);
|
||||
|
||||
/**
|
||||
* Set reader callback for mpg123_open_fd
|
||||
* @param[in] fr pointer to a mpg123_handle struct.
|
||||
*/
|
||||
void win32_net_replace (mpg123_handle *fr);
|
||||
#endif
|
||||
|
||||
#ifdef WANT_WIN32_UNICODE
|
||||
|
Reference in New Issue
Block a user