Blame src/win32_net.c

Packit c32a2d
#include "config.h"
Packit c32a2d
#include "mpg123.h"
Packit c32a2d
#include "mpg123app.h"
Packit c32a2d
#include "httpget.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
#include "resolver.h"
Packit c32a2d
#include "compat.h"
Packit c32a2d
#include <errno.h>
Packit c32a2d
Packit c32a2d
#if defined (WANT_WIN32_SOCKETS)
Packit c32a2d
#ifdef DEBUG
Packit c32a2d
#define msgme(x) win32_net_msg(x,__FILE__,__LINE__)
Packit c32a2d
#define msgme1 win32_net_msg(1,__FILE__,__LINE__)
Packit c32a2d
#define msgme_sock_err(x) if ((x)==SOCKET_ERROR) {msgme1;}
Packit c32a2d
#else
Packit c32a2d
#define msgme(x) x
Packit c32a2d
#define msgme1 do{} while(0)
Packit c32a2d
#define msgme_sock_err(x) x
Packit c32a2d
#endif
Packit c32a2d
struct ws_local
Packit c32a2d
{
Packit c32a2d
  int inited;
Packit c32a2d
  SOCKET local_socket; /*stores last connet in win32_net_open_connection*/
Packit c32a2d
  WSADATA wsadata;
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
static struct ws_local ws;
Packit c32a2d
#ifdef DEBUG
Packit c32a2d
static void win32_net_msg (const int err, const char * const filedata, const int linedata)
Packit c32a2d
{
Packit c32a2d
  char *errbuff;
Packit c32a2d
  int lc_err;
Packit c32a2d
  if (err)
Packit c32a2d
  {
Packit c32a2d
    lc_err = WSAGetLastError();
Packit c32a2d
    FormatMessage(
Packit c32a2d
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Packit c32a2d
      NULL,
Packit c32a2d
      lc_err,
Packit c32a2d
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
Packit c32a2d
      (LPTSTR) &errbuff,
Packit c32a2d
      0,
Packit c32a2d
      NULL );
Packit c32a2d
    fprintf(stderr, "[%s:%d] [WSA2: %d] %s", filedata, linedata, lc_err, errbuff);
Packit c32a2d
    LocalFree (errbuff);
Packit c32a2d
  }
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
void win32_net_init (void)
Packit c32a2d
{
Packit c32a2d
  ws.inited = 1;
Packit c32a2d
  switch ((WSAStartup(MAKEWORD(2,2), &ws.wsadata)))
Packit c32a2d
  {
Packit c32a2d
    case WSASYSNOTREADY: debug("WSAStartup failed with WSASYSNOTREADY"); break;
Packit c32a2d
    case WSAVERNOTSUPPORTED: debug("WSAStartup failed with WSAVERNOTSUPPORTED"); break;
Packit c32a2d
    case WSAEINPROGRESS: debug("WSAStartup failed with WSAEINPROGRESS"); break;
Packit c32a2d
    case WSAEPROCLIM: debug("WSAStartup failed with WSAEPROCLIM"); break;
Packit c32a2d
    case WSAEFAULT: debug("WSAStartup failed with WSAEFAULT"); break;
Packit c32a2d
    default:
Packit c32a2d
    break;
Packit c32a2d
  }
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void win32_net_deinit (void)
Packit c32a2d
{
Packit c32a2d
  debug("Begin winsock cleanup");
Packit c32a2d
  if (ws.inited)
Packit c32a2d
  {
Packit c32a2d
    if (ws.inited >= 2 && ws.local_socket != SOCKET_ERROR)
Packit c32a2d
    {
Packit c32a2d
      debug1("ws.local_socket = %"SIZE_P"", (size_p)ws.local_socket);
Packit c32a2d
      msgme_sock_err(shutdown(ws.local_socket, SD_BOTH));
Packit c32a2d
      win32_net_close(ws.local_socket);
Packit c32a2d
    }
Packit c32a2d
    WSACleanup();
Packit c32a2d
    ws.inited = 0;
Packit c32a2d
  }
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void win32_net_close (int sock)
Packit c32a2d
{
Packit c32a2d
    msgme_sock_err(closesocket(ws.local_socket));
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void win32_net_nonblock(int sock)
Packit c32a2d
{
Packit c32a2d
  u_long mode = 1;
Packit c32a2d
  msgme_sock_err(ioctlsocket(ws.local_socket, FIONBIO, &mode);;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void win32_net_block(int sock)
Packit c32a2d
{
Packit c32a2d
  u_long mode = 0;
Packit c32a2d
  msgme_sock_err(ioctlsocket(ws.local_socket, FIONBIO, &mode);;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
ssize_t win32_net_read (int fildes, void *buf, size_t nbyte)
Packit c32a2d
{
Packit c32a2d
  debug1("Attempting to read %"SIZE_P" bytes from network.", (size_p)nbyte);
Packit c32a2d
  ssize_t ret;
Packit c32a2d
  msgme_sock_err(ret = (ssize_t) recv(ws.local_socket, buf, nbyte, 0));
Packit c32a2d
  debug1("Read %"SSIZE_P" bytes from network.", (ssize_p)ret);
Packit c32a2d
Packit c32a2d
  return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int get_sock_ch (int sock)
Packit c32a2d
{
Packit c32a2d
  char c;
Packit c32a2d
  int ret;
Packit c32a2d
  msgme_sock_err(ret = recv (ws.local_socket, &c, 1, 0));
Packit c32a2d
  if (ret == 1)
Packit c32a2d
    return (((int) c)&0xff);
Packit c32a2d
  return -1;
Packit c32a2d
}
Packit c32a2d
/* Addapted from from newlib*/
Packit c32a2d
char *win32_net_fgets(char *s, int n, int stream)
Packit c32a2d
{
Packit c32a2d
  char c = 0;
Packit c32a2d
  char *buf;
Packit c32a2d
  buf = s;
Packit c32a2d
  debug1("Pseudo net fgets attempts to read %d bytes from network.", n - 1);
Packit c32a2d
  while (--n > 0 && (c = get_sock_ch (stream)) != -1)
Packit c32a2d
  {
Packit c32a2d
    *s++ = c;
Packit c32a2d
    if (c == '\n' || c == '\r')
Packit c32a2d
      break;
Packit c32a2d
  }
Packit c32a2d
  debug1("Pseudo net fgets got %"SIZE_P" bytes.", (size_p)(s - buf));
Packit c32a2d
  if (c == -1 && s == buf)
Packit c32a2d
  {
Packit c32a2d
    debug("Pseudo net fgets met a premature end.");
Packit c32a2d
    return NULL;
Packit c32a2d
  }
Packit c32a2d
  *s = 0;
Packit c32a2d
  return buf;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
ssize_t win32_net_write (int fildes, const void *buf, size_t nbyte)
Packit c32a2d
{
Packit c32a2d
  debug1("Attempting to write %"SIZE_P" bytes to network.", (size_p)nbyte);
Packit c32a2d
  ssize_t ret;
Packit c32a2d
  msgme_sock_err((ret = (ssize_t) send(ws.local_socket, buf, nbyte, 0)));
Packit c32a2d
  debug1("wrote %"SSIZE_P" bytes to network.", (ssize_t)ret);
Packit c32a2d
Packit c32a2d
  return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t win32_net_lseek (int a, off_t b, int c)
Packit c32a2d
{
Packit c32a2d
  debug("lseek on a socket called!");
Packit c32a2d
  return -1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void win32_net_replace (mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
  debug("win32_net_replace ran");
Packit c32a2d
  mpg123_replace_reader(fr, win32_net_read, win32_net_lseek);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int win32_net_timeout_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
Packit c32a2d
{
Packit c32a2d
	debug("win32_net_timeout_connect ran");
Packit c32a2d
	if(param.timeout > 0)
Packit c32a2d
	{
Packit c32a2d
		int err;
Packit c32a2d
		win32_net_nonblock(ws.local_socket);
Packit c32a2d
		err = connect(ws.local_socket, serv_addr, addrlen);
Packit c32a2d
		if(err != SOCKET_ERROR)
Packit c32a2d
		{
Packit c32a2d
			debug("immediately successful");
Packit c32a2d
			win32_net_block(ws.local_socket);
Packit c32a2d
			return 0;
Packit c32a2d
		}
Packit c32a2d
		else if(WSAGetLastError() == WSAEWOULDBLOCK) /*WSAEINPROGRESS would not work here for some reason*/
Packit c32a2d
		{
Packit c32a2d
			struct timeval tv;
Packit c32a2d
			fd_set fds;
Packit c32a2d
			tv.tv_sec = param.timeout;
Packit c32a2d
			tv.tv_usec = 0;
Packit c32a2d
Packit c32a2d
			debug("in progress, waiting...");
Packit c32a2d
Packit c32a2d
			FD_ZERO(&fds);
Packit c32a2d
			FD_SET(ws.local_socket, &fds);
Packit c32a2d
			err = select(ws.local_socket+1, NULL, &fds, NULL, &tv;;
Packit c32a2d
			if(err != SOCKET_ERROR)
Packit c32a2d
			{
Packit c32a2d
				socklen_t len = sizeof(err);
Packit c32a2d
				if((getsockopt(ws.local_socket, SOL_SOCKET, SO_ERROR, (char *)&err, &len) != SOCKET_ERROR)
Packit c32a2d
				   && (err == 0) )
Packit c32a2d
				{
Packit c32a2d
					debug("non-blocking connect has been successful");
Packit c32a2d
					win32_net_block(ws.local_socket);
Packit c32a2d
					return 0;
Packit c32a2d
				}
Packit c32a2d
				else
Packit c32a2d
				{
Packit c32a2d
					//error1("connection error: %s", msgme(err));
Packit c32a2d
					return -1;
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
			else if(err == 0)
Packit c32a2d
			{
Packit c32a2d
				error("connection timed out");
Packit c32a2d
				return -1;
Packit c32a2d
			}
Packit c32a2d
			else
Packit c32a2d
			{
Packit c32a2d
				/*error1("error from select(): %s", strerror(errno));*/
Packit c32a2d
				debug("error from select():");
Packit c32a2d
				msgme1;
Packit c32a2d
				return -1;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			/*error1("connection failed: %s", strerror(errno));*/
Packit c32a2d
			debug("connection failed: ");
Packit c32a2d
			msgme1;
Packit c32a2d
			return err;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		if(connect(ws.local_socket, serv_addr, addrlen) == SOCKET_ERROR)
Packit c32a2d
		{
Packit c32a2d
			/*error1("connection failed: %s", strerror(errno));*/
Packit c32a2d
			debug("connection failed");
Packit c32a2d
			msgme1;
Packit c32a2d
			return -1;
Packit c32a2d
		}
Packit c32a2d
		else {
Packit c32a2d
		debug("win32_net_timeout_connect succeed");
Packit c32a2d
		return 0; /* _good_ */
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int win32_net_open_connection(mpg123_string *host, mpg123_string *port)
Packit c32a2d
{
Packit c32a2d
	struct addrinfo hints;
Packit c32a2d
	struct addrinfo *addr, *addrlist;
Packit c32a2d
	SOCKET addrcount;
Packit c32a2d
	ws.local_socket = SOCKET_ERROR;
Packit c32a2d
Packit c32a2d
	if(param.verbose>1) fprintf(stderr, "Note: Attempting new-style connection to %s\n", host->p);
Packit c32a2d
	memset(&hints, 0, sizeof(struct addrinfo));
Packit c32a2d
	hints.ai_family   = AF_UNSPEC; /* We accept both IPv4 and IPv6 ... and perhaps IPv8;-) */
Packit c32a2d
	hints.ai_socktype = SOCK_STREAM;
Packit c32a2d
	hints.ai_protocol = IPPROTO_TCP;
Packit c32a2d
Packit c32a2d
	debug2("Atempt resolve/connect to %s:%s", host->p, port->p);
Packit c32a2d
	msgme(addrcount = getaddrinfo(host->p, port->p, &hints, &addrlist));
Packit c32a2d
Packit c32a2d
	if(addrcount == INVALID_SOCKET)
Packit c32a2d
	{
Packit c32a2d
		error3("Resolving %s:%s: %s", host->p, port->p, gai_strerror(addrcount));
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	addr = addrlist;
Packit c32a2d
	while(addr != NULL)
Packit c32a2d
	{
Packit c32a2d
		ws.local_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
Packit c32a2d
		if (ws.local_socket == INVALID_SOCKET)
Packit c32a2d
		{
Packit c32a2d
			msgme1;
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			if(win32_net_timeout_connect(ws.local_socket, addr->ai_addr, addr->ai_addrlen) == 0)
Packit c32a2d
			break;
Packit c32a2d
			debug("win32_net_timeout_connect error, closing socket");
Packit c32a2d
			win32_net_close(ws.local_socket);
Packit c32a2d
			ws.local_socket=SOCKET_ERROR;
Packit c32a2d
		}
Packit c32a2d
		addr=addr->ai_next;
Packit c32a2d
	}
Packit c32a2d
	if(ws.local_socket == SOCKET_ERROR) {error2("Cannot resolve/connect to %s:%s!", host->p, port->p);}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
	  ws.inited = 2;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	freeaddrinfo(addrlist);
Packit c32a2d
	return 1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static size_t win32_net_readstring (mpg123_string *string, size_t maxlen, int fd)
Packit c32a2d
{
Packit c32a2d
	debug2("Attempting readstring on %d for %"SIZE_P" bytes", fd, (size_p)maxlen);
Packit c32a2d
	int err;
Packit c32a2d
	string->fill = 0;
Packit c32a2d
	while(maxlen == 0 || string->fill < maxlen)
Packit c32a2d
	{
Packit c32a2d
		if(string->size-string->fill < 1)
Packit c32a2d
		if(!mpg123_grow_string(string, string->fill+4096))
Packit c32a2d
		{
Packit c32a2d
			error("Cannot allocate memory for reading.");
Packit c32a2d
			string->fill = 0;
Packit c32a2d
			return 0;
Packit c32a2d
		}
Packit c32a2d
		err = win32_net_read(0,string->p+string->fill,1); /*fd is ignored */
Packit c32a2d
		/* Whoa... reading one byte at a time... one could ensure the line break in another way, but more work. */
Packit c32a2d
		if( err == 1)
Packit c32a2d
		{
Packit c32a2d
			string->fill++;
Packit c32a2d
			if(string->p[string->fill-1] == '\n') break;
Packit c32a2d
		}
Packit c32a2d
		else if(errno != EINTR)
Packit c32a2d
		{
Packit c32a2d
			error("Error reading from socket or unexpected EOF.");
Packit c32a2d
			string->fill = 0;
Packit c32a2d
			/* bail out to prevent endless loop */
Packit c32a2d
			return 0;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(!mpg123_grow_string(string, string->fill+1))
Packit c32a2d
	{
Packit c32a2d
		string->fill=0;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		string->p[string->fill] = 0;
Packit c32a2d
		string->fill++;
Packit c32a2d
	}
Packit c32a2d
	return string->fill;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int win32_net_writestring (int fd, mpg123_string *string)
Packit c32a2d
{
Packit c32a2d
	size_t result, bytes;
Packit c32a2d
	char *ptr = string->p;
Packit c32a2d
	bytes = string->fill ? string->fill-1 : 0;
Packit c32a2d
Packit c32a2d
	while(bytes)
Packit c32a2d
	{
Packit c32a2d
		result = win32_net_write(ws.local_socket, ptr, bytes);
Packit c32a2d
		if(result < 0 && WSAGetLastError() != WSAEINTR)
Packit c32a2d
		{
Packit c32a2d
			perror ("writing http string");
Packit c32a2d
			return FALSE;
Packit c32a2d
		}
Packit c32a2d
		else if(result == 0)
Packit c32a2d
		{
Packit c32a2d
			error("write: socket closed unexpectedly");
Packit c32a2d
			return FALSE;
Packit c32a2d
		}
Packit c32a2d
		ptr   += result;
Packit c32a2d
		bytes -= result;
Packit c32a2d
	}
Packit c32a2d
	return TRUE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int win32_net_resolve_redirect(mpg123_string *response, mpg123_string *request_url, mpg123_string *purl)
Packit c32a2d
{
Packit c32a2d
	debug1("request_url:%s", request_url->p);
Packit c32a2d
	/* initialized with full old url */
Packit c32a2d
	if(!mpg123_copy_string(request_url, purl)) return FALSE;
Packit c32a2d
Packit c32a2d
	/* We may strip it down to a prefix ot totally. */
Packit c32a2d
	if(strncasecmp(response->p, "Location: http://", 17))
Packit c32a2d
	{ /* OK, only partial strip, need prefix for relative path. */
Packit c32a2d
		char* ptmp = NULL;
Packit c32a2d
		/* though it's not RFC (?), accept relative URIs as wget does */
Packit c32a2d
		fprintf(stderr, "NOTE: no complete URL in redirect, constructing one\n");
Packit c32a2d
		/* not absolute uri, could still be server-absolute */
Packit c32a2d
		/* I prepend a part of the request... out of the request */
Packit c32a2d
		if(response->p[10] == '/')
Packit c32a2d
		{
Packit c32a2d
			/* only prepend http://server/ */
Packit c32a2d
			/* I null the first / after http:// */
Packit c32a2d
			ptmp = strchr(purl->p+7,'/');
Packit c32a2d
			if(ptmp != NULL){ purl->fill = ptmp-purl->p+1; purl->p[purl->fill-1] = 0; }
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			/* prepend http://server/path/ */
Packit c32a2d
			/* now we want the last / */
Packit c32a2d
			ptmp = strrchr(purl->p+7, '/');
Packit c32a2d
			if(ptmp != NULL){ purl->fill = ptmp-purl->p+2; purl->p[purl->fill-1] = 0; }
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	else purl->fill = 0;
Packit c32a2d
Packit c32a2d
	debug1("prefix=%s", purl->fill ? purl->p : "");
Packit c32a2d
	if(!mpg123_add_string(purl, response->p+10)) return FALSE;
Packit c32a2d
Packit c32a2d
	debug1("           purl: %s", purl->p);
Packit c32a2d
	debug1("old request_url: %s", request_url->p);
Packit c32a2d
Packit c32a2d
	return TRUE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int win32_net_http_open(char* url, struct httpdata *hd)
Packit c32a2d
{
Packit c32a2d
	mpg123_string purl, host, port, path;
Packit c32a2d
	mpg123_string request, response, request_url;
Packit c32a2d
	mpg123_string httpauth1;
Packit c32a2d
	ws.local_socket = SOCKET_ERROR;
Packit c32a2d
	int oom  = 0;
Packit c32a2d
	int relocate, numrelocs = 0;
Packit c32a2d
	int got_location = FALSE;
Packit c32a2d
	/*
Packit c32a2d
		workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls
Packit c32a2d
		this site's apache gives me a relocation to the same place when I give the port in Host request field
Packit c32a2d
		for the record: Apache/2.0.51 (Fedora)
Packit c32a2d
	*/
Packit c32a2d
	int try_without_port = 0;
Packit c32a2d
	mpg123_init_string(&purl);
Packit c32a2d
	mpg123_init_string(&host);
Packit c32a2d
	mpg123_init_string(&port);
Packit c32a2d
	mpg123_init_string(&path);
Packit c32a2d
	mpg123_init_string(&request);
Packit c32a2d
	mpg123_init_string(&response);
Packit c32a2d
	mpg123_init_string(&request_url);
Packit c32a2d
	mpg123_init_string(&httpauth1);
Packit c32a2d
Packit c32a2d
	/* Get initial info for proxy server. Once. */
Packit c32a2d
	if(hd->proxystate == PROXY_UNKNOWN && !proxy_init(hd)) goto exit;
Packit c32a2d
Packit c32a2d
	if(!translate_url(url, &purl)){ oom=1; goto exit; }
Packit c32a2d
Packit c32a2d
	/* Don't confuse the different auth strings... */
Packit c32a2d
	if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; }
Packit c32a2d
Packit c32a2d
	/* "GET http://"		11
Packit c32a2d
	 * " HTTP/1.0\r\nUser-Agent: <PACKAGE_NAME>/<PACKAGE_VERSION>\r\n"
Packit c32a2d
	 * 				26 + PACKAGE_NAME + PACKAGE_VERSION
Packit c32a2d
	 * accept header            + accept_length()
Packit c32a2d
	 * "Authorization: Basic \r\n"	23
Packit c32a2d
	 * "\r\n"			 2
Packit c32a2d
	 * ... plus the other predefined header lines
Packit c32a2d
	 */
Packit c32a2d
	/* Just use this estimate as first guess to reduce malloc calls in string library. */
Packit c32a2d
	{
Packit c32a2d
		size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION) 
Packit c32a2d
		                       + accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill;
Packit c32a2d
		if(    !mpg123_grow_string(&request, length_estimate)
Packit c32a2d
		    || !mpg123_grow_string(&response,4096) )
Packit c32a2d
		{
Packit c32a2d
			oom=1; goto exit;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	do
Packit c32a2d
	{
Packit c32a2d
		/* Storing the request url, with http:// prepended if needed. */
Packit c32a2d
		/* used to be url here... seemed wrong to me (when loop advanced...) */
Packit c32a2d
		if(strncasecmp(purl.p, "http://", 7) != 0) mpg123_set_string(&request_url, "http://");
Packit c32a2d
		else mpg123_set_string(&request_url, "");
Packit c32a2d
Packit c32a2d
		mpg123_add_string(&request_url, purl.p);
Packit c32a2d
Packit c32a2d
		if(!split_url(&purl, NULL, &host, &port, &path)){ oom=1; goto exit; }
Packit c32a2d
		if (hd->proxystate >= PROXY_HOST)
Packit c32a2d
		{
Packit c32a2d
			/* We will connect to proxy, full URL goes into the request. */
Packit c32a2d
			if(    !mpg123_set_string(&request, "GET ")
Packit c32a2d
			    || !mpg123_add_string(&request, request_url.p) )
Packit c32a2d
			{
Packit c32a2d
				oom=1; goto exit;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			/* We will connect to the host from the URL and only the path goes into the request. */
Packit c32a2d
			if(    !mpg123_set_string(&request, "GET ")
Packit c32a2d
			    || !mpg123_add_string(&request, path.p) )
Packit c32a2d
			{
Packit c32a2d
				oom=1; goto exit;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; }
Packit c32a2d
Packit c32a2d
		httpauth1.fill = 0; /* We use the auth data from the URL only once. */
Packit c32a2d
		if (hd->proxystate >= PROXY_HOST)
Packit c32a2d
		{
Packit c32a2d
			if(    !mpg123_copy_string(&hd->proxyhost, &host)
Packit c32a2d
			    || !mpg123_copy_string(&hd->proxyport, &port) )
Packit c32a2d
			{
Packit c32a2d
				oom=1; goto exit;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
		debug2("attempting to open_connection to %s:%s", host.p, port.p);
Packit c32a2d
		win32_net_open_connection(&host, &port);
Packit c32a2d
		if(ws.local_socket == SOCKET_ERROR)
Packit c32a2d
		{
Packit c32a2d
			error1("Unable to establish connection to %s", host.fill ? host.p : "");
Packit c32a2d
			goto exit;
Packit c32a2d
		}
Packit c32a2d
		debug("win32_net_open_connection succeed");
Packit c32a2d
#define http_failure win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; goto exit;
Packit c32a2d
		
Packit c32a2d
		if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p);
Packit c32a2d
		if(!win32_net_writestring(ws.local_socket, &request)){ http_failure; }
Packit c32a2d
		debug("Skipping fdopen for WSA sockets");
Packit c32a2d
		relocate = FALSE;
Packit c32a2d
		/* Arbitrary length limit here... */
Packit c32a2d
#define safe_readstring \
Packit c32a2d
		win32_net_readstring(&response, SIZE_MAX/16, -1); \
Packit c32a2d
		if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \
Packit c32a2d
		{ \
Packit c32a2d
			error("HTTP response line exceeds max. length"); \
Packit c32a2d
			http_failure; \
Packit c32a2d
		} \
Packit c32a2d
		else if(response.fill == 0) \
Packit c32a2d
		{ \
Packit c32a2d
			error("readstring failed"); \
Packit c32a2d
			http_failure; \
Packit c32a2d
		} \
Packit c32a2d
		if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p);
Packit c32a2d
		safe_readstring;
Packit c32a2d
Packit c32a2d
		{
Packit c32a2d
			char *sptr;
Packit c32a2d
			if((sptr = strchr(response.p, ' ')))
Packit c32a2d
			{
Packit c32a2d
				if(response.fill > sptr-response.p+2)
Packit c32a2d
				switch (sptr[1])
Packit c32a2d
				{
Packit c32a2d
					case '3':
Packit c32a2d
						relocate = TRUE;
Packit c32a2d
					case '2':
Packit c32a2d
						break;
Packit c32a2d
					default:
Packit c32a2d
						fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */
Packit c32a2d
						http_failure;
Packit c32a2d
				}
Packit c32a2d
				else{ error("Too short response,"); http_failure; }
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		/* If we are relocated, we need to look out for a Location header. */
Packit c32a2d
		got_location = FALSE;
Packit c32a2d
Packit c32a2d
		do
Packit c32a2d
		{
Packit c32a2d
			safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */
Packit c32a2d
			if (!strncasecmp(response.p, "Location: ", 10))
Packit c32a2d
			{ /* It is a redirection! */
Packit c32a2d
				if(!win32_net_resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; }
Packit c32a2d
Packit c32a2d
				if(!strcmp(purl.p, request_url.p))
Packit c32a2d
				{
Packit c32a2d
					warning("relocated to very same place! trying request again without host port");
Packit c32a2d
					try_without_port = 1;
Packit c32a2d
				}
Packit c32a2d
				got_location = TRUE;
Packit c32a2d
			}
Packit c32a2d
			else
Packit c32a2d
			{ /* We got a header line (or the closing empty line). */
Packit c32a2d
				char *tmp;
Packit c32a2d
				debug1("searching for header values... %s", response.p);
Packit c32a2d
				/* Not sure if I want to bail out on error here. */
Packit c32a2d
				/* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */
Packit c32a2d
				get_header_string(&response, "content-type", &hd->content_type);
Packit c32a2d
				get_header_string(&response, "icy-name",     &hd->icy_name);
Packit c32a2d
				get_header_string(&response, "icy-url",      &hd->icy_url);
Packit c32a2d
Packit c32a2d
				/* watch out for icy-metaint */
Packit c32a2d
				if((tmp = get_header_val("icy-metaint", &response)))
Packit c32a2d
				{
Packit c32a2d
					hd->icy_interval = (off_t) atol(tmp); /* atoll ? */
Packit c32a2d
					debug1("got icy-metaint %li", (long int)hd->icy_interval);
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
		} while(response.p[0] != '\r' && response.p[0] != '\n');
Packit c32a2d
		if (relocate) { win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; }
Packit c32a2d
	} while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS);
Packit c32a2d
	if(relocate)
Packit c32a2d
	{
Packit c32a2d
		if(!got_location)
Packit c32a2d
		error("Server meant to redirect but failed to provide a location!");
Packit c32a2d
		else
Packit c32a2d
		error1("Too many HTTP relocations (%i).", numrelocs);
Packit c32a2d
Packit c32a2d
		http_failure;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
exit: /* The end as well as the exception handling point... */
Packit c32a2d
	if(oom) error("Apparently, I ran out of memory or had some bad input data...");
Packit c32a2d
Packit c32a2d
	mpg123_free_string(&purl);
Packit c32a2d
	mpg123_free_string(&host);
Packit c32a2d
	mpg123_free_string(&port);
Packit c32a2d
	mpg123_free_string(&path);
Packit c32a2d
	mpg123_free_string(&request);
Packit c32a2d
	mpg123_free_string(&response);
Packit c32a2d
	mpg123_free_string(&request_url);
Packit c32a2d
	mpg123_free_string(&httpauth1);
Packit c32a2d
	if (ws.local_socket == SOCKET_ERROR || oom)
Packit c32a2d
	return -1;
Packit c32a2d
	else
Packit c32a2d
	return 1;
Packit c32a2d
}
Packit c32a2d
#else
Packit c32a2d
int win32_net_http_open(char* url, struct httpdata *hd)
Packit c32a2d
{
Packit c32a2d
  return -1;
Packit c32a2d
}
Packit c32a2d
#endif /*WANT_WIN32_SOCKETS */