OSDN Git Service

9c3740ed23c736fc9978ba41be56699a43dba8c0
[peercast-im/PeerCastIM.git] / c: / Git / PeerCast.root / PeerCast / core / common / channel.cpp
1 // ------------------------------------------------
2 // File : channel.cpp
3 // Date: 4-apr-2002
4 // Author: giles
5 // Desc: 
6 //              Channel streaming classes. These do the actual 
7 //              streaming of media between clients. 
8 //
9 // (c) 2002 peercast.org
10 // 
11 // ------------------------------------------------
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 // ------------------------------------------------
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include "common.h"
26 #include "socket.h"
27 #include "channel.h"
28 #include "gnutella.h"
29 #include "servent.h"
30 #include "servmgr.h"
31 #include "sys.h"
32 #include "xml.h"
33 #include "http.h"
34 #include "peercast.h"
35 #include "atom.h"
36 #include "pcp.h"
37
38 #include "mp3.h"
39 #include "ogg.h"
40 #include "mms.h"
41 #include "nsv.h"
42
43 #include "icy.h"
44 #include "url.h"
45
46 #include "version2.h"
47 #ifdef _DEBUG
48 #include "chkMemoryLeak.h"
49 #define DEBUG_NEW new(__FILE__, __LINE__)
50 #define new DEBUG_NEW
51 #endif
52
53 // -----------------------------------
54 char *Channel::srcTypes[]=
55 {
56         "NONE",
57         "PEERCAST",
58         "SHOUTCAST",
59         "ICECAST",
60         "URL"
61 };
62 // -----------------------------------
63 char *Channel::statusMsgs[]=
64 {
65         "NONE",
66         "WAIT",
67         "CONNECT",
68         "REQUEST",
69         "CLOSE",
70         "RECEIVE",
71         "BROADCAST",
72         "ABORT",
73         "SEARCH",
74         "NOHOSTS",
75         "IDLE",
76         "ERROR",
77         "NOTFOUND"
78 };
79
80
81 // for PCRaw start.
82 bool isIndexTxt(ChanInfo *info)
83 {
84         size_t len;
85
86         if(     info &&
87                 info->contentType == ChanInfo::T_RAW &&
88                 info->bitrate <= 32 &&
89                 (len = strlen(info->name.cstr())) >= 9 &&
90                 !memcmp(info->name.cstr(), "index", 5) &&
91                 !memcmp(info->name.cstr()+len-4, ".txt", 4))
92         {
93                 return true;
94         }
95         else
96         {
97                 return false;
98         }
99 }
100
101 bool isIndexTxt(Channel *ch)
102 {
103         if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
104                 return true;
105         else
106                 return false;
107 }
108
109 int numMaxRelaysIndexTxt(Channel *ch)
110 {
111         return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
112 }
113
114 int canStreamIndexTxt(Channel *ch)
115 {
116         int ret;
117
118         // \8e©\95ª\82ª\94z\90M\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\8aÖ\8cW\82È\82¢
119         if(!ch || ch->isBroadcasting())
120                 return -1;
121
122         ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
123         if(ret < 0)
124                 ret = 0;
125
126         return ret;
127 }
128 // for PCRaw end.
129
130 // -----------------------------------
131 void readXMLString(String &str, XML::Node *n, const char *arg)
132 {
133         char *p;
134         p = n->findAttr(arg);
135         if (p)
136         {
137                 str.set(p,String::T_HTML);
138                 str.convertTo(String::T_ASCII);
139         }
140 }
141
142 int channel_count=1;
143 // -----------------------------------------------------------------------------
144 // Initialise the channel to its default settings of unallocated and reset.
145 // -----------------------------------------------------------------------------
146 Channel::Channel() : maxRelays(0)
147 {
148         next = NULL;
149         reset();
150         channel_id = channel_count++;
151 }
152 // -----------------------------------------------------------------------------
153 void Channel::endThread(bool flg)
154 {
155         if (pushSock)
156         {
157                 pushSock->close();
158                 delete pushSock;
159                 pushSock = NULL;
160         }
161
162         if (sock)
163         {
164                 sock->close();
165                 sock = NULL;
166         }
167
168         if (sourceData)
169         {
170                 delete sourceData;
171                 sourceData = NULL;
172         }
173
174         if (flg == true){
175                 reset();
176
177                 chanMgr->channellock.on();
178                 chanMgr->deleteChannel(this);
179                 chanMgr->channellock.off();
180
181                 sys->endThread(&thread);
182         }
183 }
184 // -----------------------------------------------------------------------------
185 void Channel::resetPlayTime()
186 {
187         info.lastPlayStart = sys->getTime();
188 }
189 // -----------------------------------------------------------------------------
190 void Channel::setStatus(STATUS s)
191 {
192         if (s != status)
193         {
194                 bool wasPlaying = isPlaying();
195
196                 status = s;
197
198                 if (isPlaying())
199                 {
200                         info.status = ChanInfo::S_PLAY;
201                         resetPlayTime();
202                 }else
203                 {
204                         if (wasPlaying)
205                                 info.lastPlayEnd = sys->getTime();
206                         info.status = ChanInfo::S_UNKNOWN;
207                 }
208
209                 if (isBroadcasting())
210                 {
211                         ChanHitList *chl = chanMgr->findHitListByID(info.id);
212                         if (!chl)
213                                 chanMgr->addHitList(info);
214                 }
215
216                 peercastApp->channelUpdate(&info);
217
218         }
219 }
220         
221 // -----------------------------------------------------------------------------
222 // Reset channel and make it available 
223 // -----------------------------------------------------------------------------
224 void Channel::reset()
225 {
226         sourceHost.init();
227         remoteID.clear();
228
229         streamIndex = 0;
230
231         lastIdleTime = 0;
232
233         info.init();
234
235         mount.clear();
236         bump = false;
237         stayConnected = false;
238         stealth = false; //JP-MOD
239         overrideMaxRelaysPerChannel = -1; //JP-MOD
240         bClap = false; //JP-MOD
241
242         icyMetaInterval = 0;
243         streamPos = 0;
244         skipCount = 0; //JP-EX
245         lastSkipTime = 0;
246
247         insertMeta.init();
248
249         headPack.init();
250
251         sourceStream = NULL;
252
253         rawData.init();
254         rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
255
256         setStatus(S_NONE);
257         type = T_NONE;
258
259         readDelay = false;
260         sock = NULL;
261         pushSock = NULL;
262
263         sourceURL.clear();
264         sourceData = NULL;
265
266         lastTrackerUpdate = 0;
267         lastMetaUpdate = 0;
268
269         srcType = SRC_NONE;
270
271
272         startTime = 0;
273         syncTime = 0;
274
275         channel_id = 0;
276         finthread = NULL;
277
278         trackerHit.init();
279 }
280
281 // -----------------------------------
282 void    Channel::newPacket(ChanPacket &pack)
283 {
284         if (pack.type != ChanPacket::T_PCP)
285         {
286                 rawData.writePacket(pack,true);
287         }
288 }
289
290
291 // -----------------------------------
292 bool    Channel::checkIdle()
293 {
294         return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
295 }
296
297 // -----------------------------------
298 bool    Channel::isFull()
299 {
300         // for PCRaw (relay) start.
301         if(isIndexTxt(this))
302         {
303                 int ret = canStreamIndexTxt(this);
304                 
305                 if(ret > 0)
306                         return false;
307                 else if(ret == 0)
308                         return true;
309         }
310         // for PCRaw (relay) end.
311
312         // \83`\83\83\83\93\83l\83\8b\8cÅ\97L\82Ì\83\8a\83\8c\81[\8fã\8cÀ\90Ý\92è\82ª\82 \82é\82©
313         if (maxRelays > 0)
314         {
315                 return localRelays() >= maxRelays;
316         } else
317         {
318                 return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
319         }
320 }
321 // -----------------------------------
322 int Channel::localRelays()
323 {
324         return servMgr->numStreams(info.id,Servent::T_RELAY,true);
325 }
326 // -----------------------------------
327 int Channel::localListeners()
328 {
329         return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
330 }
331
332 // -----------------------------------
333 int Channel::totalRelays()
334 {
335         int tot = 0;
336         ChanHitList *chl = chanMgr->findHitListByID(info.id);
337         if (chl)
338                 tot += chl->numHits();
339         return tot;
340 }
341 // -----------------------------------
342 int Channel::totalListeners()
343 {
344         int tot = localListeners();
345         ChanHitList *chl = chanMgr->findHitListByID(info.id);
346         if (chl)
347                 tot += chl->numListeners();
348         return tot;
349 }
350
351 // -----------------------------------
352 int Channel::totalClaps()       //JP-MOD
353 {
354         ChanHitList *chl = chanMgr->findHitListByID(info.id);
355         return chl ? chl->numClaps() : 0;
356 }
357
358 // -----------------------------------
359 void    Channel::startGet()
360 {
361         srcType = SRC_PEERCAST;
362         type = T_RELAY;
363         info.srcProtocol = ChanInfo::SP_PCP;
364
365
366         sourceData = new PeercastSource();
367
368         startStream();
369 }
370 // -----------------------------------
371 void    Channel::startURL(const char *u)
372 {
373         sourceURL.set(u);
374
375         srcType = SRC_URL;
376         type = T_BROADCAST;
377         stayConnected = true;
378
379         resetPlayTime();
380
381         sourceData = new URLSource(u);
382
383         startStream();
384
385 }
386 // -----------------------------------
387 void Channel::startStream()
388 {
389         thread.data = this;
390         thread.func = stream;
391         if (!sys->startThread(&thread))
392                 reset();
393 }
394
395 // -----------------------------------
396 void Channel::sleepUntil(double time)
397 {
398         double sleepTime = time - (sys->getDTime()-startTime);
399
400 //      LOG("sleep %g",sleepTime);
401         if (sleepTime > 0)
402         {
403                 if (sleepTime > 60) sleepTime = 60;
404
405                 double sleepMS = sleepTime*1000;
406
407                 sys->sleep((int)sleepMS);
408         }
409 }
410
411
412 // -----------------------------------
413 void Channel::checkReadDelay(unsigned int len)
414 {
415         if (readDelay)
416         {
417                 unsigned int time = (len*1000)/((info.bitrate*1024)/8);
418                 sys->sleep(time);
419         }
420
421
422 }
423
424
425 // -----------------------------------
426 THREAD_PROC     Channel::stream(ThreadInfo *thread)
427 {
428 //      thread->lock();
429
430         Channel *ch = (Channel *)thread->data;
431
432         LOG_CHANNEL("Channel started");
433
434         while (thread->active && !peercastInst->isQuitting && !thread->finish)
435         {
436                 ChanHitList *chl = chanMgr->findHitList(ch->info);
437                 if (!chl)
438                         chanMgr->addHitList(ch->info);
439
440                 ch->sourceData->stream(ch);
441
442                 LOG_CHANNEL("Channel stopped");
443                 ch->rawData.init();
444
445                 if (!ch->stayConnected)
446                 {
447                         thread->active = false;
448                         break;
449                 }else
450                 {
451                         if (!ch->info.lastPlayEnd)
452                                 ch->info.lastPlayEnd = sys->getTime();
453
454                         unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
455
456                         LOG_DEBUG("Channel sleeping for %d seconds",diff);
457                         for(unsigned int i=0; i<diff; i++)
458                         {
459                                 if (ch->info.lastPlayEnd == 0) // reconnected
460                                         break;
461                                 if (!thread->active || peercastInst->isQuitting){
462                                         thread->active = false;
463                                         break;
464                                 }
465                                 sys->sleep(1000);       
466                         }
467                 }
468         }
469
470         LOG_DEBUG("thread.active = %d, thread.finish = %d",
471                 ch->thread.active, ch->thread.finish);
472
473         if (!thread->finish){
474                 ch->endThread(false);
475
476                 if (!ch->finthread){
477                         ch->finthread = new ThreadInfo();
478                         ch->finthread->func = waitFinish;
479                         ch->finthread->data = ch;
480                         sys->startThread(ch->finthread);
481                 }
482         } else {
483                 ch->endThread(true);
484         }
485         return 0;
486 }       
487
488 // -----------------------------------
489 THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
490 {
491         Channel *ch = (Channel*)thread->data;
492         LOG_DEBUG("Wait channel finish");
493
494         while(!(ch->thread.finish) && !thread->finish){
495                 sys->sleep(1000);
496         }
497
498         if (ch->thread.finish){
499                 LOG_DEBUG("channel finish");
500                 ch->endThread(true);
501         } else {
502                 LOG_DEBUG("channel restart");
503         }
504
505         delete thread;
506         return 0;
507 }
508
509 // -----------------------------------
510 bool Channel::acceptGIV(ClientSocket *givSock)
511 {
512         if (!pushSock)
513         {
514                 pushSock = givSock;
515                 return true;
516         }else
517                 return false;
518 }
519 // -----------------------------------
520 void Channel::connectFetch()
521 {
522         sock = sys->createSocket();
523         
524         if (!sock)
525                 throw StreamException("Can`t create socket");
526
527         if (sourceHost.tracker || sourceHost.yp)
528         {
529                 sock->setReadTimeout(30000);
530                 sock->setWriteTimeout(30000);
531                 LOG_CHANNEL("Channel using longer timeouts");
532         } else {
533                 sock->setReadTimeout(5000);
534                 sock->setWriteTimeout(5000);
535         }
536
537         sock->open(sourceHost.host);
538                 
539         sock->connect();
540 }
541
542 // -----------------------------------
543 int Channel::handshakeFetch()
544 {
545         char idStr[64];
546         info.id.toStr(idStr);
547
548         char sidStr[64];
549         servMgr->sessionID.toStr(sidStr);
550
551         sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
552         sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
553         sock->writeLineF("%s %d",PCX_HS_PCP,1);
554         sock->writeLineF("%s %d",PCX_HS_PORT,servMgr->serverHost.port);
555
556         sock->writeLine("");
557
558         HTTP http(*sock);
559
560         int r = http.readResponse();
561
562         LOG_CHANNEL("Got response: %d",r);
563
564         while (http.nextHeader())
565         {
566                 char *arg = http.getArgStr();
567                 if (!arg) 
568                         continue;
569
570                 if (http.isHeader(PCX_HS_POS))
571                         streamPos = atoi(arg);
572                 else
573                         Servent::readICYHeader(http, info, NULL);
574
575                 LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
576         }
577
578         if ((r != 200) && (r != 503))
579                 return r;
580
581         if (!servMgr->keepDownstreams) {
582                 if (rawData.getLatestPos() > streamPos)
583                         rawData.init();
584         }
585
586         AtomStream atom(*sock);
587
588         String agent;
589
590         Host rhost = sock->host;
591
592         if (info.srcProtocol == ChanInfo::SP_PCP)
593         {
594                 // don`t need PCP_CONNECT here
595                 Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
596         }
597
598         if (r == 503) return 503;
599         return 0;
600
601 }
602
603 // -----------------------------------
604 void PeercastSource::stream(Channel *ch)
605 {
606         int numYPTries=0;
607         int numYPTries2=0;
608         bool next_yp = false;
609         bool tracker_check = (ch->trackerHit.host.ip != 0);
610         int connFailCnt = 0;
611
612         ch->lastStopTime = 0;
613         ch->bumped = false;
614
615         while (ch->thread.active)
616         {
617                 ch->skipCount = 0; //JP-EX
618                 ch->lastSkipTime = 0;
619                 
620                 ChanHitList *chl = NULL;
621
622                 ch->sourceHost.init();
623
624                 if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
625                         ch->lastIdleTime = sys->getTime();
626                         ch->setStatus(Channel::S_IDLE);
627                         ch->skipCount = 0;
628                         ch->lastSkipTime = 0;
629                         break;
630                 }
631
632                 if (!servMgr->keepDownstreams && !ch->bumped) {
633                         ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
634                 }
635
636                 ch->setStatus(Channel::S_SEARCHING);
637                 LOG_CHANNEL("Channel searching for hit..");
638                 do 
639                 {
640         
641                         if (ch->pushSock)
642                         {
643                                 ch->sock = ch->pushSock;
644                                 ch->pushSock = NULL;
645                                 ch->sourceHost.host = ch->sock->host;
646                                 break;
647                         }
648
649                         chanMgr->hitlistlock.on();
650
651                         chl = chanMgr->findHitList(ch->info);
652                         if (chl)
653                         {
654                                 ChanHitSearch chs;
655
656                                 // find local hit 
657                                 if (!ch->sourceHost.host.ip){
658                                         chs.init();
659                                         chs.matchHost = servMgr->serverHost;
660                                         chs.waitDelay = MIN_RELAY_RETRY;
661                                         chs.excludeID = servMgr->sessionID;
662                                         if (chl->pickSourceHits(chs)){
663                                                 ch->sourceHost = chs.best[0];
664                                                 LOG_DEBUG("use local hit");
665                                         }
666                                 }
667                                 
668                                 // else find global hit
669                                 if (!ch->sourceHost.host.ip)
670                                 {
671                                         chs.init();
672                                         chs.waitDelay = MIN_RELAY_RETRY;
673                                         chs.excludeID = servMgr->sessionID;
674                                         if (chl->pickSourceHits(chs)){
675                                                 ch->sourceHost = chs.best[0];
676                                                 LOG_DEBUG("use global hit");
677                                         }
678                                 }
679
680
681                                 // else find local tracker
682                                 if (!ch->sourceHost.host.ip)
683                                 {
684                                         chs.init();
685                                         chs.matchHost = servMgr->serverHost;
686                                         chs.waitDelay = MIN_TRACKER_RETRY;
687                                         chs.excludeID = servMgr->sessionID;
688                                         chs.trackersOnly = true;
689                                         if (chl->pickSourceHits(chs)){
690                                                 ch->sourceHost = chs.best[0];
691                                                 LOG_DEBUG("use local tracker");
692                                         }
693                                 }
694
695                                 // else find global tracker
696                                 if (!ch->sourceHost.host.ip)
697                                 {
698                                         chs.init();
699                                         chs.waitDelay = MIN_TRACKER_RETRY;
700                                         chs.excludeID = servMgr->sessionID;
701                                         chs.trackersOnly = true;
702                                         if (chl->pickSourceHits(chs)){
703                                                 ch->sourceHost = chs.best[0];
704                                                 tracker_check = true;
705                                                 ch->trackerHit = chs.best[0];
706                                                 LOG_DEBUG("use global tracker");
707                                         }
708                                 }
709
710                                 // find tracker
711                                 unsigned int ctime = sys->getTime();
712                                 if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
713                                         if (ch->trackerHit.lastContact + 30 < ctime){
714                                                 ch->sourceHost = ch->trackerHit;
715                                                 ch->trackerHit.lastContact = ctime;
716                                                 LOG_DEBUG("use saved tracker");
717                                         }
718                                 }
719                         }
720
721                         chanMgr->hitlistlock.off();
722
723                         if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
724                                 ch->lastStopTime = 0;
725                                 LOG_DEBUG("------------ disconnect all downstreams");
726                                 ChanPacket pack;
727                                 MemoryStream mem(pack.data,sizeof(pack.data));
728                                 AtomStream atom(mem);
729                                 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
730                                 pack.len = mem.pos;
731                                 pack.type = ChanPacket::T_PCP;
732                                 GnuID noID;
733                                 noID.clear();
734                                 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
735
736                                 chanMgr->hitlistlock.on();
737                                 ChanHitList *hl = chanMgr->findHitList(ch->info);
738                                 if (hl){
739                                         hl->clearHits(false);
740                                 }
741                                 chanMgr->hitlistlock.off();
742                         }
743
744                         // no trackers found so contact YP
745                         if (!tracker_check && !ch->sourceHost.host.ip)
746                         {
747                                 next_yp = false;
748                                 if (servMgr->rootHost.isEmpty())
749                                         goto yp2;
750
751                                 if (numYPTries >= 3)
752                                         goto yp2;
753
754                                 if  ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
755                                         goto yp2;
756
757                                 unsigned int ctime=sys->getTime();
758                                 if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
759                                 {
760                                         ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
761                                         ch->sourceHost.yp = true;
762                                         chanMgr->lastYPConnect=ctime;
763                                         numYPTries++;
764                                 }
765                                 if (numYPTries < 3)
766                                         next_yp = true;
767                         }
768
769 yp2:
770                         // no trackers found so contact YP2
771                         if (!tracker_check && !ch->sourceHost.host.ip)
772                         {
773 //                              next_yp = false;
774                                 if (servMgr->rootHost2.isEmpty())
775                                         goto yp0;
776
777                                 if (numYPTries2 >= 3)
778                                         goto yp0;
779
780                                 unsigned int ctime=sys->getTime();
781                                 if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
782                                 {
783                                         ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
784                                         ch->sourceHost.yp = true;
785                                         chanMgr->lastYPConnect2=ctime;
786                                         numYPTries2++;
787                                 }
788                                 if (numYPTries2 < 3)
789                                         next_yp = true;
790                         }
791 yp0:
792                         if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
793
794                         sys->sleepIdle();
795
796                 }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
797
798                 if (!ch->sourceHost.host.ip)
799                 {
800                         LOG_ERROR("Channel giving up");
801                         ch->setStatus(Channel::S_ERROR);                        
802                         break;
803                 }
804
805                 if (ch->sourceHost.yp)
806                 {
807                         LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
808                 }else
809                 {
810                         LOG_CHANNEL("Channel found hit");
811                         numYPTries=0;
812                         numYPTries2=0;
813                 }
814
815                 if (ch->sourceHost.host.ip)
816                 {
817                         bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
818
819
820                         //if (ch->sourceHost.tracker)
821                         //      peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
822                         
823                         char ipstr[64];
824                         ch->sourceHost.host.toStr(ipstr);
825
826                         char *type = "";
827                         if (ch->sourceHost.tracker)
828                                 type = "(tracker)";
829                         else if (ch->sourceHost.yp)
830                                 type = "(YP)";
831
832                         int error=-1;
833                         int got503 = 0;
834                         try
835                         {
836                                 ch->setStatus(Channel::S_CONNECTING);
837                                 ch->sourceHost.lastContact = sys->getTime();
838
839                                 if (!ch->sock)
840                                 {
841                                         LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
842                                         ch->connectFetch();
843                                 }
844
845                                 error = ch->handshakeFetch();
846                                 if (error == 503) {
847                                         got503 = 1;
848                                         error = 0;
849                                 }
850                                 if (error)
851                                         throw StreamException("Handshake error");
852                                 if (ch->sourceHost.tracker) connFailCnt = 0;
853
854                                 if (servMgr->autoMaxRelaySetting) //JP-EX
855                                 {       
856                                         double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
857                                         if ((unsigned int)setMaxRelays == 0)
858                                                 servMgr->maxRelays = 1;
859                                         else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
860                                                 servMgr->maxRelays = servMgr->autoMaxRelaySetting;
861                                         else
862                                                 servMgr->maxRelays = (unsigned int)setMaxRelays;
863                                 }
864
865                                 ch->sourceStream = ch->createSource();
866
867                                 error = ch->readStream(*ch->sock,ch->sourceStream);
868                                 if (error)
869                                         throw StreamException("Stream error");
870
871                                 error = 0;              // no errors, closing normally.
872 //                              ch->setStatus(Channel::S_CLOSING);                      
873                                 ch->setStatus(Channel::S_IDLE);
874
875                                 LOG_CHANNEL("Channel closed normally");
876                         }catch(StreamException &e)
877                         {
878                                 ch->setStatus(Channel::S_ERROR);                        
879                                 LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
880                                 if (!servMgr->allowConnectPCST) //JP-EX
881                                 {
882                                         if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
883                                                 ch->thread.active = false;
884                                 }
885                                 //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
886                                 if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
887                                         chanMgr->deadHit(ch->sourceHost);
888                                 if (ch->sourceHost.tracker && error == -1) {
889                                         LOG_ERROR("can't connect to tracker");
890                                         connFailCnt++;
891                                 }
892                         }
893
894                         unsigned int ctime = sys->getTime();
895                         if (ch->rawData.lastWriteTime) {
896                                 ch->lastStopTime = ch->rawData.lastWriteTime;
897                                 if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
898                                         ch->lastStopTime = ctime;
899                         }
900
901                         if (tracker_check && ch->sourceHost.tracker)
902                                 ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
903
904                         // broadcast source host
905                         if (!error && ch->sourceHost.host.ip) { // if closed normally
906                                 ChanPacket pack;
907                                 MemoryStream mem(pack.data,sizeof(pack.data));
908                                 AtomStream atom(mem);
909                                 ch->sourceHost.writeAtoms(atom, ch->info.id);
910                                 pack.len = mem.pos;
911                                 pack.type = ChanPacket::T_PCP;
912                                 GnuID noID;
913                                 noID.clear();
914                                 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
915                                 LOG_DEBUG("stream: broadcast sourceHost");
916                         }
917
918                         // broadcast quit to any connected downstream servents
919                         if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
920                                 ChanPacket pack;
921                                 MemoryStream mem(pack.data,sizeof(pack.data));
922                                 AtomStream atom(mem);
923                                 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
924                                 pack.len = mem.pos;
925                                 pack.type = ChanPacket::T_PCP;
926                                 GnuID noID;
927                                 noID.clear();
928                                 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
929                                 LOG_DEBUG("------------ broadcast quit to all downstreams");
930
931                                 chanMgr->hitlistlock.on();
932                                 ChanHitList *hl = chanMgr->findHitList(ch->info);
933                                 if (hl){
934                                         hl->clearHits(false);
935                                 }
936                                 chanMgr->hitlistlock.off();
937                         }
938
939
940                         if (ch->sourceStream)
941                         {
942                                 try
943                                 {
944                                         if (!error)
945                                         {
946                                                 ch->sourceStream->updateStatus(ch);
947                                                 ch->sourceStream->flush(*ch->sock);
948                                         }
949                                 }catch(StreamException &)
950                                 {}
951                                 ChannelStream *cs = ch->sourceStream;
952                                 ch->sourceStream = NULL;
953                                 cs->kill();
954                                 delete cs;
955                         }
956
957                         if (ch->sock)
958                         {
959                                 ch->sock->close();
960                                 delete ch->sock;
961                                 ch->sock = NULL;
962                         }
963
964                         if (error == 404)
965                         {
966                                 LOG_ERROR("Channel not found");
967                                 //if (!next_yp){
968                                 if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
969                                         chanMgr->hitlistlock.on();
970                                         ChanHitList *hl = chanMgr->findHitList(ch->info);
971                                         if (hl){
972                                                 hl->clearHits(true);
973                                         }
974                                         chanMgr->hitlistlock.off();
975
976                                         if(!isIndexTxt(&ch->info))      // for PCRaw (popup)
977                                                 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
978                                         return;
979                                 }
980                         }
981
982
983                 }
984
985                 ch->lastIdleTime = sys->getTime();
986                 ch->setStatus(Channel::S_IDLE);
987                 ch->skipCount = 0; //JP-EX
988                 ch->lastSkipTime = 0;
989                 while ((ch->checkIdle()) && (ch->thread.active))
990                 {
991                         sys->sleepIdle();
992                 }
993
994                 sys->sleepIdle();
995         }
996
997 }
998 // -----------------------------------
999 void    Channel::startICY(ClientSocket *cs, SRC_TYPE st)
1000 {
1001         srcType = st;
1002         type = T_BROADCAST;
1003         cs->setReadTimeout(0);  // stay connected even when theres no data coming through
1004         sock = cs;
1005         info.srcProtocol = ChanInfo::SP_HTTP;
1006
1007         streamIndex = ++chanMgr->icyIndex;
1008
1009         sourceData = new ICYSource();
1010         startStream();
1011 }
1012
1013 // -----------------------------------
1014 static char *nextMetaPart(char *str,char delim)
1015 {
1016         while (*str)
1017         {
1018                 if (*str == delim)
1019                 {
1020                         *str++ = 0;
1021                         return str;
1022                 }
1023                 str++;
1024         }
1025         return NULL;
1026 }
1027 // -----------------------------------
1028 static void copyStr(char *to,char *from,int max)
1029 {
1030         char c;
1031         while ((c=*from++) && (--max))
1032                 if (c != '\'')
1033                         *to++ = c;
1034
1035         *to = 0;
1036 }
1037
1038 // -----------------------------------
1039 void Channel::processMp3Metadata(char *str)
1040 {
1041         ChanInfo newInfo = info;
1042         
1043         char *cmd=str;
1044         while (cmd)
1045         {
1046                 char *arg = nextMetaPart(cmd,'=');
1047                 if (!arg)
1048                         break;
1049
1050                 char *next = nextMetaPart(arg,';');
1051
1052                 if (strcmp(cmd,"StreamTitle")==0)
1053                 {
1054                         newInfo.track.title.setUnquote(arg,String::T_ASCII);
1055                         newInfo.track.title.convertTo(String::T_UNICODE);
1056
1057                 }else if (strcmp(cmd,"StreamUrl")==0)
1058                 {
1059                         newInfo.track.contact.setUnquote(arg,String::T_ASCII);
1060                         newInfo.track.contact.convertTo(String::T_UNICODE);
1061                 }
1062
1063
1064                 cmd = next;
1065         }
1066
1067         updateInfo(newInfo);
1068 }
1069
1070 // -----------------------------------
1071 XML::Node *ChanHit::createXML()
1072 {
1073         // IP
1074         char ipStr[64];
1075         host.toStr(ipStr);
1076         
1077         return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"",
1078                 ipStr,
1079                 numHops,
1080                 numListeners,
1081                 numRelays,
1082                 upTime,
1083                 firewalled?1:0,
1084                 relay?1:0,
1085                 direct?1:0,
1086                 cin?1:0,
1087                 stable?1:0,
1088                 version,
1089                 sys->getTime()-time,
1090                 tracker
1091                 );
1092
1093 }
1094
1095 // -----------------------------------
1096 XML::Node *ChanHitList::createXML(bool addHits)
1097 {
1098         XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
1099                 numHits(),
1100                 numListeners(),
1101                 numRelays(),
1102                 numFirewalled(),
1103                 closestHit(),
1104                 furthestHit(),
1105                 sys->getTime()-newestHit()
1106                 );              
1107
1108         if (addHits)
1109         {
1110                 ChanHit *h = hit;
1111                 while (h)
1112                 {
1113                         if (h->host.ip)
1114                                 hn->add(h->createXML());
1115                         h = h->next;
1116                 }
1117         }
1118
1119         return hn;
1120 }
1121
1122 // -----------------------------------
1123 XML::Node *Channel::createRelayXML(bool showStat)
1124 {
1125         const char *ststr;
1126         ststr = getStatusStr();
1127         if (!showStat)
1128                 if ((status == S_RECEIVING) || (status == S_BROADCASTING))
1129                         ststr = "OK";
1130
1131         ChanHitList *chl = chanMgr->findHitList(info);
1132
1133         return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
1134                 localListeners(),
1135                 localRelays(),
1136                 (chl!=NULL)?chl->numHits():0,
1137                 ststr
1138                 );      
1139 }
1140
1141 // -----------------------------------
1142 void ChanMeta::fromXML(XML &xml)
1143 {
1144         MemoryStream tout(data,MAX_DATALEN);
1145         xml.write(tout);
1146
1147         len = tout.pos;
1148 }
1149 // -----------------------------------
1150 void ChanMeta::fromMem(void *p, int l)
1151 {
1152         len = l;
1153         memcpy(data,p,len);
1154 }
1155 // -----------------------------------
1156 void ChanMeta::addMem(void *p, int l)
1157 {
1158         if ((len+l) <= MAX_DATALEN)
1159         {
1160                 memcpy(data+len,p,l);
1161                 len += l;
1162         }
1163 }
1164 // -----------------------------------
1165 void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
1166 {
1167         unsigned int ctime = sys->getTime();
1168
1169         if (((ctime-lastTrackerUpdate) > 30) || (force))
1170         {
1171                 ChanPacket pack;
1172
1173                 MemoryStream mem(pack.data,sizeof(pack));
1174
1175                 AtomStream atom(mem);
1176                         
1177                 ChanHit hit;
1178
1179                 ChanHitList *chl = chanMgr->findHitListByID(info.id);
1180                 if (!chl)
1181                         throw StreamException("Broadcast channel has no hitlist");
1182
1183                 int numListeners = stealth ? -1 : totalListeners(); //JP-MOD \83\8a\83X\83i\81[\90\94\89B\95Á\8b@\94\
1184                 int numRelays = stealth ? -1 : totalRelays(); //JP-MOD \83\8a\83\8c\81[\90\94\89B\95Á\8b@\94\
1185
1186                 unsigned int oldp = rawData.getOldestPos();
1187                 unsigned int newp = rawData.getLatestPos();
1188
1189                 hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
1190                 hit.tracker = true;
1191
1192                 if (version_ex == 0)
1193                 {
1194                         atom.writeParent(PCP_BCST,8);
1195                 } else
1196                 {
1197                         atom.writeParent(PCP_BCST,10);
1198                 }
1199                 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
1200                 atom.writeChar(PCP_BCST_HOPS,0);
1201                 atom.writeChar(PCP_BCST_TTL,11);
1202                 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1203                 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1204                 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1205
1206                 if (version_ex)
1207                 {
1208                         atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1209                         atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1210                 }
1211                 atom.writeParent(PCP_CHAN,4);
1212                 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1213                 atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
1214                 info.writeInfoAtoms(atom);
1215                 info.writeTrackAtoms(atom);
1216                 hit.writeAtoms(atom,info.id);
1217
1218
1219                 pack.len = mem.pos;
1220                 pack.type = ChanPacket::T_PCP;
1221
1222                 GnuID noID;
1223                 noID.clear();
1224                 int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
1225
1226                 if (cnt)
1227                 {
1228                         LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
1229                         lastTrackerUpdate = ctime;
1230                 }
1231         }
1232 }
1233
1234 // -----------------------------------
1235 bool    Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
1236 {
1237         if ( isActive() 
1238                 && (!cid.isSet() || info.id.isSame(cid)) 
1239                 && (!sid.isSet() || !remoteID.isSame(sid))
1240                 && sourceStream 
1241            )
1242                 return sourceStream->sendPacket(pack,did);
1243
1244         return false;
1245 }
1246
1247 // -----------------------------------
1248 void Channel::updateInfo(ChanInfo &newInfo)
1249 {
1250         if (info.update(newInfo))
1251         {
1252                 if (isBroadcasting())
1253                 {
1254                         unsigned int ctime = sys->getTime();
1255                         if ((ctime-lastMetaUpdate) > 30)
1256                         {
1257                                 lastMetaUpdate = ctime;
1258
1259                                 ChanPacket pack;
1260
1261                                 MemoryStream mem(pack.data,sizeof(pack));
1262
1263                                 AtomStream atom(mem);
1264
1265                                 if (version_ex == 0)
1266                                 {
1267                                         atom.writeParent(PCP_BCST,8);
1268                                 } else
1269                                 {
1270                                         atom.writeParent(PCP_BCST,10);
1271                                 }
1272                                 atom.writeChar(PCP_BCST_HOPS,0);
1273                                 atom.writeChar(PCP_BCST_TTL,7);
1274                                 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
1275                                 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1276                                 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1277                                 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1278                                 if (version_ex)
1279                                 {
1280                                         atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1281                                         atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1282                                 }
1283                                 atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
1284                                 atom.writeParent(PCP_CHAN,3);
1285                                 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1286                                 info.writeInfoAtoms(atom);
1287                                 info.writeTrackAtoms(atom);
1288
1289                                 pack.len = mem.pos;
1290                                 pack.type = ChanPacket::T_PCP;
1291                                 GnuID noID;
1292                                 noID.clear();
1293                                 servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
1294
1295                                 broadcastTrackerUpdate(noID);
1296                         }
1297                 }
1298
1299                 ChanHitList *chl = chanMgr->findHitList(info);
1300                 if (chl)
1301                         chl->info = info;
1302
1303                 peercastApp->channelUpdate(&info);
1304
1305         }
1306
1307 }
1308 // -----------------------------------
1309 ChannelStream *Channel::createSource()
1310 {
1311 //      if (servMgr->relayBroadcast)
1312 //              chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
1313
1314
1315         ChannelStream *source=NULL;
1316
1317         if (info.srcProtocol == ChanInfo::SP_PEERCAST)
1318         {
1319                 LOG_CHANNEL("Channel is Peercast");
1320                 if (servMgr->allowConnectPCST) //JP-EX
1321                         source = new PeercastStream();
1322                 else
1323                         throw StreamException("Channel is not allowed");
1324         }
1325         else if (info.srcProtocol == ChanInfo::SP_PCP)
1326         {
1327                 LOG_CHANNEL("Channel is PCP");
1328                 PCPStream *pcp = new PCPStream(remoteID);
1329                 source = pcp;
1330         }
1331         else if (info.srcProtocol == ChanInfo::SP_MMS)
1332         {
1333                 LOG_CHANNEL("Channel is MMS");
1334                 source = new MMSStream();
1335         }else
1336         {
1337                 switch(info.contentType)
1338                 {
1339                         case ChanInfo::T_MP3:
1340                                 LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
1341                                 source = new MP3Stream();
1342                                 break;
1343                         case ChanInfo::T_NSV:
1344                                 LOG_CHANNEL("Channel is NSV");
1345                                 source = new NSVStream();
1346                                 break;
1347                         case ChanInfo::T_WMA:
1348                         case ChanInfo::T_WMV:
1349                                 throw StreamException("Channel is WMA/WMV - but not MMS");
1350                                 break;
1351                         case ChanInfo::T_OGG:
1352                         case ChanInfo::T_OGM:
1353                                 LOG_CHANNEL("Channel is OGG");
1354                                 source = new OGGStream();
1355                                 break;
1356                         default:
1357                                 LOG_CHANNEL("Channel is Raw");
1358                                 source = new RawStream();
1359                                 break;
1360                 }
1361         }
1362
1363         source->parent = this;
1364
1365         return source;
1366 }
1367 // ------------------------------------------
1368 void ChannelStream::updateStatus(Channel *ch)
1369 {
1370         ChanPacket pack;
1371         if (getStatus(ch,pack))
1372         {
1373                 if (!ch->isBroadcasting())
1374                 {
1375                         GnuID noID;
1376                         noID.clear();
1377                         int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
1378                         LOG_CHANNEL("Sent channel status update to %d clients",cnt);
1379                 }
1380         }
1381 }
1382
1383 // ------------------------------------------
1384 bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
1385 {
1386         unsigned int ctime = sys->getTime();
1387
1388         ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
1389
1390         if (!chl)
1391                 return false;
1392
1393 /*      int newLocalListeners = ch->localListeners();
1394         int newLocalRelays = ch->localRelays();
1395
1396         if (
1397                 (
1398                 (numListeners != newLocalListeners) 
1399                 || (numRelays != newLocalRelays) 
1400                 || (ch->isPlaying() != isPlaying) 
1401                 || (servMgr->getFirewall() != fwState)
1402                 || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1403                 )
1404                 && ((ctime-lastUpdate) > 10)
1405            )
1406         {
1407
1408                 numListeners = newLocalListeners;
1409                 numRelays = newLocalRelays;
1410                 isPlaying = ch->isPlaying();
1411                 fwState = servMgr->getFirewall();
1412                 lastUpdate = ctime;
1413
1414                 ChanHit hit;
1415
1416                 hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
1417                 hit.tracker = ch->isBroadcasting();*/
1418
1419         int newLocalListeners = ch->localListeners();
1420         int newLocalRelays = ch->localRelays();
1421
1422         if ((ch->isPlaying() == isPlaying)){
1423                 if ((ctime-lastUpdate) < 10){
1424                         return false;
1425                 }
1426
1427                 if ((ctime-lastCheckTime) < 10){
1428                         return false;
1429                 }
1430                 lastCheckTime = ctime;
1431         }
1432
1433         unsigned int oldp = ch->rawData.getOldestPos();
1434         unsigned int newp = ch->rawData.getLatestPos();
1435
1436         ChanHit hit;
1437
1438 //      LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
1439
1440         hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
1441         { //JP-MOD
1442                 if(!(ch->info.ppFlags & ServMgr::bcstClap))
1443                         ch->bClap = false;
1444                 hit.initLocal_pp(ch->stealth, ch->bClap ? 1 : 0);
1445         }
1446         hit.tracker = ch->isBroadcasting();
1447
1448         if      (       (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1449                 ||      (newLocalListeners != numListeners)
1450                 ||      (newLocalRelays != numRelays)
1451                 ||      (ch->isPlaying() != isPlaying)
1452                 ||      (servMgr->getFirewall() != fwState)
1453                 ||      (ch->chDisp.relay != hit.relay)
1454                 ||      (ch->chDisp.relayfull != hit.relayfull)
1455                 ||      (ch->chDisp.chfull != hit.chfull)
1456                 ||      (ch->chDisp.ratefull != hit.ratefull)
1457                 ||      (ch->bClap && ((ctime-lastClapped) > 60)) //JP-MOD      
1458         ){
1459                 numListeners = newLocalListeners;
1460                 numRelays = newLocalRelays;
1461                 isPlaying = ch->isPlaying();
1462                 fwState = servMgr->getFirewall();
1463                 lastUpdate = ctime;
1464
1465                 if(ch->bClap){ //JP-MOD
1466                         lastClapped = ctime;
1467                         ch->bClap = false;
1468                 }
1469         
1470                 ch->chDisp = hit;
1471
1472                 if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
1473                         ch->stayConnected = true;
1474
1475                 if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
1476                         ch->stayConnected = false;
1477
1478                 MemoryStream pmem(pack.data,sizeof(pack.data));
1479                 AtomStream atom(pmem);
1480
1481                 GnuID noID;
1482                 noID.clear();
1483
1484                 if (version_ex == 0)
1485                 {
1486                         atom.writeParent(PCP_BCST,8);
1487                 } else
1488                 {
1489                         atom.writeParent(PCP_BCST,10);
1490                 }
1491                 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
1492                 atom.writeChar(PCP_BCST_HOPS,0);
1493                 atom.writeChar(PCP_BCST_TTL,11);
1494                 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1495                 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1496                 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1497                 if (version_ex)
1498                 {
1499                         atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1500                         atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1501                 }
1502                 atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
1503                 hit.writeAtoms(atom,noID);
1504
1505                 pack.len = pmem.pos;
1506                 pack.type = ChanPacket::T_PCP;
1507                 return true;
1508         }else
1509                 return false;
1510 }
1511 // -----------------------------------
1512 bool    Channel::checkBump()
1513 {
1514         unsigned int maxIdleTime = 30;
1515         if (isIndexTxt(this)) maxIdleTime = 60;
1516
1517         if (!isBroadcasting() && (!sourceHost.tracker))
1518             if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > maxIdleTime))
1519                 {
1520                         LOG_ERROR("Channel Auto bumped");
1521                         bump = true;
1522                 }
1523         
1524         if (bump)
1525         {
1526                 bump = false;
1527                 return true;
1528         }else
1529                 return false;
1530 }
1531
1532 // -----------------------------------
1533 int Channel::readStream(Stream &in,ChannelStream *source)
1534 {
1535         //sys->sleep(300);
1536
1537         int error = 0;
1538
1539         info.numSkips = 0;
1540
1541         source->readHeader(in,this);
1542
1543         peercastApp->channelStart(&info);
1544
1545         rawData.lastWriteTime = 0;
1546
1547         bool wasBroadcasting=false;
1548
1549         unsigned int receiveStartTime = 0;
1550
1551         unsigned int ptime = 0;
1552         unsigned int upsize = 0;
1553
1554         try
1555         {
1556                 while (thread.active && !peercastInst->isQuitting)
1557                 {                       
1558                         if (checkIdle())
1559                         {
1560                                 LOG_DEBUG("Channel idle");
1561                                 break;
1562                         }
1563
1564                         if (checkBump())
1565                         {
1566                                 LOG_DEBUG("Channel bumped");
1567                                 error = -1;
1568                                 bumped = true;
1569                                 break;
1570                         }
1571
1572                         if (in.eof())
1573                         {
1574                                 LOG_DEBUG("Channel eof");
1575                                 break;
1576                         }
1577
1578                         if (in.readReady())
1579                         {
1580                                 error = source->readPacket(in,this);
1581
1582                                 if (error)
1583                                         break;
1584
1585                                 //if (rawData.writePos > 0)
1586                                 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1587                                 {
1588                                         if (isBroadcasting())
1589                                         {                                       
1590                                                 if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
1591                                                 {
1592                                                         GnuID noID;
1593                                                         noID.clear();
1594                                                         broadcastTrackerUpdate(noID);
1595                                                 }
1596                                                 wasBroadcasting = true;
1597
1598                                         }else
1599                                         {
1600 /*                                              if (status != Channel::S_RECEIVING){
1601                                                         receiveStartTime = sys->getTime();
1602                                                 } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
1603                                                         chanMgr->hitlistlock.on();
1604                                                         ChanHitList *hl = chanMgr->findHitList(info);
1605                                                         if (hl){
1606                                                                 hl->clearHits(true);
1607                                                         }
1608                                                         chanMgr->hitlistlock.off();
1609                                                         receiveStartTime = 0;
1610                                                 }*/
1611                                                 setStatus(Channel::S_RECEIVING);
1612                                                 bumped = false;
1613                                         }
1614                                         source->updateStatus(this);
1615                                 }
1616                         }
1617
1618                         unsigned int t = sys->getTime();
1619                         if (t != ptime) {
1620                                 ptime = t;
1621                                 upsize = Servent::MAX_OUTWARD_SIZE;
1622                         }
1623
1624                         unsigned int len = source->flushUb(in, upsize);
1625                         upsize -= len;
1626
1627                         sys->sleepIdle();
1628                 }
1629         }catch(StreamException &e)
1630         {
1631                 LOG_ERROR("readStream: %s",e.msg);
1632                 error = -1;
1633         }
1634
1635         if (!servMgr->keepDownstreams) {
1636                 if (status == Channel::S_RECEIVING){
1637                         chanMgr->hitlistlock.on();
1638                         ChanHitList *hl = chanMgr->findHitList(info);
1639                         if (hl){
1640                                 hl->clearHits(false);
1641                         }
1642                         chanMgr->hitlistlock.off();
1643                 }
1644         }
1645
1646 //      setStatus(S_CLOSING);
1647         setStatus(S_IDLE);
1648
1649         if (wasBroadcasting)
1650         {
1651                 GnuID noID;
1652                 noID.clear();
1653                 broadcastTrackerUpdate(noID,true);
1654         }
1655
1656         peercastApp->channelStop(&info);
1657
1658         source->readEnd(in,this);
1659
1660         return error;
1661 }
1662
1663 // -----------------------------------
1664 void PeercastStream::readHeader(Stream &in,Channel *ch)
1665 {
1666         if (in.readTag() != 'PCST')
1667                 throw StreamException("Not PeerCast stream");
1668
1669 }
1670 // -----------------------------------
1671 void PeercastStream::readEnd(Stream &,Channel *)
1672 {
1673
1674 }
1675 // -----------------------------------
1676 int PeercastStream::readPacket(Stream &in,Channel *ch)
1677 {
1678         ChanPacket pack;
1679
1680         {
1681
1682                 pack.readPeercast(in);
1683
1684                 MemoryStream mem(pack.data,pack.len);
1685
1686                 switch(pack.type)
1687                 {
1688                         case ChanPacket::T_HEAD:
1689                                 // update sync pos
1690                                 ch->headPack = pack;
1691                                 pack.pos = ch->streamPos;
1692                                 ch->newPacket(pack);
1693                                 ch->streamPos+=pack.len;
1694                                 break;
1695                         case ChanPacket::T_DATA:
1696                                 pack.pos = ch->streamPos;
1697                                 ch->newPacket(pack);
1698                                 ch->streamPos+=pack.len;
1699                                 break;
1700                         case ChanPacket::T_META:
1701                                 ch->insertMeta.fromMem(pack.data,pack.len);
1702                                 {
1703                                         if (pack.len)
1704                                         {
1705                                                 XML xml;
1706                                                 xml.read(mem);
1707                                                 XML::Node *n = xml.findNode("channel");                                 
1708                                                 if (n)
1709                                                 {
1710                                                         ChanInfo newInfo = ch->info;
1711                                                         newInfo.updateFromXML(n);
1712                                                         ChanHitList *chl = chanMgr->findHitList(ch->info);
1713                                                         if (chl)
1714                                                                 newInfo.updateFromXML(n);
1715                                                         ch->updateInfo(newInfo);
1716                                                 }
1717                                         }
1718                                 }
1719                                 break;
1720 #if 0
1721                         case ChanPacket::T_SYNC:
1722                                 {
1723                                         unsigned int s = mem.readLong();
1724                                         if ((s-ch->syncPos) != 1)
1725                                         {
1726                                                 LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
1727                                                 if (ch->syncPos)
1728                                                 {
1729                                                         ch->info.numSkips++;
1730                                                         if (ch->info.numSkips>50)
1731                                                                 throw StreamException("Bumped - Too many skips");
1732                                                 }
1733                                         }
1734
1735                                         ch->syncPos = s;
1736                                 }
1737                                 break;
1738 #endif
1739
1740                 }
1741
1742         }
1743         return 0;
1744 }
1745
1746 // -----------------------------------
1747 void ChannelStream::readRaw(Stream &in, Channel *ch)
1748 {
1749         ChanPacket pack;
1750
1751         const int readLen = 8192;
1752
1753         pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
1754         in.read(pack.data,pack.len);
1755         ch->newPacket(pack);
1756         ch->checkReadDelay(pack.len);
1757
1758         ch->streamPos+=pack.len;
1759
1760 }
1761 // ------------------------------------------
1762 void RawStream::readHeader(Stream &,Channel *)
1763 {
1764 }
1765
1766 // ------------------------------------------
1767 int RawStream::readPacket(Stream &in,Channel *ch)
1768 {
1769         readRaw(in,ch);
1770         return 0;
1771 }
1772
1773 // ------------------------------------------
1774 void RawStream::readEnd(Stream &,Channel *)
1775 {
1776 }
1777
1778
1779
1780 // -----------------------------------
1781 void ChanPacket::init(ChanPacketv &p)
1782 {
1783         type = p.type;
1784         len = p.len;
1785         if (len > MAX_DATALEN)
1786                 throw StreamException("Packet data too large");
1787         pos = p.pos;
1788         sync = p.sync;
1789         skip = p.skip;
1790         priority = p.priority;
1791         memcpy(data, p.data, len);
1792 }
1793 // -----------------------------------
1794 void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
1795 {
1796         type = t;
1797         if (l > MAX_DATALEN)
1798                 throw StreamException("Packet data too large");
1799         len = l;
1800         memcpy(data,p,len);
1801         pos = _pos;
1802         skip = false;
1803         priority = 0;
1804 }
1805 // -----------------------------------
1806 void ChanPacket::writeRaw(Stream &out)
1807 {
1808         out.write(data,len);
1809 }
1810 // -----------------------------------
1811 void ChanPacket::writePeercast(Stream &out)
1812 {
1813         unsigned int tp = 0;
1814         switch (type)
1815         {
1816                 case T_HEAD: tp = 'HEAD'; break;
1817                 case T_META: tp = 'META'; break;
1818                 case T_DATA: tp = 'DATA'; break;
1819         }
1820
1821         if (type != T_UNKNOWN)
1822         {
1823                 out.writeTag(tp);
1824                 out.writeShort(len);
1825                 out.writeShort(0);
1826                 out.write(data,len);
1827         }
1828 }
1829 // -----------------------------------
1830 void ChanPacket::readPeercast(Stream &in)
1831 {
1832         unsigned int tp = in.readTag();
1833
1834         switch (tp)
1835         {
1836                 case 'HEAD':    type = T_HEAD; break;
1837                 case 'DATA':    type = T_DATA; break;
1838                 case 'META':    type = T_META; break;
1839                 default:                type = T_UNKNOWN;
1840         }
1841         len = in.readShort();
1842         in.readShort();
1843         if (len > MAX_DATALEN)
1844                 throw StreamException("Bad ChanPacket");
1845         in.read(data,len);
1846 }
1847 // -----------------------------------
1848 int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
1849 {
1850         lock.on();
1851         buf.lock.on();
1852
1853         firstPos = 0;
1854         lastPos = 0;
1855         safePos = 0;
1856         readPos = 0;
1857
1858         for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
1859         {
1860                 //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
1861                 ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
1862                 if (src->type & accept)
1863                 {
1864                         if (src->pos >= reqPos)
1865                         {
1866                                 lastPos = writePos;
1867                                 //packets[writePos++] = *src;
1868                                 packets[writePos++].init(*src);
1869                         }
1870                 }
1871
1872         }
1873
1874
1875         buf.lock.off();
1876         lock.off();
1877         return lastPos-firstPos;
1878 }
1879
1880 // -----------------------------------
1881 bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
1882 {
1883         if (writePos == 0)
1884                 return false;
1885
1886         lock.on();
1887
1888         unsigned int bound = packets[0].len * ChanPacketBuffer::MAX_PACKETS * 2; // max packets to wait
1889         unsigned int fpos = getStreamPos(firstPos);
1890         unsigned int lpos = getStreamPos(lastPos);
1891         if (spos < fpos && (fpos < lpos || spos > lpos + bound))
1892                 spos = fpos;
1893
1894
1895         for(unsigned int i=firstPos; i<=lastPos; i++)
1896         {
1897                 //ChanPacket &p = packets[i%MAX_PACKETS];
1898                 ChanPacketv &p = packets[i%MAX_PACKETS];
1899                 if (p.pos >= spos && p.pos - spos <= bound)
1900                 {
1901                         pack.init(p);
1902                         lock.off();
1903                         return true;
1904                 }
1905         }
1906
1907         lock.off();
1908         return false;
1909 }
1910 // -----------------------------------
1911 unsigned int    ChanPacketBuffer::getLatestPos()
1912 {
1913         if (!writePos)
1914                 return 0;
1915         else
1916                 return getStreamPos(lastPos);
1917                 
1918 }
1919 // -----------------------------------
1920 unsigned int    ChanPacketBuffer::getOldestPos()
1921 {
1922         if (!writePos)
1923                 return 0;
1924         else
1925                 return getStreamPos(firstPos);
1926 }
1927
1928 // -----------------------------------
1929 unsigned int    ChanPacketBuffer::findOldestPos(unsigned int spos)
1930 {
1931         unsigned int min = getStreamPos(safePos);
1932         unsigned int max = getStreamPos(lastPos);
1933
1934         if (min > spos)
1935                 return min;
1936
1937         if (max < spos)
1938                 return max;
1939
1940         return spos;
1941 }
1942
1943 // -----------------------------------
1944 unsigned int    ChanPacketBuffer::getStreamPos(unsigned int index)
1945 {
1946         return packets[index%MAX_PACKETS].pos;
1947 }
1948 // -----------------------------------
1949 unsigned int    ChanPacketBuffer::getStreamPosEnd(unsigned int index)
1950 {
1951         return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
1952 }
1953 // -----------------------------------
1954 bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
1955 {
1956         if (pack.len)
1957         {
1958                 if (servMgr->keepDownstreams) {
1959                         unsigned int lpos = getLatestPos();
1960                         unsigned int diff = pack.pos - lpos;
1961                         if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
1962                         if (lpos && (diff == 0 || diff > 0xfff00000)) {
1963                                 LOG_DEBUG("*   latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
1964                                 lastSkipTime = sys->getTime();
1965                                 return false;
1966                         }
1967                 }
1968
1969                 if (willSkip()) // too far behind
1970                 {
1971                         lastSkipTime = sys->getTime();
1972                         return false;
1973                 }
1974
1975                 lock.on();
1976
1977                 pack.sync = writePos;
1978                 packets[writePos%MAX_PACKETS].init(pack);
1979
1980 //              LOG_DEBUG("packet.len = %d",pack.len);
1981
1982
1983                 lastPos = writePos;
1984                 writePos++;
1985
1986                 if (writePos >= MAX_PACKETS)
1987                         firstPos = writePos-MAX_PACKETS;
1988                 else
1989                         firstPos = 0;
1990
1991                 if (writePos >= NUM_SAFEPACKETS)
1992                         safePos = writePos - NUM_SAFEPACKETS;
1993                 else
1994                         safePos = 0;
1995
1996                 if (updateReadPos)
1997                         readPos = writePos;
1998
1999                 lastWriteTime = sys->getTime();
2000
2001                 lock.off();
2002                 return true;
2003         }
2004
2005         return false;
2006 }
2007 // -----------------------------------
2008 void    ChanPacketBuffer::readPacket(ChanPacket &pack)
2009 {
2010
2011         unsigned int tim = sys->getTime();
2012
2013         if (readPos < firstPos) 
2014                 throw StreamException("Read too far behind");
2015
2016         while (readPos >= writePos)
2017         {
2018                 sys->sleepIdle();
2019                 if ((sys->getTime() - tim) > 30)
2020                         throw TimeoutException();
2021         }
2022         lock.on();
2023         pack.init(packets[readPos%MAX_PACKETS]);
2024         readPos++;
2025         lock.off();
2026 }
2027
2028 // -----------------------------------
2029 void    ChanPacketBuffer::readPacketPri(ChanPacket &pack)
2030 {
2031         unsigned int tim = sys->getTime();
2032
2033         if (readPos < firstPos) 
2034                 throw StreamException("Read too far behind");
2035  
2036         while (readPos >= writePos)
2037         {
2038                 sys->sleepIdle();
2039                 if ((sys->getTime() - tim) > 30)
2040                         throw TimeoutException();
2041         }
2042         lock.on();
2043         ChanPacketv *best = &packets[readPos % MAX_PACKETS];
2044         for (unsigned int i = readPos + 1; i < writePos; i++) {
2045                 if (packets[i % MAX_PACKETS].priority > best->priority)
2046                         best = &packets[i % MAX_PACKETS];
2047         }
2048         pack.init(*best);
2049         best->init(packets[readPos % MAX_PACKETS]);
2050         readPos++;
2051         lock.off();
2052  }
2053
2054 // -----------------------------------
2055 bool    ChanPacketBuffer::willSkip()
2056 {
2057         return ((writePos-readPos) >= MAX_PACKETS);
2058 }
2059
2060 // -----------------------------------
2061 void Channel::getStreamPath(char *str)
2062 {
2063         char idStr[64];
2064
2065         getIDStr(idStr);
2066
2067         sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
2068 }
2069
2070
2071
2072 // -----------------------------------
2073 void ChanMgr::startSearch(ChanInfo &info)
2074 {
2075         searchInfo = info;
2076         clearHitLists();
2077         numFinds = 0;
2078         lastHit = 0;
2079 //      lastSearch = 0;
2080         searchActive = true;
2081 }
2082 // -----------------------------------
2083 void ChanMgr::quit()
2084 {
2085         LOG_DEBUG("ChanMgr is quitting..");
2086         closeAll();
2087 }
2088 // -----------------------------------
2089 int ChanMgr::numIdleChannels()
2090 {
2091         int cnt=0;
2092         Channel *ch = channel;
2093         while (ch)
2094         {
2095                 if (ch->isActive())
2096                         if (ch->thread.active)
2097                                 if (ch->status == Channel::S_IDLE)
2098                                         cnt++;
2099                 ch=ch->next;
2100         }
2101         return cnt;
2102 }
2103 // -----------------------------------
2104 void ChanMgr::closeOldestIdle()
2105 {
2106         unsigned int idleTime = (unsigned int)-1;
2107         Channel *ch = channel,*oldest=NULL;
2108         while (ch)
2109         {
2110                 if (ch->isActive())
2111                         if (ch->thread.active)
2112                                 if (ch->status == Channel::S_IDLE)
2113                                         if (ch->lastIdleTime < idleTime)
2114                                         {
2115                                                 oldest = ch;
2116                                                 idleTime = ch->lastIdleTime;
2117                                         }
2118                 ch=ch->next;
2119         }
2120
2121         if (oldest)
2122                 oldest->thread.active = false;
2123 }
2124
2125 // -----------------------------------
2126 void ChanMgr::closeAll()
2127 {
2128         Channel *ch = channel;
2129         while (ch)
2130         {
2131                 if (ch->thread.active)
2132                         ch->thread.shutdown();
2133                 ch=ch->next;
2134         }
2135 }
2136 // -----------------------------------
2137 Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
2138 {
2139         Channel *ch = channel;
2140         while (ch)
2141         {
2142                 if (ch->isActive())
2143                         if (ch->info.matchNameID(info))
2144                                 return ch;
2145                 ch=ch->next;
2146         }
2147         return NULL;
2148 }
2149
2150 // -----------------------------------
2151 Channel *ChanMgr::findChannelByName(const char *n)
2152 {
2153         Channel *ch = channel;
2154         while (ch)
2155         {
2156                 if (ch->isActive())
2157                         if (stricmp(ch->info.name,n)==0)
2158                                 return ch;
2159                 ch=ch->next;
2160         }
2161
2162         return NULL;
2163 }
2164 // -----------------------------------
2165 Channel *ChanMgr::findChannelByIndex(int index)
2166 {
2167         int cnt=0;
2168         Channel *ch = channel;
2169         while (ch)
2170         {
2171                 if (ch->isActive())
2172                 {
2173                         if (cnt == index)
2174                                 return ch;
2175                         cnt++;
2176                 }
2177                 ch=ch->next;
2178         }
2179         return NULL;
2180 }       
2181 // -----------------------------------
2182 Channel *ChanMgr::findChannelByMount(const char *str)
2183 {
2184         Channel *ch = channel;
2185         while (ch)
2186         {
2187                 if (ch->isActive())
2188                         if (strcmp(ch->mount,str)==0)
2189                                 return ch;
2190                 ch=ch->next;
2191         }
2192
2193         return NULL;
2194 }       
2195 // -----------------------------------
2196 Channel *ChanMgr::findChannelByID(GnuID &id)
2197 {
2198         Channel *ch = channel;
2199         while (ch)
2200         {
2201                 if (ch->isActive())
2202                         if (ch->info.id.isSame(id))
2203                                 return ch;
2204                 ch=ch->next;
2205         }
2206         return NULL;
2207 }       
2208 // -----------------------------------
2209 Channel *ChanMgr::findChannelByChannelID(int id)
2210 {
2211         int cnt=0;
2212         Channel *ch = channel;
2213         while (ch)
2214         {
2215                 if (ch->isActive()){
2216                         if (ch->channel_id == id){
2217                                 return ch;
2218                         }
2219                 }
2220                 ch = ch->next;
2221         }
2222         return NULL;
2223 }
2224 // -----------------------------------
2225 int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
2226 {
2227         int cnt=0;
2228         Channel *ch = channel;
2229         while (ch)
2230         {
2231                 if (ch->isActive())
2232                         if (ch->info.match(info))
2233                         {
2234                                 chlist[cnt++] = ch;
2235                                 if (cnt >= max)
2236                                         break;
2237                         }
2238                 ch=ch->next;
2239         }
2240         return cnt;
2241 }
2242 // -----------------------------------
2243 int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
2244 {
2245         int cnt=0;
2246         Channel *ch = channel;
2247         while (ch)
2248         {
2249                 if (ch->isActive())
2250                         if (ch->status == status)
2251                         {
2252                                 chlist[cnt++] = ch;
2253                                 if (cnt >= max)
2254                                         break;
2255                         }
2256                 ch=ch->next;
2257         }
2258         return cnt;
2259 }
2260 // -----------------------------------
2261 Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
2262 {
2263         Channel *c = chanMgr->createChannel(info,NULL);
2264         if (c)
2265         {
2266                 c->stayConnected = stayConnected;
2267                 c->startGet();
2268                 return c;
2269         }
2270         return NULL;
2271 }
2272 // -----------------------------------
2273 Channel *ChanMgr::findAndRelay(ChanInfo &info)
2274 {
2275         char idStr[64];
2276         info.id.toStr(idStr);
2277         LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
2278
2279         if(!isIndexTxt(&info))  // for PCRaw (popup)
2280                 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
2281
2282
2283         Channel *c = NULL;
2284
2285         WLockBlock wb(&(chanMgr->channellock));
2286
2287         wb.on();
2288
2289         c = findChannelByNameID(info);
2290
2291         if (!c)
2292         {
2293                 c = chanMgr->createChannel(info,NULL);
2294                 if (c)
2295                 {
2296                         c->setStatus(Channel::S_SEARCHING);                     
2297                         c->startGet();
2298                 }
2299         } else if (!(c->thread.active)){
2300                 c->thread.active = true;
2301                 c->thread.finish = false;
2302                 c->info.lastPlayStart = 0; // reconnect 
2303                 c->info.lastPlayEnd = 0;
2304                 if (c->finthread){
2305                         c->finthread->finish = true;
2306                         c->finthread = NULL;
2307                 }
2308                 if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
2309                         c->setStatus(Channel::S_SEARCHING);     
2310                         c->startGet();
2311                 }
2312         }
2313
2314         wb.off();
2315
2316         for(int i=0; i<600; i++)        // search for 1 minute.
2317         {
2318
2319
2320                 wb.on();
2321                 c = findChannelByNameID(info);
2322
2323                 if (!c)
2324                 {
2325 //                      peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
2326                         return NULL;
2327                 }
2328
2329                 
2330                 if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
2331                         break;
2332
2333                 wb.off();
2334
2335                 sys->sleep(100);
2336         }
2337
2338         return c;
2339 }
2340 // -----------------------------------
2341 ChanMgr::ChanMgr()
2342 {
2343         channel = NULL;
2344         
2345         hitlist = NULL;
2346
2347         currFindAndPlayChannel.clear();
2348
2349         broadcastMsg.clear();
2350         broadcastMsgInterval=10;
2351
2352         broadcastID.generate(PCP_BROADCAST_FLAGS);
2353
2354         deadHitAge = 600;
2355
2356         icyIndex = 0;
2357         icyMetaInterval = 8192; 
2358         maxRelaysPerChannel = 1;
2359
2360         searchInfo.init();
2361
2362         minBroadcastTTL = 1;
2363         maxBroadcastTTL = 7;
2364
2365         pushTimeout = 60;       // 1 minute
2366         pushTries = 5;          // 5 times
2367         maxPushHops = 8;        // max 8 hops away
2368         maxUptime = 0;          // 0 = none
2369
2370         prefetchTime = 10;      // n seconds
2371
2372         hostUpdateInterval = 120; // 2 minutes
2373
2374         bufferTime = 5;
2375
2376         autoQuery = 0;  
2377         lastQuery = 0;
2378
2379         lastYPConnect = 0;
2380         lastYPConnect2 = 0;
2381
2382 }
2383
2384 // -----------------------------------
2385 bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
2386 {
2387         char buf[1024];
2388         if (var == "numHitLists")
2389                 sprintf(buf,"%d",numHitLists());
2390         
2391         else if (var == "numChannels")
2392                 sprintf(buf,"%d",numChannels());
2393         else if (var == "djMessage")
2394         {
2395                 String utf8 = broadcastMsg;
2396                 utf8.convertTo(String::T_UNICODESAFE);
2397                 strcpy(buf,utf8.cstr());
2398         }
2399         else if (var == "icyMetaInterval")
2400                 sprintf(buf,"%d",icyMetaInterval);
2401         else if (var == "maxRelaysPerChannel")
2402                 sprintf(buf,"%d",maxRelaysPerChannel);
2403         else if (var == "hostUpdateInterval")
2404                 sprintf(buf,"%d",hostUpdateInterval);
2405         else if (var == "broadcastID")
2406                 broadcastID.toStr(buf);
2407         else
2408                 return false;
2409
2410
2411
2412         out.writeString(buf);
2413         return true;
2414 }
2415
2416 // -----------------------------------
2417 bool Channel::writeVariable(Stream &out, const String &var, int index)
2418 {
2419         char buf[1024];
2420
2421         buf[0]=0;
2422
2423         String utf8;
2424
2425         if (var == "name")
2426         {
2427                 utf8 = info.name;
2428                 utf8.convertTo(String::T_UNICODESAFE);
2429                 strcpy(buf,utf8.cstr());
2430
2431         }else if (var == "bitrate")
2432         {
2433                 sprintf(buf,"%d",info.bitrate);
2434
2435         }else if (var == "srcrate")
2436         {
2437                 if (sourceData)
2438                 {
2439                         unsigned int tot = sourceData->getSourceRate();
2440                         sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
2441                 }else
2442                         strcpy(buf,"0");
2443
2444         }else if (var == "genre")
2445         {
2446                 utf8 = info.genre;
2447                 utf8.convertTo(String::T_UNICODESAFE);
2448                 strcpy(buf,utf8.cstr());
2449         }else if (var == "desc")
2450         {
2451                 utf8 = info.desc;
2452                 utf8.convertTo(String::T_UNICODESAFE);
2453                 strcpy(buf,utf8.cstr());
2454         }else if (var == "comment")
2455         {
2456                 utf8 = info.comment;
2457                 utf8.convertTo(String::T_UNICODESAFE);
2458                 strcpy(buf,utf8.cstr());
2459         }else if (var == "bcstClap") //JP-MOD
2460         {
2461                 strcpy(buf,info.ppFlags & ServMgr::bcstClap ? "1":"0");
2462         }else if (var == "uptime")
2463         {
2464                 String uptime;
2465                 if (info.lastPlayStart)
2466                         uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
2467                 else
2468                         uptime.set("-");
2469                 strcpy(buf,uptime.cstr());
2470         }
2471         else if (var == "type")
2472                 sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
2473         else if (var == "ext")
2474                 sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
2475         else if (var == "proto") {
2476                 switch(info.contentType) {
2477                 case ChanInfo::T_WMA:
2478                 case ChanInfo::T_WMV:
2479                         sprintf(buf, "mms://");
2480                         break;
2481                 default:
2482                         sprintf(buf, "http://");
2483                 }
2484         }
2485         else if (var == "localRelays")
2486                 sprintf(buf,"%d",localRelays());
2487         else if (var == "localListeners")
2488                 sprintf(buf,"%d",localListeners());
2489
2490         else if (var == "totalRelays")
2491                 sprintf(buf,"%d",totalRelays());
2492         else if (var == "totalListeners")
2493                 sprintf(buf,"%d",totalListeners());
2494         else if (var == "totalClaps") //JP-MOD
2495                 sprintf(buf,"%d",totalClaps());
2496         else if (var == "status")
2497                 sprintf(buf,"%s",getStatusStr());
2498         else if (var == "keep")
2499                 sprintf(buf,"%s",stayConnected?"Yes":"No");
2500         else if (var == "id")
2501                 info.id.toStr(buf);
2502         else if (var.startsWith("track."))
2503         {
2504
2505                 if (var == "track.title")
2506                         utf8 = info.track.title;
2507                 else if (var == "track.artist")
2508                         utf8 = info.track.artist;
2509                 else if (var == "track.album")
2510                         utf8 = info.track.album;
2511                 else if (var == "track.genre")
2512                         utf8 = info.track.genre;
2513                 else if (var == "track.contactURL")
2514                         utf8 = info.track.contact;
2515
2516                 utf8.convertTo(String::T_UNICODESAFE);
2517                 strcpy(buf,utf8.cstr());
2518
2519         }else if (var == "contactURL")
2520                 sprintf(buf,"%s",info.url.cstr());
2521         else if (var == "streamPos")
2522                 sprintf(buf,"%d",streamPos);
2523         else if (var == "sourceType")
2524                 strcpy(buf,getSrcTypeStr());
2525         else if (var == "sourceProtocol")
2526                 strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
2527         else if (var == "sourceURL")
2528         {
2529                 if (sourceURL.isEmpty())
2530                         sourceHost.host.toStr(buf);
2531                 else
2532                         strcpy(buf,sourceURL.cstr());
2533         }
2534         else if (var == "headPos")
2535                 sprintf(buf,"%d",headPack.pos);
2536         else if (var == "headLen")
2537                 sprintf(buf,"%d",headPack.len);
2538         else if (var == "numHits")
2539         {
2540                 ChanHitList *chl = chanMgr->findHitListByID(info.id);
2541                 int numHits = 0;
2542                 if (chl){
2543 //                      numHits = chl->numHits();
2544                         ChanHit *hit;
2545                         hit = chl->hit;
2546                         while(hit){
2547                                 numHits++;
2548                                 hit = hit->next;
2549                         }
2550                 }
2551                 sprintf(buf,"%d",numHits);
2552         } else if (var == "isBroadcast")
2553                 strcpy(buf, (type == T_BROADCAST) ? "1":"0");
2554         else
2555                 return false;
2556
2557         out.writeString(buf);
2558         return true;
2559 }
2560
2561 // -----------------------------------
2562 void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
2563 {
2564         Channel *c = channel;
2565         while(c)
2566         {
2567                 if ( c->isActive() && c->isBroadcasting() )
2568                         c->broadcastTrackerUpdate(svID,force);
2569                 c=c->next;
2570         }
2571 }
2572
2573
2574 // -----------------------------------
2575 int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
2576 {
2577         int cnt=0;
2578
2579         Channel *c = channel;
2580         while(c)
2581         {
2582                 if (c->sendPacketUp(pack,chanID,srcID,destID))
2583                         cnt++;
2584                 c=c->next;
2585         }
2586
2587         return cnt;
2588 }
2589
2590 // -----------------------------------
2591 void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
2592 {
2593         //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
2594         {
2595
2596                 Host sh = servMgr->serverHost;
2597                 bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
2598                 bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
2599                 bool stable = servMgr->totalStreams>0;
2600
2601
2602                 GnuPacket hit;
2603
2604                 int numChans=0;
2605
2606                 Channel *c = channel;
2607                 while(c)
2608                 {
2609                         if (c->isPlaying())
2610                         {
2611
2612                                 bool tracker = c->isBroadcasting();
2613
2614                                 int ttl = (c->info.getUptime() / servMgr->relayBroadcast);      // 1 hop per N seconds
2615
2616                                 if (ttl < minTTL)
2617                                         ttl = minTTL;
2618
2619                                 if (ttl > maxTTL)
2620                                         ttl = maxTTL;
2621
2622                                 if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
2623                                 {
2624                                         int numOut=0;
2625                                         numChans++;
2626                                         if (serv)
2627                                         {
2628                                                 serv->outputPacket(hit,false);
2629                                                 numOut++;
2630                                         }
2631
2632                                         LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);          
2633
2634                                 }
2635                         }
2636                         c=c->next;
2637                 }
2638                 //if (numChans)
2639                 //      LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);         
2640         }
2641 }
2642 // -----------------------------------
2643 void ChanMgr::setUpdateInterval(unsigned int v)
2644 {
2645         hostUpdateInterval = v;
2646 }
2647
2648
2649 // -----------------------------------
2650 // message check
2651 #if 0
2652                                 ChanPacket pack;
2653                                 MemoryStream mem(pack.data,sizeof(pack.data));
2654                                 AtomStream atom(mem);
2655                                 atom.writeParent(PCP_BCST,3);
2656                                         atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
2657                                         atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
2658                                         atom.writeParent(PCP_MESG,1);
2659                                                 atom.writeString(PCP_MESG_DATA,msg.cstr());
2660
2661                                 mem.len = mem.pos;
2662                                 mem.rewind();
2663                                 pack.len = mem.len;
2664
2665                                 GnuID noID;
2666                                 noID.clear();
2667
2668                                 BroadcastState bcs;
2669                                 PCPStream::readAtom(atom,bcs);
2670                                 //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2671                                 //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
2672                                 //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2673                                 //LOG_DEBUG("Sent message to %d clients",cnt);
2674 #endif
2675 // -----------------------------------
2676 void ChanMgr::setBroadcastMsg(String &msg)
2677 {
2678         if (!msg.isSame(broadcastMsg))
2679         {
2680                 broadcastMsg = msg;
2681
2682                 Channel *c = channel;
2683                 while(c)
2684                 {
2685                         if (c->isActive() && c->isBroadcasting())
2686                         {
2687                                 ChanInfo newInfo = c->info;
2688                                 newInfo.comment = broadcastMsg;
2689                                 c->updateInfo(newInfo);
2690                         }
2691                         c=c->next;
2692                 }
2693
2694         }
2695 }
2696
2697
2698 // -----------------------------------
2699 void ChanMgr::clearHitLists()
2700 {
2701
2702 //      LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
2703         chanMgr->hitlistlock.on();
2704         while (hitlist)
2705         {
2706                 peercastApp->delChannel(&hitlist->info);
2707         
2708                 ChanHitList *next = hitlist->next;
2709
2710                 delete hitlist;
2711
2712                 hitlist = next;
2713         }
2714 //      LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
2715         chanMgr->hitlistlock.off();
2716 }
2717 // -----------------------------------
2718 Channel *ChanMgr::deleteChannel(Channel *delchan)
2719 {
2720         lock.on();
2721
2722         Channel *ch = channel,*prev=NULL,*next=NULL;
2723
2724         while (ch)
2725         {
2726                 if (ch == delchan)
2727                 {
2728                         Channel *next = ch->next;
2729                         if (prev)
2730                                 prev->next = next;
2731                         else
2732                                 channel = next;
2733
2734                         if (delchan->sourceStream){
2735                                 delchan->sourceStream->parent = NULL;
2736                         }
2737
2738                         delete delchan;
2739
2740                         break;
2741                 }
2742                 prev = ch;
2743                 ch=ch->next;
2744         }
2745
2746
2747         lock.off();
2748         return next;
2749 }
2750
2751 // -----------------------------------
2752 Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
2753 {
2754         lock.on();
2755
2756         Channel *nc=NULL;
2757
2758         nc = new Channel();
2759
2760         nc->next = channel;
2761         channel = nc;
2762
2763
2764         nc->info = info;
2765         nc->info.lastPlayStart = 0;
2766         nc->info.lastPlayEnd = 0;
2767         nc->info.status = ChanInfo::S_UNKNOWN;
2768         if (mount)
2769                 nc->mount.set(mount);
2770         nc->setStatus(Channel::S_WAIT);
2771         nc->type = Channel::T_ALLOCATED;
2772         nc->info.createdTime = sys->getTime();
2773
2774         LOG_CHANNEL("New channel created");
2775
2776         lock.off();
2777         return nc;
2778 }
2779 // -----------------------------------
2780 int ChanMgr::pickHits(ChanHitSearch &chs)
2781 {
2782         ChanHitList *chl = hitlist;
2783         while(chl)
2784         {
2785                 if (chl->isUsed())
2786                         if (chl->pickHits(chs))
2787                         {
2788                                 chl->info.id;
2789                                 return 1;
2790                         }
2791                 chl = chl->next;
2792         }
2793         return 0;
2794 }
2795
2796 // -----------------------------------
2797 ChanHitList *ChanMgr::findHitList(ChanInfo &info)
2798 {
2799         ChanHitList *chl = hitlist;
2800         while(chl)
2801         {
2802                 if (chl->isUsed())
2803                         if (chl->info.matchNameID(info))
2804                                 return chl;
2805
2806                 chl = chl->next;
2807         }
2808         return NULL;
2809 }
2810 // -----------------------------------
2811 ChanHitList *ChanMgr::findHitListByID(GnuID &id)
2812 {
2813         ChanHitList *chl = hitlist;
2814         while(chl)
2815         {
2816                 if (chl->isUsed())
2817                         if (chl->info.id.isSame(id))
2818                                 return chl;
2819                 chl = chl->next;
2820         }
2821         return NULL;
2822 }
2823 // -----------------------------------
2824 int ChanMgr::numHitLists()
2825 {
2826         int num=0;
2827         ChanHitList *chl = hitlist;
2828         while(chl)
2829         {
2830                 if (chl->isUsed())
2831                         num++;
2832                 chl = chl->next;
2833         }
2834         return num;
2835 }
2836 // -----------------------------------
2837 ChanHitList *ChanMgr::addHitList(ChanInfo &info)
2838 {       
2839         ChanHitList *chl = new ChanHitList();   
2840
2841
2842         chl->next = hitlist;
2843         hitlist = chl;
2844
2845         chl->used = true;
2846         chl->info = info;
2847         chl->info.createdTime = sys->getTime();
2848         peercastApp->addChannel(&chl->info);
2849
2850
2851         return chl;
2852 }
2853 // -----------------------------------
2854 void ChanMgr::clearDeadHits(bool clearTrackers)
2855 {
2856         unsigned int interval;
2857         
2858         if (servMgr->isRoot)
2859                 interval = 1200;                // mainly for old 0.119 clients
2860         else
2861                 interval = hostUpdateInterval+120;
2862
2863         chanMgr->hitlistlock.on();
2864         ChanHitList *chl = hitlist,*prev = NULL;
2865         while (chl)
2866         {
2867                 if (chl->isUsed())
2868                 {
2869                         if (chl->clearDeadHits(interval,clearTrackers) == 0)
2870                         {
2871                                 if (!isBroadcasting(chl->info.id))
2872                                 {
2873                                         if (!chanMgr->findChannelByID(chl->info.id))
2874                                         {
2875                                                 peercastApp->delChannel(&chl->info);
2876
2877                                                 ChanHitList *next = chl->next;
2878                                                 if (prev)
2879                                                         prev->next = next;
2880                                                 else
2881                                                         hitlist = next;
2882
2883                                                 delete chl;
2884                                                 chl = next;
2885                                                 continue;
2886                                         }
2887                                 }
2888                         }
2889                 }
2890                 prev = chl;
2891                 chl = chl->next;
2892         }
2893         chanMgr->hitlistlock.off();
2894 }
2895 // -----------------------------------
2896 bool    ChanMgr::isBroadcasting(GnuID &id)
2897 {
2898         Channel *ch = findChannelByID(id);
2899         if (ch)
2900                 return ch->isBroadcasting();
2901
2902         return false;
2903 }
2904 // -----------------------------------
2905 bool    ChanMgr::isBroadcasting()
2906 {
2907         Channel *ch = channel;
2908         while (ch)
2909         {
2910                 if (ch->isActive())
2911                         if (ch->isBroadcasting())
2912                                 return true;
2913
2914                 ch = ch->next;
2915         }
2916         return false;
2917 }
2918
2919 // -----------------------------------
2920 int ChanMgr::numChannels()
2921 {
2922         int tot = 0;
2923         Channel *ch = channel;
2924         while (ch)
2925         {
2926                 if (ch->isActive())
2927                         tot++;
2928                 ch = ch->next;
2929         }
2930         return tot;
2931 }
2932
2933 // -----------------------------------
2934 void ChanMgr::deadHit(ChanHit &hit)
2935 {
2936         ChanHitList *chl = findHitListByID(hit.chanID);
2937         if (chl)
2938                 chl->deadHit(hit);
2939 }
2940 // -----------------------------------
2941 void ChanMgr::delHit(ChanHit &hit)
2942 {
2943         ChanHitList *chl = findHitListByID(hit.chanID);
2944         if (chl)
2945                 chl->delHit(hit);
2946 }
2947
2948 // -----------------------------------
2949 void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
2950 {
2951         ChanHit hit;
2952         hit.init();
2953         hit.host = h; 
2954         hit.rhost[0] = h;
2955         hit.rhost[1].init();
2956         hit.tracker = tracker;
2957         hit.recv = true;
2958         hit.chanID = id;
2959         addHit(hit);
2960 }
2961 // -----------------------------------
2962 ChanHit *ChanMgr::addHit(ChanHit &h)
2963 {
2964         if (searchActive)
2965                 lastHit = sys->getTime();
2966
2967         ChanHitList *hl=NULL;
2968
2969         hl = findHitListByID(h.chanID);
2970
2971         if (!hl)
2972         {
2973                 ChanInfo info;
2974                 info.id = h.chanID;
2975                 hl = addHitList(info);
2976         }
2977
2978         if (hl)
2979         {
2980                 return hl->addHit(h);
2981         }else
2982                 return NULL;
2983 }
2984
2985 // -----------------------------------
2986 bool ChanMgr::findParentHit(ChanHit &p)
2987 {
2988         ChanHitList *hl=NULL;
2989
2990         chanMgr->hitlistlock.on();
2991
2992         hl = findHitListByID(p.chanID);
2993
2994         if (hl)
2995         {
2996                 ChanHit *ch = hl->hit;
2997                 while (ch)
2998                 {
2999                         if (!ch->dead && (ch->rhost[0].ip == p.uphost.ip)
3000                                 && (ch->rhost[0].port == p.uphost.port))
3001                         {
3002                                 chanMgr->hitlistlock.off();
3003                                 return 1;
3004                         }
3005                         ch = ch->next;
3006                 }
3007         }
3008
3009         chanMgr->hitlistlock.off();
3010
3011         return 0;
3012 }
3013
3014 // -----------------------------------
3015 class ChanFindInfo : public ThreadInfo
3016 {
3017 public:
3018         ChanInfo        info;
3019         bool    keep;
3020 };
3021 // -----------------------------------
3022 THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
3023 {
3024         ChanFindInfo *cfi = (ChanFindInfo *)th;
3025
3026         ChanInfo info;
3027         info = cfi->info;
3028
3029
3030         Channel *ch = chanMgr->findChannelByNameID(info);
3031
3032         chanMgr->currFindAndPlayChannel = info.id;
3033
3034         if (!ch)
3035                 ch = chanMgr->findAndRelay(info);
3036
3037         if (ch)
3038         {
3039                 // check that a different channel hasn`t be selected already.
3040                 if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
3041                         chanMgr->playChannel(ch->info);
3042
3043                 if (cfi->keep)
3044                         ch->stayConnected = cfi->keep;
3045         }
3046
3047         delete cfi;
3048         return 0;
3049 }
3050 // -----------------------------------
3051 void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
3052 {
3053         ChanFindInfo *cfi = new ChanFindInfo;
3054         cfi->info = info;
3055         cfi->keep = keep;
3056         cfi->func = findAndPlayChannelProc;
3057
3058
3059         sys->startThread(cfi);
3060 }
3061 // -----------------------------------
3062 void ChanMgr::playChannel(ChanInfo &info)
3063 {
3064
3065         char str[128],fname[256],idStr[128];
3066
3067         sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
3068         info.id.toStr(idStr);
3069
3070         PlayList::TYPE type;
3071
3072
3073         if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
3074         {
3075                 type = PlayList::T_ASX;
3076                 // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
3077                 // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
3078                 if (servMgr->getModulePath) //JP-EX
3079                 {
3080                         peercastApp->getDirectory();
3081                         sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);   
3082                 }else
3083                         sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
3084         }else if (info.contentType == ChanInfo::T_OGM)
3085         {
3086                 type = PlayList::T_RAM;
3087                 if (servMgr->getModulePath) //JP-EX
3088                 {
3089                         peercastApp->getDirectory();
3090                         sprintf(fname,"%s/play.ram",servMgr->modulePath);
3091                 }else
3092                         sprintf(fname,"%s/play.ram",peercastApp->getPath());
3093
3094         }else
3095         {
3096                 type = PlayList::T_SCPLS;
3097                 if (servMgr->getModulePath) //JP-EX
3098                 {
3099                         peercastApp->getDirectory();
3100                         sprintf(fname,"%s/play.pls",servMgr->modulePath);
3101                 }else
3102                         sprintf(fname,"%s/play.pls",peercastApp->getPath());
3103         }
3104
3105
3106         PlayList *pls = new PlayList(type,1);
3107         pls->addChannel(str,info);
3108
3109
3110         LOG_DEBUG("Writing %s",fname);
3111         FileStream file;
3112         file.openWriteReplace(fname);
3113         pls->write(file);
3114         file.close();
3115
3116
3117         LOG_DEBUG("Executing: %s",fname);
3118         sys->executeFile(fname);
3119         delete pls;
3120
3121 }
3122
3123 // -----------------------------------
3124 ChanHitList::ChanHitList()
3125 {
3126         info.init();
3127         lastHitTime = 0;
3128         used = false;
3129         hit = NULL;
3130 }
3131 // -----------------------------------
3132 ChanHitList::~ChanHitList()
3133 {
3134         chanMgr->hitlistlock.on();
3135         while (hit)
3136                 hit = deleteHit(hit);
3137         chanMgr->hitlistlock.off();
3138 }
3139 // -----------------------------------
3140 void ChanHit::pickNearestIP(Host &h)
3141 {
3142         for(int i=0; i<2; i++)
3143         {
3144                 if (h.classType() == rhost[i].classType())
3145                 {
3146                         host = rhost[i];
3147                         break;
3148                 }
3149         }
3150 }
3151
3152 // -----------------------------------
3153 void ChanHit::init()
3154 {
3155         host.init();
3156
3157         rhost[0].init();
3158         rhost[1].init();
3159
3160         next = NULL;
3161
3162         numListeners = 0;
3163         numRelays = 0;
3164         clap_pp = 0; //JP-MOD
3165
3166         dead = tracker = firewalled = stable = yp = false;
3167         recv = cin = direct = relay = true;
3168         relayfull = chfull = ratefull = false;
3169         direct = 0;
3170         numHops = 0;
3171         time = upTime = 0;
3172         lastContact = 0;
3173
3174         version = 0;
3175         version_vp = 0;
3176
3177         version_ex_prefix[0] = ' ';
3178         version_ex_prefix[1] = ' ';
3179         version_ex_number = 0;
3180
3181         status = 0;
3182         servent_id = 0;
3183
3184         sessionID.clear();
3185         chanID.clear();
3186
3187
3188         oldestPos = newestPos = 0;
3189         uphost.init();
3190         uphostHops = 0;
3191 }
3192
3193 // -----------------------------------
3194 void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp)
3195 {
3196         init();
3197         firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
3198         numListeners = numl;
3199         numRelays = numr;
3200         upTime = uptm;
3201         stable = servMgr->totalStreams>0;
3202         sessionID = servMgr->sessionID;
3203         recv = connected;
3204
3205         direct = !servMgr->directFull();
3206 //      relay = !servMgr->relaysFull();
3207         cin = !servMgr->controlInFull();
3208
3209         relayfull = servMgr->relaysFull();
3210         chfull = isFull;
3211
3212         Channel *c = chanMgr->channel;
3213         int noRelay = 0;
3214         unsigned int needRate = 0;
3215         unsigned int allRate = 0;
3216         while(c){
3217                 if (c->isPlaying()){
3218                         allRate += c->info.bitrate * c->localRelays();
3219                         if ((c != ch) && (c->localRelays() == 0)){
3220                                 if(!isIndexTxt(c))      // for PCRaw (relay)
3221                                         noRelay++;
3222                                 needRate+=c->info.bitrate;
3223                         }
3224                 }
3225                 c = c->next;
3226         }
3227         unsigned int numRelay = servMgr->numStreams(Servent::T_RELAY,false);
3228         int diff = servMgr->maxRelays - numRelay;
3229         if (ch->localRelays()){
3230                 if (noRelay > diff){
3231                         noRelay = diff;
3232                 }
3233         } else {
3234                 noRelay = 0;
3235                 needRate = 0;
3236         }
3237
3238 //      ratefull = servMgr->bitrateFull(needRate+bitrate);
3239         ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
3240
3241         if (!isIndexTxt(ch))
3242                 relay = (!relayfull) && (!chfull) && (!ratefull) && (numRelay + noRelay < servMgr->maxRelays);
3243         else
3244                 relay = (!chfull) && (!ratefull); // for PCRaw (relay)
3245
3246 /*      if (relayfull){
3247                 LOG_DEBUG("Reject by relay full");
3248         }
3249         if (chfull){
3250                 LOG_DEBUG("Reject by channel full");
3251         }
3252         if (ratefull){
3253                 LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
3254         }*/
3255
3256         host = servMgr->serverHost;
3257
3258         version = PCP_CLIENT_VERSION;
3259         version_vp = PCP_CLIENT_VERSION_VP;
3260         if (version_ex)
3261         {
3262                 strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
3263                 version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
3264         } else
3265         {
3266                 version_ex_prefix[0] = ' ';
3267                 version_ex_prefix[1] = ' ';
3268                 version_ex_number = 0;
3269         }
3270
3271         status = ch->status;
3272
3273         rhost[0] = Host(host.ip,host.port);
3274         rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
3275
3276         if (firewalled)
3277                 rhost[0].port = 0;
3278
3279         oldestPos = oldp;
3280         newestPos = newp;
3281
3282         uphost.ip = ch->sourceHost.host.ip;
3283         uphost.port = ch->sourceHost.host.port;
3284         uphostHops = 1;
3285 }
3286
3287 // -----------------------------------
3288 void ChanHit::initLocal_pp(bool isStealth, int numClaps) //JP-MOD
3289 {
3290         numListeners = numListeners && !isStealth ? 1 : 0;
3291         clap_pp = numClaps;
3292 }
3293
3294 // -----------------------------------
3295 void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
3296 {
3297         bool addChan=chanID.isSet();
3298         bool uphostdata=(uphost.ip != 0);
3299
3300         int fl1 = 0; 
3301         if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
3302         if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
3303         if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
3304         if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
3305         if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
3306         if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
3307
3308         atom.writeParent(PCP_HOST,13  + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0) + (clap_pp?1:0/*JP-MOD*/));
3309
3310         if (addChan)
3311                 atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
3312         atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
3313         atom.writeInt(PCP_HOST_IP,rhost[0].ip);
3314         atom.writeShort(PCP_HOST_PORT,rhost[0].port);
3315         atom.writeInt(PCP_HOST_IP,rhost[1].ip);
3316         atom.writeShort(PCP_HOST_PORT,rhost[1].port);
3317         atom.writeInt(PCP_HOST_NUML,numListeners);
3318         atom.writeInt(PCP_HOST_NUMR,numRelays);
3319         atom.writeInt(PCP_HOST_UPTIME,upTime);
3320         atom.writeInt(PCP_HOST_VERSION,version);
3321         atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
3322         if (version_ex_number){
3323                 atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
3324                 atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
3325         }
3326         atom.writeChar(PCP_HOST_FLAGS1,fl1);
3327         atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
3328         atom.writeInt(PCP_HOST_NEWPOS,newestPos);
3329         if (uphostdata){
3330                 atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
3331                 atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
3332                 atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
3333         }
3334         if (clap_pp){   //JP-MOD
3335                 atom.writeInt(PCP_HOST_CLAP_PP,clap_pp);
3336         }
3337 }
3338 // -----------------------------------
3339 bool    ChanHit::writeVariable(Stream &out, const String &var)
3340 {
3341         char buf[1024];
3342
3343         if (var == "rhost0")
3344         {
3345                 if (servMgr->enableGetName) //JP-EX s
3346                 {
3347                         char buf2[256];
3348                         if (firewalled) 
3349                         {
3350                                 if (numRelays==0) 
3351                                         strcpy(buf,"<font color=red>");
3352                                 else 
3353                                         strcpy(buf,"<font color=orange>");
3354                         }
3355                         else {
3356                                 if (!relay){
3357                                         if (numRelays==0){
3358                                                 strcpy(buf,"<font color=purple>");
3359                                         } else {
3360                                                 strcpy(buf,"<font color=blue>");
3361                                         }
3362                                 } else {
3363                                         strcpy(buf,"<font color=green>");
3364                                 }
3365                         }
3366
3367                         rhost[0].toStr(buf2);
3368                         strcat(buf,buf2);
3369
3370                         char h_name[128];
3371                         if (ClientSocket::getHostname(h_name,sizeof(h_name),rhost[0].ip)) // BOF\91Î\8dô\82Á\82Û\82¢
3372                         {
3373                                 strcat(buf,"[");
3374                                 strcat(buf,h_name);
3375                                 strcat(buf,"]");
3376                         }
3377                         strcat(buf,"</font>");
3378                 } //JP-EX e
3379                 else
3380                         rhost[0].toStr(buf);
3381         }
3382         else if (var == "rhost1")
3383                 rhost[1].toStr(buf);
3384         else if (var == "numHops")
3385                 sprintf(buf,"%d",numHops);
3386         else if (var == "numListeners")
3387                 sprintf(buf,"%d",numListeners);
3388         else if (var == "numRelays")
3389                 sprintf(buf,"%d",numRelays);
3390         else if (var == "uptime")
3391         {
3392                 String timeStr;
3393                 timeStr.setFromStopwatch(upTime);
3394                 strcpy(buf,timeStr.cstr());
3395         }else if (var == "update")
3396         {
3397                 String timeStr;
3398                 if (timeStr)
3399                         timeStr.setFromStopwatch(sys->getTime()-time);
3400                 else
3401                         timeStr.set("-");
3402                 strcpy(buf,timeStr.cstr());
3403         }else if (var == "isFirewalled"){
3404                 sprintf(buf,"%d",firewalled?1:0);
3405         }else if (var == "version"){
3406                 sprintf(buf,"%d",version);
3407         }else if (var == "agent"){
3408                 if (version){
3409                         if (version_ex_number){
3410                                 sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
3411                         } else if (version_vp){
3412                                 sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
3413                         } else {
3414                                 sprintf(buf,"v0.%d", version);
3415                         }
3416                 } else {
3417                         strcpy(buf, "0");
3418                 }
3419         }
3420         else if (var == "check")
3421         {
3422                 char buf2[256];
3423                 strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
3424                 rhost[0].IPtoStr(buf2);
3425                 strcat(buf, buf2);
3426                 strcat(buf, "')\">_</a>");
3427         }
3428         else if (var == "uphost")               // tree
3429                 uphost.toStr(buf);
3430         else if (var == "uphostHops")   // tree
3431                 sprintf(buf,"%d",uphostHops);
3432         else if (var == "canRelay")             // tree
3433                 sprintf(buf, "%d",relay);
3434         else
3435                 return false;
3436
3437         out.writeString(buf);
3438         return true;
3439 }
3440
3441 // -----------------------------------
3442 int ChanHitList::getTotalListeners()
3443 {
3444         int cnt=0;
3445         ChanHit *h = hit;
3446         while (h)
3447         {
3448                 if (h->host.ip)
3449                         cnt+=h->numListeners;
3450                 h=h->next;
3451         }
3452         return cnt;
3453 }
3454 // -----------------------------------
3455 int ChanHitList::getTotalRelays()
3456 {
3457         int cnt=0;
3458         ChanHit *h = hit;
3459         while (h)
3460         {
3461                 if (h->host.ip)
3462                         cnt+=h->numRelays;
3463                 h=h->next;
3464         }
3465         return cnt;
3466 }
3467 // -----------------------------------
3468 int ChanHitList::getTotalFirewalled()
3469 {
3470         int cnt=0;
3471         ChanHit *h = hit;
3472         while (h)
3473         {
3474                 if (h->host.ip)
3475                         if (h->firewalled)
3476                                 cnt++;
3477                 h=h->next;
3478         }
3479         return cnt;
3480 }
3481
3482 // -----------------------------------
3483 int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
3484 {
3485         return 0;
3486 }
3487
3488 void ChanHitList::clearHits(bool flg)
3489 {
3490         ChanHit *c = hit, *prev = NULL;
3491
3492         while(c){
3493                 if (flg || (c->numHops != 0)){
3494                         ChanHit *next = c->next;
3495                         if (prev)
3496                                 prev->next = next;
3497                         else
3498                                 hit = next;
3499
3500                         delete c;
3501                         c = next;
3502                 } else {
3503                         prev = c;
3504                         c = c->next;
3505                 }
3506         }
3507 }
3508
3509 // -----------------------------------
3510 ChanHit *ChanHitList::deleteHit(ChanHit *ch)
3511 {
3512         ChanHit *c = hit,*prev=NULL;
3513         while (c)
3514         {
3515                 if (c == ch)
3516                 {
3517                         ChanHit *next = c->next;
3518                         if (prev)
3519                                 prev->next = next;
3520                         else
3521                                 hit = next;
3522
3523                         delete c;
3524
3525                         return next;
3526                 }
3527                 prev=c;
3528                 c=c->next;
3529         }
3530
3531         return NULL;
3532 }
3533 // -----------------------------------
3534 ChanHit *ChanHitList::addHit(ChanHit &h)
3535 {
3536         char ip0str[64],ip1str[64];
3537         h.rhost[0].toStr(ip0str);
3538         h.rhost[1].toStr(ip1str);
3539         char uphostStr[64];
3540         h.uphost.toStr(uphostStr);
3541         if (h.uphost.ip){
3542                 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
3543         } else {
3544                 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
3545         }
3546
3547         // dont add our own hits
3548         if (servMgr->sessionID.isSame(h.sessionID))
3549                 return NULL;
3550
3551
3552         lastHitTime = sys->getTime();
3553         h.time = lastHitTime;
3554
3555         ChanHit *ch = hit;
3556         while (ch)
3557         {
3558                 if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
3559                         if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
3560                         {
3561                                 if (!ch->dead)
3562                                 {
3563                                         if (ch->numHops > 0 && h.numHops == 0)
3564                                                 // downstream hit recieved as RelayHost
3565                                                 return ch;
3566                                         ChanHit *next = ch->next;
3567                                         *ch = h;
3568                                         ch->next = next;
3569                                         return ch;
3570                                 }
3571                         }
3572                 ch=ch->next;
3573         }
3574
3575         // clear hits with same session ID (IP may have changed)
3576         if (h.sessionID.isSet())
3577         {
3578                 ChanHit *ch = hit;
3579                 while (ch)
3580                 {
3581                         if (ch->host.ip)
3582                                 if (ch->sessionID.isSame(h.sessionID))
3583                                 {
3584                                         ch = deleteHit(ch);
3585                                         continue;                                               
3586                                 }
3587                         ch=ch->next;
3588                 }
3589         }
3590
3591
3592         // else add new hit
3593         {
3594                 ChanHit *ch = new ChanHit();
3595                 *ch = h;
3596                 ch->chanID = info.id;
3597                 ch->next = hit;
3598                 hit = ch;
3599                 return ch;
3600         }
3601
3602         return NULL;
3603 }
3604
3605
3606 // -----------------------------------
3607 int     ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
3608 {
3609         int cnt=0;
3610         unsigned int ctime = sys->getTime();
3611
3612 //      LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
3613         chanMgr->hitlistlock.on();
3614         ChanHit *ch = hit;
3615         while (ch)
3616         {
3617                 if (ch->host.ip)
3618                 {
3619                         if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
3620                         {
3621 //                              ch = deleteHit(ch);
3622
3623                                 if (ch->firewalled){
3624 //                                      LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
3625                                         if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
3626                                                 ch = deleteHit(ch);
3627                                         } else {
3628                                                 ch->numHops = 0;
3629                                                 ch->numListeners = 0;
3630                                                 ch = ch->next;
3631                                         }
3632                                 } else {
3633                                         ch = deleteHit(ch);
3634                                 }
3635
3636                                 continue;
3637                         }else
3638                                 cnt++;
3639                 }
3640                 ch = ch->next;
3641         }
3642 //      LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
3643         chanMgr->hitlistlock.off();
3644         return cnt;
3645 }
3646
3647
3648 // -----------------------------------
3649 void    ChanHitList::deadHit(ChanHit &h)
3650 {
3651         char ip0str[64],ip1str[64];
3652         h.rhost[0].toStr(ip0str);
3653         h.rhost[1].toStr(ip1str);
3654         LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
3655
3656         ChanHit *ch = hit;
3657         while (ch)
3658         {
3659                 if (ch->host.ip)
3660                         if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3661                         {
3662                                 ch->dead = true;
3663                         }
3664                 ch = ch->next;
3665         }
3666 }
3667 // -----------------------------------
3668 void    ChanHitList::delHit(ChanHit &h)
3669 {
3670         char ip0str[64],ip1str[64];
3671         h.rhost[0].toStr(ip0str);
3672         h.rhost[1].toStr(ip1str);
3673         LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
3674
3675         ChanHit *ch = hit;
3676         while (ch)
3677         {
3678                 if (ch->host.ip)
3679                         if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3680                         {
3681                                 ch=deleteHit(ch);
3682                                 continue;
3683                         }
3684                 ch = ch->next;
3685         }
3686 }
3687 // -----------------------------------
3688 int     ChanHitList::numHits()
3689 {
3690         int cnt=0;
3691         ChanHit *ch = hit;
3692         while (ch)
3693         {
3694                 if (ch->host.ip && !ch->dead && ch->numHops)
3695                         cnt++;
3696                 ch = ch->next;
3697         }
3698
3699         return cnt;
3700 }
3701 // -----------------------------------
3702 int     ChanHitList::numListeners()
3703 {
3704         int cnt=0;
3705         ChanHit *ch = hit;
3706         while (ch)
3707         {
3708                 if (ch->host.ip && !ch->dead && ch->numHops)
3709                         cnt += (unsigned int)ch->numListeners > 3 ? 3 : ch->numListeners;
3710                 ch=ch->next;
3711         }
3712
3713         return cnt;
3714 }
3715
3716 // -----------------------------------
3717 int ChanHitList::numClaps()     //JP-MOD
3718 {
3719         int cnt=0;
3720         ChanHit *ch = hit;
3721         while (ch)
3722         {
3723                 if (ch->host.ip && !ch->dead && ch->numHops && (ch->clap_pp & 1)){
3724                         cnt++;
3725                 }
3726                 ch=ch->next;
3727         }
3728
3729         return cnt;
3730 }
3731 // -----------------------------------
3732 int     ChanHitList::numRelays()
3733 {
3734         int cnt=0;
3735         ChanHit *ch = hit;
3736         while (ch)
3737         {
3738                 if (ch->host.ip && !ch->dead)
3739                         cnt += ch->numRelays;
3740                 ch=ch->next;
3741         }
3742
3743         return cnt;
3744 }
3745
3746 // -----------------------------------
3747 int     ChanHitList::numTrackers()
3748 {
3749         int cnt=0;
3750         ChanHit *ch = hit;
3751         while (ch)
3752         {
3753                 if ((ch->host.ip && !ch->dead) && (ch->tracker))
3754                         cnt++;
3755                 ch=ch->next;
3756         }
3757         return cnt;
3758 }
3759 // -----------------------------------
3760 int     ChanHitList::numFirewalled()
3761 {
3762         int cnt=0;
3763         ChanHit *ch = hit;
3764         while (ch)
3765         {
3766                 if (ch->host.ip && !ch->dead)
3767                         cnt += ch->firewalled?1:0;
3768                 ch=ch->next;
3769         }
3770         return cnt;
3771 }
3772 // -----------------------------------
3773 int     ChanHitList::closestHit()
3774 {
3775         unsigned int hop=10000;
3776         ChanHit *ch = hit;
3777         while (ch)
3778         {
3779                 if (ch->host.ip && !ch->dead)
3780                         if (ch->numHops < hop)
3781                                 hop = ch->numHops;
3782                 ch=ch->next;
3783         }
3784
3785         return hop;
3786 }
3787 // -----------------------------------
3788 int     ChanHitList::furthestHit()
3789 {
3790         unsigned int hop=0;
3791         ChanHit *ch = hit;
3792         while (ch)
3793         {
3794                 if (ch->host.ip && !ch->dead)
3795                         if (ch->numHops > hop)
3796                                 hop = ch->numHops;
3797                 ch=ch->next;
3798         }
3799
3800         return hop;
3801 }
3802 // -----------------------------------
3803 unsigned int    ChanHitList::newestHit()
3804 {
3805         unsigned int time=0;
3806         ChanHit *ch = hit;
3807         while (ch)
3808         {
3809                 if (ch->host.ip && !ch->dead)
3810                         if (ch->time > time)
3811                                 time = ch->time;
3812                 ch=ch->next;
3813         }
3814
3815         return time;
3816 }
3817 // -----------------------------------
3818 int ChanHitList::pickHits(ChanHitSearch &chs)
3819 {
3820         ChanHit best,*bestP=NULL;
3821         best.init();
3822         best.numHops = 255;
3823         best.time = 0;
3824
3825         unsigned int ctime = sys->getTime();
3826
3827         ChanHit *c = hit;
3828         while (c)
3829         {
3830                 if (c->host.ip && !c->dead)
3831                 {
3832                         if (!chs.excludeID.isSame(c->sessionID))
3833                         if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
3834                         if ((c->numHops<=best.numHops)) // (c->time>=best.time))
3835                         if (c->relay || (!c->relay && chs.useBusyRelays))
3836                         if (c->cin || (!c->cin && chs.useBusyControls))
3837                         {
3838
3839                                 if (chs.trackersOnly && c->tracker)
3840                                 {
3841                                         if (chs.matchHost.ip)
3842                                         {
3843                                                 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3844                                                 {
3845                                                         bestP = c;
3846                                                         best = *c;
3847                                                         best.host = best.rhost[1];      // use lan ip
3848                                                 }
3849                                         }else if (c->firewalled == chs.useFirewalled)
3850                                         {
3851                                                 bestP = c;
3852                                                 best = *c;
3853                                                 best.host = best.rhost[0];                      // use wan ip
3854                                         }
3855                                 }else if (!chs.trackersOnly && !c->tracker)
3856                                 {
3857                                         if (chs.matchHost.ip)
3858                                         {
3859                                                 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3860                                                 {
3861                                                         bestP = c;
3862                                                         best = *c;
3863                                                         best.host = best.rhost[1];      // use lan ip
3864                                                 }
3865                                         }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
3866                                         {
3867                                                 bestP = c;
3868                                                 best = *c;
3869                                                 best.host = best.rhost[0];                      // use wan ip
3870                                         }
3871                                 }
3872                         }
3873                 }
3874                 c=c->next;
3875         }
3876
3877         if (bestP)
3878         {
3879                 if (chs.numResults < ChanHitSearch::MAX_RESULTS)
3880                 {
3881                         if (chs.waitDelay)
3882                                 bestP->lastContact = ctime;
3883                         chs.best[chs.numResults++] = best;
3884                         return 1;
3885                 }
3886
3887         }
3888
3889         return 0;
3890 }
3891
3892
3893 // -----------------------------------
3894 int ChanHitList::pickSourceHits(ChanHitSearch &chs)
3895 {
3896         if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
3897         return 0;
3898 }
3899
3900
3901 // -----------------------------------
3902 const char *ChanInfo::getTypeStr(TYPE t)
3903 {
3904         switch (t)
3905         {
3906                 case T_RAW: return "RAW";
3907
3908                 case T_MP3: return "MP3";
3909                 case T_OGG: return "OGG";
3910                 case T_OGM: return "OGM";
3911                 case T_WMA: return "WMA";
3912
3913                 case T_MOV: return "MOV";
3914                 case T_MPG: return "MPG";
3915                 case T_NSV: return "NSV";
3916                 case T_WMV: return "WMV";
3917
3918                 case T_PLS: return "PLS";
3919                 case T_ASX: return "ASX";
3920
3921                 default: return "UNKNOWN";
3922         }
3923 }
3924 // -----------------------------------
3925 const char *ChanInfo::getProtocolStr(PROTOCOL t)
3926 {
3927         switch (t)
3928         {
3929                 case SP_PEERCAST: return "PEERCAST";
3930                 case SP_HTTP: return "HTTP";
3931                 case SP_FILE: return "FILE";
3932                 case SP_MMS: return "MMS";
3933                 case SP_PCP: return "PCP";
3934                 default: return "UNKNOWN";
3935         }
3936 }
3937 // -----------------------------------
3938 ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
3939 {
3940         if (stricmp(str,"PEERCAST")==0)
3941                 return SP_PEERCAST;
3942         else if (stricmp(str,"HTTP")==0)
3943                 return SP_HTTP;
3944         else if (stricmp(str,"FILE")==0)
3945                 return SP_FILE;
3946         else if (stricmp(str,"MMS")==0)
3947                 return SP_MMS;
3948         else if (stricmp(str,"PCP")==0)
3949                 return SP_PCP;
3950         else 
3951                 return SP_UNKNOWN;
3952 }
3953
3954 // -----------------------------------
3955 const char *ChanInfo::getTypeExt(TYPE t)
3956 {
3957         switch(t)
3958         {
3959                 case ChanInfo::T_OGM:
3960                 case ChanInfo::T_OGG:
3961                         return ".ogg";
3962                 case ChanInfo::T_MP3:
3963                         return ".mp3";
3964                 case ChanInfo::T_MOV:
3965                         return ".mov";
3966                 case ChanInfo::T_NSV:
3967                         return ".nsv";
3968                 case ChanInfo::T_WMV:
3969                         return ".wmv";
3970                 case ChanInfo::T_WMA:
3971                         return ".wma";
3972                 default:
3973                         return "";
3974         }
3975 }
3976 // -----------------------------------
3977 ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
3978 {
3979         if (stricmp(str,"MP3")==0)
3980                 return T_MP3;
3981         else if (stricmp(str,"OGG")==0)
3982                 return T_OGG;
3983         else if (stricmp(str,"OGM")==0)
3984                 return T_OGM;
3985         else if (stricmp(str,"RAW")==0)
3986                 return T_RAW;
3987         else if (stricmp(str,"NSV")==0)
3988                 return T_NSV;
3989         else if (stricmp(str,"WMA")==0)
3990                 return T_WMA;
3991         else if (stricmp(str,"WMV")==0)
3992                 return T_WMV;
3993         else if (stricmp(str,"PLS")==0)
3994                 return T_PLS;
3995         else if (stricmp(str,"M3U")==0)
3996                 return T_PLS;
3997         else if (stricmp(str,"ASX")==0)
3998                 return T_ASX;
3999         else 
4000                 return T_UNKNOWN;
4001 }
4002 // -----------------------------------
4003 bool    ChanInfo::matchNameID(ChanInfo &inf)
4004 {
4005         if (inf.id.isSet())
4006                 if (id.isSame(inf.id))
4007                         return true;
4008
4009         if (!inf.name.isEmpty())
4010                 if (name.contains(inf.name))
4011                         return true;
4012
4013         return false;
4014 }
4015 // -----------------------------------
4016 bool    ChanInfo::match(ChanInfo &inf)
4017 {
4018         bool matchAny=true;
4019
4020         if (inf.status != S_UNKNOWN)
4021         {
4022                 if (status != inf.status)
4023                         return false;
4024         }
4025
4026         if (inf.bitrate != 0)
4027         {
4028                 if (bitrate == inf.bitrate)
4029                         return true;
4030                 matchAny = false;
4031         }
4032
4033         if (inf.id.isSet())
4034         {
4035                 if (id.isSame(inf.id))
4036                         return true;
4037                 matchAny = false;
4038         }
4039
4040         if (inf.contentType != T_UNKNOWN)
4041         {
4042                 if (contentType == inf.contentType)
4043                         return true;
4044                 matchAny = false;
4045         }
4046
4047         if (!inf.name.isEmpty())
4048         {
4049                 if (name.contains(inf.name))
4050                         return true;
4051                 matchAny = false;
4052         }
4053
4054         if (!inf.genre.isEmpty())
4055         {
4056                 if (genre.contains(inf.genre))
4057                         return true;
4058                 matchAny = false;
4059         }
4060
4061         return matchAny;
4062 }
4063 // -----------------------------------
4064 bool TrackInfo::update(TrackInfo &inf)
4065 {
4066         bool changed = false;
4067
4068         if (!contact.isSame(inf.contact))
4069         {
4070                 contact = inf.contact;
4071                 changed = true;
4072         }
4073
4074         if (!title.isSame(inf.title))
4075         {
4076                 title = inf.title;
4077                 changed = true;
4078         }
4079
4080         if (!artist.isSame(inf.artist))
4081         {
4082                 artist = inf.artist;
4083                 changed = true;
4084         }
4085
4086         if (!album.isSame(inf.album))
4087         {
4088                 album = inf.album;
4089                 changed = true;
4090         }
4091
4092         if (!genre.isSame(inf.genre))
4093         {
4094                 genre = inf.genre;
4095                 changed = true;
4096         }
4097
4098
4099         return changed;
4100 }
4101
4102
4103 // -----------------------------------
4104 bool ChanInfo::update(ChanInfo &info)
4105 {
4106         bool changed = false;
4107
4108
4109
4110         // check valid id
4111         if (!info.id.isSet())
4112                 return false;
4113
4114         // only update from chaninfo that has full name etc..
4115         if (info.name.isEmpty())
4116                 return false;
4117
4118         // check valid broadcaster key
4119         if (bcID.isSet())
4120         {
4121                 if (!bcID.isSame(info.bcID))
4122                 {
4123                         LOG_ERROR("ChanInfo BC key not valid");
4124                         return false;
4125                 }
4126         }else
4127         {
4128                 bcID = info.bcID;
4129         }
4130
4131
4132
4133         if (bitrate != info.bitrate)
4134         {
4135                 bitrate = info.bitrate;
4136                 changed = true;
4137         }
4138
4139         if (contentType != info.contentType)
4140         {
4141                 contentType = info.contentType;
4142                 changed = true;
4143         }
4144
4145         if(ppFlags != info.ppFlags) //JP-MOD
4146         {
4147                 ppFlags = info.ppFlags;
4148                 changed = true;
4149         }
4150
4151         if (!desc.isSame(info.desc)) //JP-EX
4152         {
4153                 desc = info.desc;
4154                 changed = true;
4155         }
4156
4157         if (!name.isSame(info.name))
4158         {
4159                 name = info.name;
4160                 changed = true;
4161         }
4162
4163         if (!comment.isSame(info.comment))
4164         {
4165                 comment = info.comment;
4166                 changed = true;
4167         }
4168
4169         if (!genre.isSame(info.genre))
4170         {
4171                 genre = info.genre;
4172                 changed = true;
4173         }
4174         
4175         if (!url.isSame(info.url))
4176         {
4177                 url = info.url;
4178                 changed = true;
4179         }
4180
4181         if (track.update(info.track))
4182                 changed = true;
4183
4184
4185         return changed;
4186 }
4187 // -----------------------------------
4188 void ChanInfo::initNameID(const char *n)
4189 {
4190         init();
4191         id.fromStr(n);
4192         if (!id.isSet())
4193                 name.set(n);
4194 }
4195
4196 // -----------------------------------
4197 void ChanInfo::init()
4198 {
4199         status = S_UNKNOWN;
4200         name.clear();
4201         bitrate = 0;
4202         contentType = T_UNKNOWN;
4203         srcProtocol = SP_UNKNOWN;
4204         id.clear();
4205         url.clear();
4206         genre.clear();
4207         comment.clear();
4208         track.clear();
4209         lastPlayStart = 0;
4210         lastPlayEnd = 0;
4211         numSkips = 0;
4212         bcID.clear();
4213         createdTime = 0;
4214         ppFlags = 0; //JP-MOD
4215 }
4216 // -----------------------------------
4217 void ChanInfo::readTrackXML(XML::Node *n)
4218 {
4219         track.clear();
4220         readXMLString(track.title,n,"title");
4221         readXMLString(track.contact,n,"contact");
4222         readXMLString(track.artist,n,"artist");
4223         readXMLString(track.album,n,"album");
4224         readXMLString(track.genre,n,"genre");
4225 }
4226 // -----------------------------------
4227 unsigned int ChanInfo::getUptime()
4228 {
4229         // calculate uptime and cap if requested by settings.
4230         unsigned int upt;
4231         upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
4232         if (chanMgr->maxUptime)
4233                 if (upt > chanMgr->maxUptime)
4234                         upt = chanMgr->maxUptime;
4235         return upt;
4236 }
4237 // -----------------------------------
4238 unsigned int ChanInfo::getAge()
4239 {
4240         return sys->getTime()-createdTime;
4241 }
4242
4243 // ------------------------------------------
4244 void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
4245 {
4246         for(int i=0; i<numc; i++)
4247         {
4248                 int c,d;
4249                 ID4 id = atom.read(c,d);
4250                 if (id == PCP_CHAN_TRACK_TITLE)
4251                 {
4252                         atom.readString(track.title.data,sizeof(track.title.data),d);
4253                 }else if (id == PCP_CHAN_TRACK_CREATOR)
4254                 {
4255                         atom.readString(track.artist.data,sizeof(track.artist.data),d);
4256                 }else if (id == PCP_CHAN_TRACK_URL)
4257                 {
4258                         atom.readString(track.contact.data,sizeof(track.contact.data),d);
4259                 }else if (id == PCP_CHAN_TRACK_ALBUM)
4260                 {
4261                         atom.readString(track.album.data,sizeof(track.album.data),d);
4262                 }else
4263                         atom.skip(c,d);
4264         }
4265 }
4266 // ------------------------------------------
4267 void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
4268 {
4269         for(int i=0; i<numc; i++)
4270         {
4271                 int c,d;
4272                 ID4 id = atom.read(c,d);
4273                 if (id == PCP_CHAN_INFO_NAME)
4274                 {
4275                         atom.readString(name.data,sizeof(name.data),d);
4276                 }else if (id == PCP_CHAN_INFO_BITRATE)
4277                 {
4278                         bitrate = atom.readInt();
4279                 }else if (id == PCP_CHAN_INFO_GENRE)
4280                 {
4281                         atom.readString(genre.data,sizeof(genre.data),d);
4282                 }else if (id == PCP_CHAN_INFO_URL)
4283                 {
4284                         atom.readString(url.data,sizeof(url.data),d);
4285                 }else if (id == PCP_CHAN_INFO_DESC)
4286                 {
4287                         atom.readString(desc.data,sizeof(desc.data),d);
4288                 }else if (id == PCP_CHAN_INFO_COMMENT)
4289                 {
4290                         atom.readString(comment.data,sizeof(comment.data),d);
4291                 }else if (id == PCP_CHAN_INFO_TYPE)
4292                 {
4293                         char type[16];
4294                         atom.readString(type,sizeof(type),d);
4295                         contentType = ChanInfo::getTypeFromStr(type);
4296                 }else if (id == PCP_CHAN_INFO_PPFLAGS) //JP-MOD
4297                 {
4298                         ppFlags = (unsigned int)atom.readInt();
4299                 }else
4300                         atom.skip(c,d);
4301         }       
4302 }
4303
4304 // -----------------------------------
4305 void ChanInfo::writeInfoAtoms(AtomStream &atom)
4306 {
4307         atom.writeParent(PCP_CHAN_INFO,7 + (ppFlags ? 1:0/*JP-MOD*/));
4308                 atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
4309                 atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
4310                 atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
4311                 atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
4312                 atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
4313                 atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
4314                 atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));
4315                 if(ppFlags)
4316                         atom.writeInt(PCP_CHAN_INFO_PPFLAGS,ppFlags); //JP-MOD
4317
4318 }
4319 // -----------------------------------
4320 void ChanInfo::writeTrackAtoms(AtomStream &atom)
4321 {
4322         atom.writeParent(PCP_CHAN_TRACK,4);
4323                 atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
4324                 atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
4325                 atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
4326                 atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
4327 }
4328
4329
4330 // -----------------------------------
4331 XML::Node *ChanInfo::createChannelXML()
4332 {
4333         char idStr[64];
4334
4335         String nameUNI = name;
4336         nameUNI.convertTo(String::T_UNICODESAFE);
4337
4338         String urlUNI = url;
4339         urlUNI.convertTo(String::T_UNICODESAFE);
4340
4341         String genreUNI = genre;
4342         genreUNI.convertTo(String::T_UNICODESAFE);
4343
4344         String descUNI = desc;
4345         descUNI.convertTo(String::T_UNICODESAFE);
4346
4347         String commentUNI;
4348         commentUNI = comment;
4349         commentUNI.convertTo(String::T_UNICODESAFE);
4350
4351
4352         id.toStr(idStr);
4353
4354
4355         return new XML::Node("channel name=\"%s\" id=\"%s\" bitrate=\"%d\" type=\"%s\" genre=\"%s\" desc=\"%s\" url=\"%s\" uptime=\"%d\" comment=\"%s\" skips=\"%d\" age=\"%d\" bcflags=\"%d\"",
4356                 nameUNI.cstr(),
4357                 idStr,
4358                 bitrate,
4359                 getTypeStr(contentType),
4360                 genreUNI.cstr(),
4361                 descUNI.cstr(),
4362                 urlUNI.cstr(),
4363                 getUptime(),
4364                 commentUNI.cstr(),
4365                 numSkips,
4366                 getAge(),
4367                 bcID.getFlags()
4368                 );      
4369 }
4370
4371 // -----------------------------------
4372 XML::Node *ChanInfo::createQueryXML()
4373 {
4374         char buf[512];
4375         char idStr[64];
4376
4377
4378         String nameHTML = name;
4379         nameHTML.convertTo(String::T_HTML);
4380         String genreHTML = genre;
4381         genreHTML.convertTo(String::T_HTML);
4382
4383         buf[0]=0;
4384         if (!nameHTML.isEmpty())
4385         {
4386                 strcat(buf," name=\"");
4387                 strcat(buf,nameHTML.cstr());
4388                 strcat(buf,"\"");
4389         }
4390
4391         if (!genreHTML.isEmpty())
4392         {
4393                 strcat(buf," genre=\"");
4394                 strcat(buf,genreHTML.cstr());
4395                 strcat(buf,"\"");
4396         }
4397
4398         if (id.isSet())
4399         {
4400                 id.toStr(idStr);
4401                 strcat(buf," id=\"");
4402                 strcat(buf,idStr);
4403                 strcat(buf,"\"");
4404         }
4405                 
4406
4407         return new XML::Node("channel %s",buf);
4408 }
4409
4410 // -----------------------------------
4411 XML::Node *ChanInfo::createRelayChannelXML()
4412 {
4413         char idStr[64];
4414
4415         id.toStr(idStr);
4416
4417
4418         return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
4419                 idStr,
4420                 getUptime(),
4421                 numSkips,
4422                 getAge()
4423                 );      
4424 }// -----------------------------------
4425 XML::Node *ChanInfo::createTrackXML()
4426 {
4427         String titleUNI = track.title;
4428         titleUNI.convertTo(String::T_UNICODESAFE);
4429
4430         String artistUNI = track.artist;
4431         artistUNI.convertTo(String::T_UNICODESAFE);
4432
4433         String albumUNI = track.album;
4434         albumUNI.convertTo(String::T_UNICODESAFE);
4435
4436         String genreUNI = track.genre;
4437         genreUNI.convertTo(String::T_UNICODESAFE);
4438
4439         String contactUNI = track.contact;
4440         contactUNI.convertTo(String::T_UNICODESAFE);
4441         
4442
4443
4444         return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
4445                 titleUNI.cstr(),
4446                 artistUNI.cstr(),
4447                 albumUNI.cstr(),
4448                 genreUNI.cstr(),
4449                 contactUNI.cstr()
4450                 );
4451 }
4452
4453 // -----------------------------------
4454 void ChanInfo::init(XML::Node *n)
4455 {
4456         init();
4457
4458         updateFromXML(n);
4459 }
4460 // -----------------------------------
4461 void ChanInfo::updateFromXML(XML::Node *n)
4462 {
4463         String typeStr,idStr;
4464
4465         readXMLString(name,n,"name");
4466         readXMLString(genre,n,"genre");
4467         readXMLString(url,n,"url");
4468         readXMLString(desc,n,"desc");
4469
4470
4471         int br = n->findAttrInt("bitrate");
4472         if (br)
4473                 bitrate = br;
4474
4475         { //JP-MOD
4476                 ppFlags = ServMgr::bcstNone;
4477
4478                 if (n->findAttrInt("bcstClap"))
4479                         ppFlags |= ServMgr::bcstClap;
4480         }
4481
4482         readXMLString(typeStr,n,"type");
4483         if (!typeStr.isEmpty())
4484                 contentType = getTypeFromStr(typeStr.cstr());
4485
4486
4487         readXMLString(idStr,n,"id");
4488         if (!idStr.isEmpty())
4489                 id.fromStr(idStr.cstr());
4490
4491         readXMLString(comment,n,"comment");
4492
4493         XML::Node *tn = n->findNode("track");
4494         if (tn)
4495                 readTrackXML(tn);
4496
4497 }
4498
4499 // -----------------------------------
4500 void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
4501 {
4502         init();
4503
4504         name.set(n);
4505         bitrate = br;
4506         contentType = tp;
4507         id = cid;
4508 }
4509
4510 // -----------------------------------
4511 void ChanInfo::init(const char *fn)
4512 {
4513         init();
4514
4515         if (fn)
4516                 name.set(fn);
4517 }
4518 // -----------------------------------
4519 void PlayList::readASX(Stream &in)
4520 {
4521         LOG_DEBUG("Reading ASX");
4522         XML xml;
4523
4524         try
4525         {
4526                 xml.read(in);
4527         }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
4528
4529         if (xml.root)
4530         {
4531                 XML::Node *n = xml.root->child;
4532                 while (n)
4533                 {
4534                         if (stricmp("entry",n->getName())==0)
4535                         {
4536                                 XML::Node *rf = n->findNode("ref");
4537                                 if (rf)
4538                                 {
4539                                         char *hr = rf->findAttr("href");
4540                                         if (hr)
4541                                         {
4542                                                 addURL(hr,"","");
4543                                                 //LOG("asx url %s",hr);
4544                                         }
4545
4546                                 }
4547                         }
4548                         n=n->sibling;
4549                 }
4550         }
4551 }
4552 // -----------------------------------
4553 void PlayList::readSCPLS(Stream &in)
4554 {
4555         char tmp[256];
4556         while (in.readLine(tmp,sizeof(tmp)))
4557         {
4558                 if (strnicmp(tmp,"file",4)==0)
4559                 {
4560                         char *p = strstr(tmp,"=");
4561                         if (p)
4562                                 addURL(p+1,"","");
4563                 }
4564         }
4565 }
4566 // -----------------------------------
4567 void PlayList::readPLS(Stream &in)
4568 {
4569         char tmp[256];
4570         while (in.readLine(tmp,sizeof(tmp)))
4571         {
4572                 if (tmp[0] != '#')
4573                         addURL(tmp,"","");
4574         }
4575 }
4576 // -----------------------------------
4577 void PlayList::writeSCPLS(Stream &out)
4578 {
4579         out.writeLine("[playlist]");
4580         out.writeLine("");
4581         out.writeLineF("NumberOfEntries=%d",numURLs);
4582
4583         for(int i=0; i<numURLs; i++)
4584         {
4585                 out.writeLineF("File%d=%s",i+1,urls[i].cstr());
4586                 out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
4587                 out.writeLineF("Length%d=-1",i+1);
4588         }
4589         out.writeLine("Version=2");
4590 }
4591 // -----------------------------------
4592 void PlayList::writePLS(Stream &out)
4593 {
4594         for(int i=0; i<numURLs; i++)
4595                 out.writeLineF("%s",urls[i].cstr());
4596 }
4597 // -----------------------------------
4598 void PlayList::writeRAM(Stream &out)
4599 {
4600         for(int i=0; i<numURLs; i++)
4601                 out.writeLineF("%s",urls[i].cstr());
4602 }
4603
4604 // -----------------------------------
4605 #define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
4606 static void SJIStoSJISSAFE(char *string, size_t size)
4607 {
4608         size_t pos;
4609         for(pos = 0;
4610                 (string[pos] != '\0') && (pos < size);
4611                 ++pos)
4612         {
4613                 if(isHTMLSPECIAL(string[pos]))
4614                         string[pos] = ' ';
4615         }
4616 }
4617
4618 // -----------------------------------
4619 static void WriteASXInfo(Stream &out, String &title, String &contacturl, String::TYPE tEncoding = String::T_UNICODESAFE) //JP-MOD
4620 {
4621         if(!title.isEmpty())
4622         {
4623                 String titleEncode;
4624                 titleEncode = title;
4625                 titleEncode.convertTo(tEncoding);
4626                 if(tEncoding == String::T_SJIS)
4627                         SJIStoSJISSAFE(titleEncode.cstr(), String::MAX_LEN);
4628                 out.writeLineF("<TITLE>%s</TITLE>", titleEncode.cstr());
4629         }
4630
4631         if(!contacturl.isEmpty())
4632         {
4633                 String contacturlEncode;
4634                 contacturlEncode = contacturl;
4635                 contacturlEncode.convertTo(tEncoding);
4636                 if(tEncoding == String::T_SJIS)
4637                         SJIStoSJISSAFE(contacturlEncode.cstr(), String::MAX_LEN);
4638                 out.writeLineF("<MOREINFO HREF = \"%s\" />", contacturlEncode.cstr());
4639         }
4640 }
4641
4642 // -----------------------------------
4643 void PlayList::writeASX(Stream &out)
4644 {
4645         out.writeLine("<ASX Version=\"3.0\">");
4646
4647         String::TYPE tEncoding = String::T_SJIS;
4648         if(servMgr->asxDetailedMode == 2)
4649         {
4650                 out.writeLine("<PARAM NAME = \"Encoding\" VALUE = \"utf-8\" />"); //JP-MOD Memo: UTF-8 cannot be used in some recording software.
4651                 tEncoding = String::T_UNICODESAFE;
4652         }
4653
4654         if(servMgr->asxDetailedMode)
4655                 WriteASXInfo(out, titles[0], contacturls[0], tEncoding); //JP-MOD
4656
4657         for(int i=0; i<numURLs; i++)
4658         {
4659                 out.writeLine("<ENTRY>");
4660                 if(servMgr->asxDetailedMode)
4661                         WriteASXInfo(out, titles[i], contacturls[i], tEncoding); //JP-MOD
4662                 out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
4663                 out.writeLine("</ENTRY>");
4664         }
4665         out.writeLine("</ASX>");
4666 }
4667
4668
4669 // -----------------------------------
4670 void PlayList::addChannel(const char *path, ChanInfo &info)
4671 {
4672         String url;
4673
4674         char idStr[64];
4675
4676         info.id.toStr(idStr);
4677         char *nid = info.id.isSet()?idStr:info.name.cstr();
4678
4679         sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
4680         addURL(url.cstr(),info.name,info.url);
4681 }
4682
4683 // -----------------------------------
4684 void ChanHitSearch::init()
4685 {
4686         matchHost.init();
4687         waitDelay = 0;
4688         useFirewalled = false;
4689         trackersOnly = false;
4690         useBusyRelays = true;
4691         useBusyControls = true;
4692         excludeID.clear();
4693         numResults = 0;
4694
4695         //seed = sys->getTime();
4696         //srand(seed);
4697 }
4698
4699 int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
4700 {
4701         int cnt = 0;
4702         int loop = 1;
4703         int index = 0;
4704         int prob;
4705         int rnd;
4706         static int base = 0x400;
4707         ChanHit tmpHit[MAX_RESULTS];
4708         static WLock seqLock;
4709         static unsigned int riSequence = 0;
4710
4711         //srand(seed);
4712         //seed += 11;
4713
4714         unsigned int seq;
4715         seqLock.on();
4716         seq = riSequence++;
4717         riSequence &= 0xffffff;
4718         seqLock.off();
4719
4720         Servent *s = servMgr->servents;
4721         while (s) {
4722                 if (s->serventHit.rhost[0].port && s->type == Servent::T_RELAY
4723                         && s->chanID.isSame(chl->info.id)) {
4724                                 int i = index % MAX_RESULTS;
4725                                 if (index < MAX_RESULTS
4726                                         || tmpHit[i].lastSendSeq > s->serventHit.lastSendSeq) {
4727                                                 s->serventHit.lastSendSeq = seq;
4728                                                 tmpHit[i] = s->serventHit;
4729                                                 tmpHit[i].host = s->serventHit.rhost[0];
4730                                                 index++;
4731                                 }
4732                 }
4733                 s = s->next;
4734         }
4735
4736         ChanHit *hit = chl->hit;
4737
4738         while(hit){
4739                 if (hit->host.ip && !hit->dead){
4740                         if (
4741                                 (!exID.isSame(hit->sessionID))
4742 //                      &&      (hit->relay)
4743                         &&      (!hit->tracker)
4744                         &&      (!hit->firewalled)
4745                         &&      (hit->numHops != 0)
4746                         ){
4747                                 if (    (hit->rhost[0].ip == host1.ip)
4748                                         &&      hit->rhost[1].isValid()
4749                                         &&      (host2.ip != hit->rhost[1].ip)
4750                                 ){
4751                                         best[0] = *hit;
4752                                         best[0].host = hit->rhost[1];
4753                                         index++;
4754                                 }
4755                                 if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
4756                                         best[0] = *hit;
4757                                         best[0].host = hit->rhost[1];
4758                                         index++;
4759                                 }
4760
4761                                 loop = (index / MAX_RESULTS) + 1;
4762                                 //prob = (float)1 / (float)loop;
4763                                 prob = base / loop;
4764                                 //rnd = (float)rand() / (float)RAND_MAX;
4765                                 rnd = rand() % base;
4766                                 if (hit->numHops == 1){
4767 #if 0
4768                                         if (tmpHit[index % MAX_RESULTS].numHops == 1){
4769                                                 if (rnd < prob){
4770                                                         tmpHit[index % MAX_RESULTS] = *hit;
4771                                                         tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4772                                                         index++;
4773                                                 }
4774                                         } else {
4775                                                 tmpHit[index % MAX_RESULTS] = *hit;
4776                                                 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4777                                                 index++;
4778                                         }
4779 #endif
4780                                 } else {
4781                                         if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob) || rnd == 0){
4782                                                 tmpHit[index % MAX_RESULTS] = *hit;
4783                                                 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4784                                                 index++;
4785                                         }
4786                                 }
4787
4788 //                              char tmp[50];
4789 //                              hit->host.toStr(tmp);
4790 //                              LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
4791                         }
4792                 }
4793                 hit = hit->next;
4794         }
4795         
4796         if (index > MAX_RESULTS){
4797                 cnt = MAX_RESULTS;
4798         } else {
4799                 cnt = index;
4800         }
4801
4802 /*      int use[MAX_RESULTS];
4803         memset(use, 0, sizeof(use));
4804         int i;
4805         for (i = 0; i < cnt; i++){
4806                 use[i] = -1;
4807         }
4808         int r;
4809         for (i = 0; i < cnt; i++){
4810                 do {
4811                         r = rand();
4812 //                      LOG_DEBUG("%d",r);
4813                         r = r % cnt;
4814                         if (use[r] == -1){
4815                                 use[r] = i;
4816                                 break;
4817                         }
4818                 } while(1);
4819         }
4820         for (i = 0; i < cnt; i++){
4821 //              LOG_DEBUG("%d", use[i]);
4822                 best[use[i]] = tmpHit[i];
4823         }*/
4824
4825         int use[MAX_RESULTS];
4826         int i;
4827         for (i = 0; i < cnt; i++) {
4828                 use[i] = (i + seq) % cnt;
4829         }
4830
4831         for (i = 0; i < cnt; i++){
4832 //              LOG_DEBUG("%d", use[i]);
4833                 best[use[i]] = tmpHit[i];
4834         }
4835 //      for (i = 0; i < cnt; i++){
4836 //              char tmp[50];
4837 //              best[i].host.toStr(tmp);
4838 //              LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);
4839 //      }
4840
4841         return cnt;
4842 }