OSDN Git Service

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