OSDN Git Service

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