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