1 /* MPEG/WAVE Sound library
2 
3    (C) 1997 by Woo-jae Jung */
4 
5 // Httpinputstream.cc
6 // Inputstream for http
7 
8 // It's from mpg123
9 
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #include <sys/stat.h>
15 #include <unistd.h>
16 
17 #include "mpegsound.h"
18 #include "mpegsound_locals.h"
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <netdb.h>
23 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #ifdef HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32 
33 #ifndef INADDR_NONE
34 #define INADDR_NONE 0xffffffff
35 #endif
36 
37 static const char *httpstr="http://";
38 
writestring(int fd,char * string)39 bool Soundinputstreamfromhttp::writestring(int fd, char *string)
40 {
41   int result,bytes=strlen(string);
42 
43   while(bytes)
44   {
45     if((result=write(fd,string,bytes))<0 && errno!=EINTR)
46     {
47       seterrorcode(SOUND_ERROR_HTTPWRITEFAIL);
48       return false;
49     }
50     else if(result==0)
51     {
52       seterrorcode(SOUND_ERROR_HTTPWRITEFAIL);
53       return false;
54     }
55     string += result;
56     bytes -= result;
57   }
58 
59   return true;
60 }
61 
readstring(char * string,int maxlen,FILE * f)62 bool Soundinputstreamfromhttp::readstring(char *string,int maxlen,FILE *f)
63 {
64   char *result;
65 
66   do{
67     result=fgets(string,maxlen,f);
68   }while(!result  && errno==EINTR);
69   if(!result)
70   {
71     seterrorcode(SOUND_ERROR_FILEREADFAIL);
72     return false;
73   }
74 
75   return true;
76 }
77 
strndup(char * src,int num)78 static char *strndup(char *src,int num)
79 {
80   char *dst;
81 
82   if(!(dst=(char *)malloc(num+1)))return NULL;
83   dst[num]='\0';
84 
85   return strncpy(dst, src, num);
86 }
87 
url2hostport(char * url,char ** hname,unsigned long * hip,unsigned int * port)88 static char *url2hostport(char *url,char **hname,
89 			  unsigned long *hip,unsigned int *port)
90 {
91   char *cptr;
92   struct hostent *myhostent;
93   struct in_addr myaddr;
94   int isip=1;
95 
96   if(!(strncmp(url,httpstr,7)))url+=7;
97   cptr=url;
98   while(*cptr && *cptr!=':' && *cptr!='/')
99   {
100     if((*cptr<'0' || *cptr>'9') && *cptr!='.')isip=0;
101     cptr++;
102   }
103   if(!(*hname=strndup(url,cptr-url)))
104   {
105     *hname=NULL;
106     return NULL;
107   }
108   if(!isip)
109   {
110     if (!(myhostent=gethostbyname(*hname)))return NULL;
111     memcpy(&myaddr,myhostent->h_addr,sizeof(myaddr));
112     *hip=myaddr.s_addr;
113   }
114   else if((*hip=inet_addr(*hname))==INADDR_NONE)return NULL;
115   if(!*cptr || *cptr=='/')
116   {
117     *port=80;
118     return cptr;
119   }
120   *port=atoi(++cptr);
121   while(*cptr && *cptr!='/')cptr++;
122   return cptr;
123 }
124 
125 char *proxyurl=NULL;
126 unsigned long proxyip=0;
127 unsigned int proxyport;
128 
129 FILE
http_open(const char * urrel)130 *Soundinputstreamfromhttp::http_open(const char *urrel)
131 {
132 	char
133 		*purl=NULL,
134 		*host = NULL,
135 		*request = NULL,
136 		*sptr = NULL,
137 		*url = NULL;
138 	char agent[50];
139 	const char *url_part;
140 	int linelength;
141 	int sock;
142 	int relocate=0,numrelocs=0;
143 	int slash_count = 0;
144 	unsigned long myip;
145 	unsigned int myport;
146 	struct sockaddr_in server;
147 	FILE *myfile;
148 
149 	url = new char[strlen(urrel) + 2];
150 	strcpy(url, urrel);
151 
152 	//find hostname from URL
153 	url_part = url;
154 	while ( (url_part = strchr(url_part, '/')) != NULL)
155 	{
156 		url_part++;
157 		slash_count++;
158 	}
159 
160 	if (strlen(url) > 0 && url[strlen(url)-1] != '/' && slash_count == 2)
161 	{
162 		//add a trailing slash after the url's hostname
163 		url[strlen(url)] = '/';
164 		url[strlen(url)+1] = '\0';
165 	}
166 
167 	if (!proxyip)
168 	{
169 		if (!proxyurl && !(proxyurl=getenv("MP3_HTTP_PROXY")) &&
170 			!(proxyurl=getenv("http_proxy")))
171 		{
172 			proxyurl = getenv("HTTP_PROXY");
173 		}
174 
175 		if (proxyurl && proxyurl[0] && strcmp(proxyurl, "none"))
176 		{
177 			if (!(url2hostport(proxyurl, &host, &proxyip, &proxyport)))
178 			{
179 				seterrorcode(SOUND_ERROR_UNKNOWNPROXY);
180 				return NULL;
181 			}
182 			if (host)
183 			{
184 				free(host);
185 				host = NULL;
186 			}
187 		}
188 		else
189 			proxyip = INADDR_NONE;
190 	}
191 
192 	if (!(purl=(char *)malloc(1024)))
193 	{
194 		seterrorcode(SOUND_ERROR_MEMORYNOTENOUGH);
195 		delete[] url;
196 		return NULL;
197 	}
198 	strncpy(purl,url,1022);
199 	purl[1022]= purl[1023] = '\0';
200 	delete[] url;
201 	url = NULL;
202 	request = NULL;
203 
204 	do
205 	{
206 		if (request)
207 			free(request);
208 
209 		if ((linelength = strlen(purl) * 2 + 100) < 1024)
210 			linelength=1024;
211 		if (!(request=(char *)malloc(linelength)))
212 		{
213 			seterrorcode(SOUND_ERROR_MEMORYNOTENOUGH);
214 			free(purl);
215 			return NULL;
216 		}
217 		if (host)
218 			free(host);
219 		host = NULL;
220 		strcpy(request,"GET ");
221 		if (proxyip!=INADDR_NONE)
222 		{
223 			if(strncmp(purl,httpstr,7))
224 				strcat(request,httpstr);
225 			strcat(request,purl);
226 			myport=proxyport;
227 			myip=proxyip;
228 		}
229 		else
230 		{
231 			if (!(sptr=url2hostport(purl,&host,&myip,&myport)))
232 			{
233 				seterrorcode(SOUND_ERROR_UNKNOWNHOST);
234 				free(purl);
235 				free(request);
236 				return NULL;
237 			}
238 			strcat (request, sptr);
239 		}
240 
241 		strcat(request, " HTTP/1.1\r\n");
242 		if (host && proxyip == INADDR_NONE)
243 		{
244 			strcat(request, "Host: ");
245 			strcat(request, host);
246 			strcat(request, "\r\n");
247 			free(host);
248 			host = NULL;
249 		}
250 		sprintf (agent, "User-Agent: %s/%s\r\n\r\n",
251 			 "Mp3blaster",VERSION);
252 		strcat (request, agent);
253 		debug("HTTP Request:\n\n%s", request);
254 		server.sin_family = AF_INET;
255 		server.sin_port = htons(myport);
256 		server.sin_addr.s_addr = myip;
257 		if ((sock=socket(PF_INET,SOCK_STREAM,6))<0)
258 		{
259 			seterrorcode(SOUND_ERROR_SOCKET);
260 			free(purl);
261 			free(request);
262 			return NULL;
263 		}
264 		if (connect(sock,(struct sockaddr *)&server,sizeof(server)))
265 		{
266 			seterrorcode(SOUND_ERROR_CONNECT);
267 			free(purl);
268 			free(request);
269 			return NULL;
270 		}
271 		if (!writestring(sock,request))
272 		{
273 			free(purl);
274 			free(request);
275 			return NULL;
276 		}
277 
278 		if (!(myfile=fdopen(sock, "rb")))
279 		{
280 			seterrorcode(SOUND_ERROR_FDOPEN);
281 			free(purl);
282 			return NULL;
283 		};
284 
285 		relocate=false;
286 		purl[0]='\0';
287 
288 		if (!readstring(request,linelength-1,myfile))
289 		{
290 			free(purl);
291 			free(request);
292 			return NULL;
293 		}
294 
295 		if ((sptr=strchr(request,' ')))
296 		{
297 			switch(sptr[1])
298 			{
299 				case '3':relocate=true;
300 				case '2':break;
301 				default: seterrorcode(SOUND_ERROR_HTTPFAIL);
302 				free(purl);
303 				free(request);
304 				return NULL;
305 			}
306 		}
307 
308 		do
309 		{
310 			if (!readstring(request,linelength-1,myfile))
311 			{
312 				free(purl);
313 				free(request);
314 				return NULL;
315 			}
316 			if (!strncmp(request,"Location:",9))
317 				strncpy (purl,request+10,1023);
318 		} while (request[0]!='\r' && request[0]!='n');
319 	} while (relocate && purl[0] && numrelocs++<5);
320 
321 	if (relocate)
322 	{
323 		seterrorcode(SOUND_ERROR_TOOMANYRELOC);
324 		return NULL;
325 	}
326 
327 	free(purl);
328 	free(request);
329 
330 	return myfile;
331 }
332 
Soundinputstreamfromhttp()333 Soundinputstreamfromhttp::Soundinputstreamfromhttp()
334 {
335   fp=NULL;
336   __canseek = false;
337 }
338 
~Soundinputstreamfromhttp()339 Soundinputstreamfromhttp::~Soundinputstreamfromhttp()
340 {
341   if(fp)fclose(fp);
342 }
343 
open(const char * url)344 bool Soundinputstreamfromhttp::open(const char *url)
345 {
346   if((fp=http_open(url))==NULL)
347   {
348 		debug("Could not open url..\n");
349     seterrorcode(SOUND_ERROR_FILEOPENFAIL);
350     return false;
351   }
352 
353 	debug("url opened\n");
354   return true;
355 }
356 
getbytedirect(void)357 int Soundinputstreamfromhttp::getbytedirect(void)
358 {
359   int c;
360 
361   if((c=getc(fp))<0)
362   {
363     seterrorcode(SOUND_ERROR_FILEREADFAIL);
364     return -1;
365   }
366 
367   return c;
368 }
369 
_readbuffer(char * buffer,int size)370 bool Soundinputstreamfromhttp::_readbuffer(char *buffer,int size)
371 {
372   if(fread(buffer,size,1,fp)!=1)
373   {
374     seterrorcode(SOUND_ERROR_FILEREADFAIL);
375     return false;
376   }
377   return true;
378 }
379 
eof(void)380 bool Soundinputstreamfromhttp::eof(void)
381 {
382   return feof(fp);
383 };
384 
getblock(char * buffer,int size)385 int Soundinputstreamfromhttp::getblock(char *buffer,int size)
386 {
387   int l;
388   l=fread(buffer,1,size,fp);
389   if(l==0)seterrorcode(SOUND_ERROR_FILEREADFAIL);
390   return l;
391 }
392 
getsize(void)393 int Soundinputstreamfromhttp::getsize(void)
394 {
395   return 1;
396 }
397 
setposition(int)398 void Soundinputstreamfromhttp::setposition(int)
399 {
400 }
401 
getposition(void)402 int  Soundinputstreamfromhttp::getposition(void)
403 {
404   return 0;
405 }
406 
407