diff --git a/NEWS b/NEWS index b6e54da6..e41f082e 100644 --- a/NEWS +++ b/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 . +-- 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 ------ diff --git a/configure.ac b/configure.ac index 8f8db97e..8827a01f 100644 --- a/configure.ac +++ b/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=], [Available options, depending on platform, are auto, none, internal, winhttp, wininet, and exec (wget or curl binaries).])], + [AS_HELP_STRING([--with-network=], +[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 diff --git a/ports/cmake/src/CMakeLists.txt b/ports/cmake/src/CMakeLists.txt index 44f99b9f..612738ee 100644 --- a/ports/cmake/src/CMakeLists.txt +++ b/ports/cmake/src/CMakeLists.txt @@ -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) diff --git a/src/Makemodule.am b/src/Makemodule.am index 7b302179..9946fbc5 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -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 diff --git a/src/common.c b/src/common.c index ce7f4387..9b185b03 100644 --- a/src/common.c +++ b/src/common.c @@ -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; diff --git a/src/control_generic.c b/src/control_generic.c index 19670cb4..1eb2dd3e 100644 --- a/src/control_generic.c +++ b/src/control_generic.c @@ -751,7 +751,6 @@ int control_generic (mpg123_handle *fr) /* Simple EQ: SEQ */ 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); diff --git a/src/httpget.c b/src/httpget.c index 6026fdf0..cb4741f3 100644 --- a/src/httpget.c +++ b/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: /\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 */ diff --git a/src/httpget.h b/src/httpget.h index ecdb80bc..4805c53d 100644 --- a/src/httpget.h +++ b/src/httpget.h @@ -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 diff --git a/src/local.c b/src/local.c index 9a1dc4e3..10bb3e04 100644 --- a/src/local.c +++ b/src/local.c @@ -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"; diff --git a/src/mpg123.c b/src/mpg123.c index c47f0f05..a80c2ac6 100644 --- a/src/mpg123.c +++ b/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 --proxy set WWW proxy\n"); -#else + fprintf(o," -p --proxy override proxy environemnt variable for plain HTTP\n"); fprintf(o," --network 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 --audiodevice select audio device (depending on chosen module)\n"); fprintf(o," -s --stdout write raw audio to stdout (host native format)\n"); + fprintf(o," -O --outfile write raw audio to given file (- is stdout)\n"); fprintf(o," -w --wav write samples as WAV file in (- is stdout)\n"); fprintf(o," --au write samples as Sun AU file in (- is stdout)\n"); fprintf(o," --cdr write samples as raw CD audio file in (- is stdout)\n"); diff --git a/src/net123.h b/src/net123.h index f6c725fc..11f002e5 100644 --- a/src/net123.h +++ b/src/net123.h @@ -39,12 +39,17 @@ #ifndef _MPG123_NET123_H_ #define _MPG123_NET123_H_ +#include "config.h" #include -// 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 diff --git a/src/net123_exec.c b/src/net123_exec.c index af3dc4b3..93c4c37c 100644 --- a/src/net123_exec.c +++ b/src/net123_exec.c @@ -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); -} - diff --git a/src/net123_winhttp.c b/src/net123_winhttp.c index f02070f3..4d1562bf 100644 --- a/src/net123_winhttp.c +++ b/src/net123_winhttp.c @@ -5,13 +5,11 @@ #include #include -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); } diff --git a/src/net123_wininet.c b/src/net123_wininet.c index 49907e3a..520c0996 100644 --- a/src/net123_wininet.c +++ b/src/net123_wininet.c @@ -5,13 +5,11 @@ #include #include -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); } diff --git a/src/playlist.c b/src/playlist.c index fe48f548..c72e1c0a 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -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? diff --git a/src/streamdump.c b/src/streamdump.c index 778c03d8..6c7c44aa 100644 --- a/src/streamdump.c +++ b/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 #include @@ -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; ibufp = 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) diff --git a/src/streamdump.h b/src/streamdump.h index c220b620..5bb93a02 100644 --- a/src/streamdump.h +++ b/src/streamdump.h @@ -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 diff --git a/src/term.c b/src/term.c index 2e9594ad..ae0eefa3 100644 --- a/src/term.c +++ b/src/term.c @@ -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 */ diff --git a/src/term_posix.c b/src/term_posix.c index ba1d161d..9c26cd95 100644 --- a/src/term_posix.c +++ b/src/term_posix.c @@ -8,6 +8,10 @@ initially written by Thomas Orgis */ +// ctermid +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L + #include "config.h" #ifdef __OS2__ diff --git a/src/win32_net.c b/src/win32_net.c index 11a5a422..e43ddd42 100755 --- a/src/win32_net.c +++ b/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 - #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: /\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 */ diff --git a/src/win32_support.h b/src/win32_support.h index 1c797de3..498d7e61 100755 --- a/src/win32_support.h +++ b/src/win32_support.h @@ -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