OSDN Git Service

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