OSDN Git Service

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