OSDN Git Service

WebGUIのレスポンスが悪かったのを修正
[peercast-im/PeerCastIM.git] / PeerCast.root / PeerCast / core / common / url.cpp
1 // ------------------------------------------------
2 // File : url.h
3 // Date: 20-feb-2004
4 // Author: giles
5 //
6 // (c) 2002-4 peercast.org
7 // ------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 // ------------------------------------------------
18
19 #include "url.h"
20 #include "socket.h"
21 #include "http.h"
22 #include "servent.h"
23 #include "servmgr.h"
24 #include "peercast.h"
25 #include "version2.h"
26 #ifdef _DEBUG
27 #include "chkMemoryLeak.h"
28 #define DEBUG_NEW new(__FILE__, __LINE__)
29 #define new DEBUG_NEW
30 #endif
31
32 // ------------------------------------------------
33 void URLSource::stream(Channel *ch)
34 {
35         
36         String url,tmpUrl;
37         while (ch->thread.active && !peercastInst->isQuitting)
38         {
39                 tmpUrl = url;
40                 if (url.isEmpty())
41                         url = baseurl;
42
43                 url = streamURL(ch,url.cstr());
44                 if (url == tmpUrl){
45                         sys->sleep(2000);
46                 }
47         }
48
49 }
50 // ------------------------------------------------
51 int URLSource::getSourceRate()
52 {
53         if (inputStream)
54                 return inputStream->bytesInPerSec;
55         else
56                 return 0;
57 }
58
59 // ------------------------------------------------
60 ::String URLSource::streamURL(Channel *ch, const char *url)
61 {
62         String nextURL;
63
64         if (peercastInst->isQuitting || !ch->thread.active)
65                 return nextURL;
66
67
68         String urlTmp;
69         urlTmp.set(url);
70
71         char *fileName = urlTmp.cstr();
72
73         PlayList *pls=NULL;
74         ChannelStream *source=NULL;
75
76         LOG_CHANNEL("Fetch URL=%s",fileName);
77
78         try
79         {
80
81                 // get the source protocol
82                 if (strnicmp(fileName,"http://",7)==0)  
83                 {
84                         ch->info.srcProtocol = ChanInfo::SP_HTTP;
85                         fileName += 7;
86                 }
87                 else if (strnicmp(fileName,"mms://",6)==0)      
88                 {
89                         ch->info.srcProtocol = ChanInfo::SP_MMS;
90                         fileName += 6;
91                 }
92                 else if (strnicmp(fileName,"pcp://",6)==0)      
93                 {
94                         ch->info.srcProtocol = ChanInfo::SP_PCP;
95                         fileName += 6;
96                 }
97                 else if (strnicmp(fileName,"file://",7)==0)     
98                 {
99                         ch->info.srcProtocol = ChanInfo::SP_FILE;
100                         fileName += 7;
101                 }
102                 else 
103                 {
104                         ch->info.srcProtocol = ChanInfo::SP_FILE;
105                 }
106
107                 // default to mp3 for shoutcast servers
108                 if (ch->info.contentType == ChanInfo::T_PLS)
109                         ch->info.contentType = ChanInfo::T_MP3;
110
111
112                 ch->setStatus(Channel::S_CONNECTING);
113
114                 if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
115                 {
116
117                         if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
118                                 ch->info.srcProtocol = ChanInfo::SP_MMS;
119
120                         
121                         LOG_CHANNEL("Channel source is HTTP");
122
123                         ClientSocket *inputSocket = sys->createSocket();
124                         if (!inputSocket)
125                                 throw StreamException("Channel cannot create socket");
126
127
128                         inputStream = inputSocket;
129
130
131                         char *dir = strstr(fileName,"/");
132                         if (dir)
133                                 *dir++=0;
134
135
136                         LOG_CHANNEL("Fetch Host=%s",fileName);
137                         if (dir)
138                                 LOG_CHANNEL("Fetch Dir=%s",dir);
139
140
141                         Host host;
142                         host.fromStrName(fileName,80);
143
144                         inputSocket->open(host);
145                         inputSocket->connect();
146
147                         HTTP http(*inputSocket);
148                         http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
149
150                         http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
151                         http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
152                         http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
153
154                         if (ch->info.srcProtocol == ChanInfo::SP_MMS)
155                         {
156                                 http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
157                                 http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
158                                 //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
159                                 http.writeLine("Pragma: xPlayStrm=1");
160                                 http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
161                                 http.writeLine("Pragma: stream-switch-count=2");
162                                 http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
163                         }else
164                         {
165                                 http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);  
166                                 http.writeLineF("%s %d",PCX_HS_PCP,1);  
167                                 http.writeLine("Icy-MetaData:1");                               // fix by ravon 
168                         }
169
170                         http.writeLine("");
171
172                         int res = http.readResponse();
173
174
175                         String name = ch->info.name;
176
177                         while (http.nextHeader())
178                         {                               
179
180                                 LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
181
182                                 ChanInfo tmpInfo = ch->info;
183                                 Servent::readICYHeader(http, ch->info, NULL, 0);
184
185                                 if (!tmpInfo.name.isEmpty())
186                                         ch->info.name = tmpInfo.name;
187                                 if (!tmpInfo.genre.isEmpty())
188                                         ch->info.genre = tmpInfo.genre;
189                                 if (!tmpInfo.url.isEmpty())
190                                         ch->info.url = tmpInfo.url;
191
192                                 if (http.isHeader("icy-metaint"))
193                                         ch->icyMetaInterval = http.getArgInt();
194                                 else if (http.isHeader("Location:"))
195                                         nextURL.set(http.getArgStr());
196
197                                 char *arg = http.getArgStr();
198                                 if (arg)
199                                 {
200                                         if (http.isHeader("content-type"))
201                                         {
202                                                 if (stristr(arg,MIME_XSCPLS))
203                                                         pls = new PlayList(PlayList::T_SCPLS, 1000);
204                                                 else if (stristr(arg,MIME_PLS))
205                                                         pls = new PlayList(PlayList::T_PLS, 1000);
206                                                 else if (stristr(arg,MIME_XPLS))
207                                                         pls = new PlayList(PlayList::T_PLS, 1000);
208                                                 else if (stristr(arg,MIME_M3U))
209                                                         pls = new PlayList(PlayList::T_PLS, 1000);
210                                                 else if (stristr(arg,MIME_TEXT))
211                                                         pls = new PlayList(PlayList::T_PLS, 1000);
212                                                 else if (stristr(arg,MIME_ASX))
213                                                         pls = new PlayList(PlayList::T_ASX, 1000);
214                                                 else if (stristr(arg,MIME_MMS))
215                                                         ch->info.srcProtocol = ChanInfo::SP_MMS;
216                                         }
217                                 }
218
219                         }
220
221                         if ((!nextURL.isEmpty()) && (res==302))
222                         {
223                                 LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
224                                 inputSocket->close();
225                                 delete inputSocket;
226                                 inputSocket = NULL;
227                                 return nextURL;
228                         }
229
230                         if (res!=200)
231                         {
232                                 LOG_ERROR("HTTP response: %d",res);
233                                 throw StreamException("Bad HTTP connect");
234                         }
235
236
237                 }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
238                 {
239
240                         LOG_CHANNEL("Channel source is FILE");
241
242                         FileStream *fs = new FileStream();
243                         fs->openReadOnly(fileName);
244                         inputStream = fs;
245
246                         ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
247                         // if filetype is unknown, try and figure it out from file extension.
248                         //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
249                         {
250                                 const char *ext = fileName+strlen(fileName);
251                                 while (*--ext)
252                                         if (*ext=='.')
253                                         {
254                                                 ext++;
255                                                 break;
256                                         }
257
258                                 fileType = ChanInfo::getTypeFromStr(ext);
259                         }
260
261
262                         if (ch->info.bitrate)
263                                 ch->readDelay = true;
264
265
266                         if (fileType == ChanInfo::T_PLS) 
267                                 pls = new PlayList(PlayList::T_PLS, 1000);
268                         else if (fileType == ChanInfo::T_ASX) 
269                                 pls = new PlayList(PlayList::T_ASX, 1000);
270                         else
271                                 ch->info.contentType = fileType;
272
273                 }else
274                 {
275                         throw StreamException("Unsupported URL");
276                 }
277
278                 
279                 if (pls)
280                 {
281
282                         LOG_CHANNEL("Channel is Playlist");
283
284                         pls->read(*inputStream);
285
286                         inputStream->close();
287                         delete inputStream;
288                         inputStream = NULL;
289
290                         int urlNum=0;
291                         String url;
292
293                         LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
294                         while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
295                         {
296                                 if (url.isEmpty())
297                                 {
298                                         url = pls->urls[urlNum%pls->numURLs];
299                                         urlNum++;
300                                 }
301                                 try
302                                 {
303                                         url = streamURL(ch,url.cstr());
304                                 }catch(StreamException &)
305                                 {}
306                         }
307
308                         delete pls;
309                         
310                 }else
311                 {
312
313                         // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
314                         if (!ch->info.id.isSet())
315                         {
316                                 ch->info.id = chanMgr->broadcastID;
317                                 ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
318                         }
319
320                         if (ch->info.contentType == ChanInfo::T_ASX)
321                                 ch->info.contentType = ChanInfo::T_WMV;
322
323                         ch->setStatus(Channel::S_BROADCASTING);
324
325                         inputStream->setReadTimeout(60);        // use longer read timeout
326
327                         source = ch->createSource();
328
329                         ch->readStream(*inputStream,source);
330
331                         inputStream->close();
332                 }
333
334         }catch(StreamException &e)
335         {
336                 ch->setStatus(Channel::S_ERROR);
337                 LOG_ERROR("Channel error: %s",e.msg);
338                 sys->sleep(1000);
339         }
340
341
342         ch->setStatus(Channel::S_CLOSING);
343         if (inputStream)
344         {
345                 delete inputStream;
346                 inputStream = NULL;
347         }
348
349         if (source)
350                 delete source;
351
352
353         return nextURL;
354
355 }