OSDN Git Service

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