1 // ------------------------------------------------
6 // Channel streaming classes. These do the actual
7 // streaming of media between clients.
9 // (c) 2002 peercast.org
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.
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 // ------------------------------------------------
48 #include "chkMemoryLeak.h"
49 #define DEBUG_NEW new(__FILE__, __LINE__)
53 // -----------------------------------
54 char *Channel::srcTypes[]=
62 // -----------------------------------
63 char *Channel::statusMsgs[]=
82 bool isIndexTxt(ChanInfo *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))
101 bool isIndexTxt(Channel *ch)
103 if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
109 int numMaxRelaysIndexTxt(Channel *ch)
111 return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
114 int canStreamIndexTxt(Channel *ch)
118 //
\8e©
\95ª
\82ª
\94z
\90M
\82µ
\82Ä
\82¢
\82é
\8fê
\8d\87\82Í
\8aÖ
\8cW
\82È
\82¢
119 if(!ch || ch->isBroadcasting())
122 ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
130 // -----------------------------------
131 void readXMLString(String &str, XML::Node *n, const char *arg)
134 p = n->findAttr(arg);
137 str.set(p,String::T_HTML);
138 str.convertTo(String::T_ASCII);
143 // -----------------------------------------------------------------------------
144 // Initialise the channel to its default settings of unallocated and reset.
145 // -----------------------------------------------------------------------------
146 Channel::Channel() : maxRelays(0)
150 channel_id = channel_count++;
152 // -----------------------------------------------------------------------------
153 void Channel::endThread(bool flg)
177 chanMgr->channellock.on();
178 chanMgr->deleteChannel(this);
179 chanMgr->channellock.off();
181 sys->endThread(&thread);
184 // -----------------------------------------------------------------------------
185 void Channel::resetPlayTime()
187 info.lastPlayStart = sys->getTime();
189 // -----------------------------------------------------------------------------
190 void Channel::setStatus(STATUS s)
194 bool wasPlaying = isPlaying();
200 info.status = ChanInfo::S_PLAY;
205 info.lastPlayEnd = sys->getTime();
206 info.status = ChanInfo::S_UNKNOWN;
209 if (isBroadcasting())
211 ChanHitList *chl = chanMgr->findHitListByID(info.id);
213 chanMgr->addHitList(info);
216 peercastApp->channelUpdate(&info);
221 // -----------------------------------------------------------------------------
222 // Reset channel and make it available
223 // -----------------------------------------------------------------------------
224 void Channel::reset()
237 stayConnected = false;
238 stealth = false; //JP-MOD
239 overrideMaxRelaysPerChannel = -1; //JP-MOD
240 bClap = false; //JP-MOD
244 skipCount = 0; //JP-EX
254 rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
266 lastTrackerUpdate = 0;
281 // -----------------------------------
282 void Channel::newPacket(ChanPacket &pack)
284 if (pack.type != ChanPacket::T_PCP)
286 rawData.writePacket(pack,true);
291 // -----------------------------------
292 bool Channel::checkIdle()
294 return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
297 // -----------------------------------
298 bool Channel::isFull()
300 // for PCRaw (relay) start.
303 int ret = canStreamIndexTxt(this);
310 // for PCRaw (relay) end.
312 //
\83`
\83\83\83\93\83l
\83\8b\8cÅ
\97L
\82Ì
\83\8a\83\8c\81[
\8fã
\8cÀ
\90Ý
\92è
\82ª
\82 \82é
\82©
315 return localRelays() >= maxRelays;
318 return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
321 // -----------------------------------
322 int Channel::localRelays()
324 return servMgr->numStreams(info.id,Servent::T_RELAY,true);
326 // -----------------------------------
327 int Channel::localListeners()
329 return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
332 // -----------------------------------
333 int Channel::totalRelays()
336 ChanHitList *chl = chanMgr->findHitListByID(info.id);
338 tot += chl->numHits();
341 // -----------------------------------
342 int Channel::totalListeners()
344 int tot = localListeners();
345 ChanHitList *chl = chanMgr->findHitListByID(info.id);
347 tot += chl->numListeners();
351 // -----------------------------------
352 int Channel::totalClaps() //JP-MOD
354 ChanHitList *chl = chanMgr->findHitListByID(info.id);
355 return chl ? chl->numClaps() : 0;
358 // -----------------------------------
359 void Channel::startGet()
361 srcType = SRC_PEERCAST;
363 info.srcProtocol = ChanInfo::SP_PCP;
366 sourceData = new PeercastSource();
370 // -----------------------------------
371 void Channel::startURL(const char *u)
377 stayConnected = true;
381 sourceData = new URLSource(u);
386 // -----------------------------------
387 void Channel::startStream()
390 thread.func = stream;
391 if (!sys->startThread(&thread))
395 // -----------------------------------
396 void Channel::sleepUntil(double time)
398 double sleepTime = time - (sys->getDTime()-startTime);
400 // LOG("sleep %g",sleepTime);
403 if (sleepTime > 60) sleepTime = 60;
405 double sleepMS = sleepTime*1000;
407 sys->sleep((int)sleepMS);
412 // -----------------------------------
413 void Channel::checkReadDelay(unsigned int len)
417 unsigned int time = (len*1000)/((info.bitrate*1024)/8);
425 // -----------------------------------
426 THREAD_PROC Channel::stream(ThreadInfo *thread)
430 Channel *ch = (Channel *)thread->data;
432 LOG_CHANNEL("Channel started");
434 while (thread->active && !peercastInst->isQuitting && !thread->finish)
436 ChanHitList *chl = chanMgr->findHitList(ch->info);
438 chanMgr->addHitList(ch->info);
440 ch->sourceData->stream(ch);
442 LOG_CHANNEL("Channel stopped");
445 if (!ch->stayConnected)
447 thread->active = false;
451 if (!ch->info.lastPlayEnd)
452 ch->info.lastPlayEnd = sys->getTime();
454 unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
456 LOG_DEBUG("Channel sleeping for %d seconds",diff);
457 for(unsigned int i=0; i<diff; i++)
459 if (ch->info.lastPlayEnd == 0) // reconnected
461 if (!thread->active || peercastInst->isQuitting){
462 thread->active = false;
470 LOG_DEBUG("thread.active = %d, thread.finish = %d",
471 ch->thread.active, ch->thread.finish);
473 if (!thread->finish){
474 ch->endThread(false);
477 ch->finthread = new ThreadInfo();
478 ch->finthread->func = waitFinish;
479 ch->finthread->data = ch;
480 sys->startThread(ch->finthread);
488 // -----------------------------------
489 THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
491 Channel *ch = (Channel*)thread->data;
492 LOG_DEBUG("Wait channel finish");
494 while(!(ch->thread.finish) && !thread->finish){
498 if (ch->thread.finish){
499 LOG_DEBUG("channel finish");
502 LOG_DEBUG("channel restart");
509 // -----------------------------------
510 bool Channel::acceptGIV(ClientSocket *givSock)
519 // -----------------------------------
520 void Channel::connectFetch()
522 sock = sys->createSocket();
525 throw StreamException("Can`t create socket");
527 if (sourceHost.tracker || sourceHost.yp)
529 sock->setReadTimeout(30000);
530 sock->setWriteTimeout(30000);
531 LOG_CHANNEL("Channel using longer timeouts");
533 sock->setReadTimeout(5000);
534 sock->setWriteTimeout(5000);
537 sock->open(sourceHost.host);
542 // -----------------------------------
543 int Channel::handshakeFetch()
546 info.id.toStr(idStr);
549 servMgr->sessionID.toStr(sidStr);
551 sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
552 sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
553 sock->writeLineF("%s %d",PCX_HS_PCP,1);
554 sock->writeLineF("%s %d",PCX_HS_PORT,servMgr->serverHost.port);
560 int r = http.readResponse();
562 LOG_CHANNEL("Got response: %d",r);
564 while (http.nextHeader())
566 char *arg = http.getArgStr();
570 if (http.isHeader(PCX_HS_POS))
571 streamPos = atoi(arg);
573 Servent::readICYHeader(http, info, NULL);
575 LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
578 if ((r != 200) && (r != 503))
581 if (!servMgr->keepDownstreams) {
582 if (rawData.getLatestPos() > streamPos)
586 AtomStream atom(*sock);
590 Host rhost = sock->host;
592 if (info.srcProtocol == ChanInfo::SP_PCP)
594 // don`t need PCP_CONNECT here
595 Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
598 if (r == 503) return 503;
603 // -----------------------------------
604 void PeercastSource::stream(Channel *ch)
608 bool next_yp = false;
609 bool tracker_check = (ch->trackerHit.host.ip != 0);
612 ch->lastStopTime = 0;
615 while (ch->thread.active)
617 ch->skipCount = 0; //JP-EX
618 ch->lastSkipTime = 0;
620 ChanHitList *chl = NULL;
622 ch->sourceHost.init();
624 if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
625 ch->lastIdleTime = sys->getTime();
626 ch->setStatus(Channel::S_IDLE);
628 ch->lastSkipTime = 0;
632 if (!servMgr->keepDownstreams && !ch->bumped) {
633 ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
636 ch->setStatus(Channel::S_SEARCHING);
637 LOG_CHANNEL("Channel searching for hit..");
643 ch->sock = ch->pushSock;
645 ch->sourceHost.host = ch->sock->host;
649 chanMgr->hitlistlock.on();
651 chl = chanMgr->findHitList(ch->info);
657 if (!ch->sourceHost.host.ip){
659 chs.matchHost = servMgr->serverHost;
660 chs.waitDelay = MIN_RELAY_RETRY;
661 chs.excludeID = servMgr->sessionID;
662 if (chl->pickSourceHits(chs)){
663 ch->sourceHost = chs.best[0];
664 LOG_DEBUG("use local hit");
668 // else find global hit
669 if (!ch->sourceHost.host.ip)
672 chs.waitDelay = MIN_RELAY_RETRY;
673 chs.excludeID = servMgr->sessionID;
674 if (chl->pickSourceHits(chs)){
675 ch->sourceHost = chs.best[0];
676 LOG_DEBUG("use global hit");
681 // else find local tracker
682 if (!ch->sourceHost.host.ip)
685 chs.matchHost = servMgr->serverHost;
686 chs.waitDelay = MIN_TRACKER_RETRY;
687 chs.excludeID = servMgr->sessionID;
688 chs.trackersOnly = true;
689 if (chl->pickSourceHits(chs)){
690 ch->sourceHost = chs.best[0];
691 LOG_DEBUG("use local tracker");
695 // else find global tracker
696 if (!ch->sourceHost.host.ip)
699 chs.waitDelay = MIN_TRACKER_RETRY;
700 chs.excludeID = servMgr->sessionID;
701 chs.trackersOnly = true;
702 if (chl->pickSourceHits(chs)){
703 ch->sourceHost = chs.best[0];
704 tracker_check = true;
705 ch->trackerHit = chs.best[0];
706 LOG_DEBUG("use global tracker");
711 unsigned int ctime = sys->getTime();
712 if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
713 if (ch->trackerHit.lastContact + 30 < ctime){
714 ch->sourceHost = ch->trackerHit;
715 ch->trackerHit.lastContact = ctime;
716 LOG_DEBUG("use saved tracker");
721 chanMgr->hitlistlock.off();
723 if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
724 ch->lastStopTime = 0;
725 LOG_DEBUG("------------ disconnect all downstreams");
727 MemoryStream mem(pack.data,sizeof(pack.data));
728 AtomStream atom(mem);
729 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
731 pack.type = ChanPacket::T_PCP;
734 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
736 chanMgr->hitlistlock.on();
737 ChanHitList *hl = chanMgr->findHitList(ch->info);
739 hl->clearHits(false);
741 chanMgr->hitlistlock.off();
744 // no trackers found so contact YP
745 if (!tracker_check && !ch->sourceHost.host.ip)
748 if (servMgr->rootHost.isEmpty())
754 if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
757 unsigned int ctime=sys->getTime();
758 if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
760 ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
761 ch->sourceHost.yp = true;
762 chanMgr->lastYPConnect=ctime;
770 // no trackers found so contact YP2
771 if (!tracker_check && !ch->sourceHost.host.ip)
774 if (servMgr->rootHost2.isEmpty())
777 if (numYPTries2 >= 3)
780 unsigned int ctime=sys->getTime();
781 if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
783 ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
784 ch->sourceHost.yp = true;
785 chanMgr->lastYPConnect2=ctime;
792 if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
796 }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
798 if (!ch->sourceHost.host.ip)
800 LOG_ERROR("Channel giving up");
801 ch->setStatus(Channel::S_ERROR);
805 if (ch->sourceHost.yp)
807 LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
810 LOG_CHANNEL("Channel found hit");
815 if (ch->sourceHost.host.ip)
817 bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
820 //if (ch->sourceHost.tracker)
821 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
824 ch->sourceHost.host.toStr(ipstr);
827 if (ch->sourceHost.tracker)
829 else if (ch->sourceHost.yp)
836 ch->setStatus(Channel::S_CONNECTING);
837 ch->sourceHost.lastContact = sys->getTime();
841 LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
845 error = ch->handshakeFetch();
851 throw StreamException("Handshake error");
852 if (ch->sourceHost.tracker) connFailCnt = 0;
854 if (servMgr->autoMaxRelaySetting) //JP-EX
856 double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
857 if ((unsigned int)setMaxRelays == 0)
858 servMgr->maxRelays = 1;
859 else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
860 servMgr->maxRelays = servMgr->autoMaxRelaySetting;
862 servMgr->maxRelays = (unsigned int)setMaxRelays;
865 ch->sourceStream = ch->createSource();
867 error = ch->readStream(*ch->sock,ch->sourceStream);
869 throw StreamException("Stream error");
871 error = 0; // no errors, closing normally.
872 // ch->setStatus(Channel::S_CLOSING);
873 ch->setStatus(Channel::S_IDLE);
875 LOG_CHANNEL("Channel closed normally");
876 }catch(StreamException &e)
878 ch->setStatus(Channel::S_ERROR);
879 LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
880 if (!servMgr->allowConnectPCST) //JP-EX
882 if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
883 ch->thread.active = false;
885 //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
886 if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
887 chanMgr->deadHit(ch->sourceHost);
888 if (ch->sourceHost.tracker && error == -1) {
889 LOG_ERROR("can't connect to tracker");
894 unsigned int ctime = sys->getTime();
895 if (ch->rawData.lastWriteTime) {
896 ch->lastStopTime = ch->rawData.lastWriteTime;
897 if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
898 ch->lastStopTime = ctime;
901 if (tracker_check && ch->sourceHost.tracker)
902 ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
904 // broadcast source host
905 if (!error && ch->sourceHost.host.ip) { // if closed normally
907 MemoryStream mem(pack.data,sizeof(pack.data));
908 AtomStream atom(mem);
909 ch->sourceHost.writeAtoms(atom, ch->info.id);
911 pack.type = ChanPacket::T_PCP;
914 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
915 LOG_DEBUG("stream: broadcast sourceHost");
918 // broadcast quit to any connected downstream servents
919 if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
921 MemoryStream mem(pack.data,sizeof(pack.data));
922 AtomStream atom(mem);
923 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
925 pack.type = ChanPacket::T_PCP;
928 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
929 LOG_DEBUG("------------ broadcast quit to all downstreams");
931 chanMgr->hitlistlock.on();
932 ChanHitList *hl = chanMgr->findHitList(ch->info);
934 hl->clearHits(false);
936 chanMgr->hitlistlock.off();
940 if (ch->sourceStream)
946 ch->sourceStream->updateStatus(ch);
947 ch->sourceStream->flush(*ch->sock);
949 }catch(StreamException &)
951 ChannelStream *cs = ch->sourceStream;
952 ch->sourceStream = NULL;
966 LOG_ERROR("Channel not found");
968 if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
969 chanMgr->hitlistlock.on();
970 ChanHitList *hl = chanMgr->findHitList(ch->info);
974 chanMgr->hitlistlock.off();
976 if(!isIndexTxt(&ch->info)) // for PCRaw (popup)
977 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
985 ch->lastIdleTime = sys->getTime();
986 ch->setStatus(Channel::S_IDLE);
987 ch->skipCount = 0; //JP-EX
988 ch->lastSkipTime = 0;
989 while ((ch->checkIdle()) && (ch->thread.active))
998 // -----------------------------------
999 void Channel::startICY(ClientSocket *cs, SRC_TYPE st)
1003 cs->setReadTimeout(0); // stay connected even when theres no data coming through
1005 info.srcProtocol = ChanInfo::SP_HTTP;
1007 streamIndex = ++chanMgr->icyIndex;
1009 sourceData = new ICYSource();
1013 // -----------------------------------
1014 static char *nextMetaPart(char *str,char delim)
1027 // -----------------------------------
1028 static void copyStr(char *to,char *from,int max)
1031 while ((c=*from++) && (--max))
1038 // -----------------------------------
1039 void Channel::processMp3Metadata(char *str)
1041 ChanInfo newInfo = info;
1046 char *arg = nextMetaPart(cmd,'=');
1050 char *next = nextMetaPart(arg,';');
1052 if (strcmp(cmd,"StreamTitle")==0)
1054 newInfo.track.title.setUnquote(arg,String::T_ASCII);
1055 newInfo.track.title.convertTo(String::T_UNICODE);
1057 }else if (strcmp(cmd,"StreamUrl")==0)
1059 newInfo.track.contact.setUnquote(arg,String::T_ASCII);
1060 newInfo.track.contact.convertTo(String::T_UNICODE);
1067 updateInfo(newInfo);
1070 // -----------------------------------
1071 XML::Node *ChanHit::createXML()
1077 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\"",
1089 sys->getTime()-time,
1095 // -----------------------------------
1096 XML::Node *ChanHitList::createXML(bool addHits)
1098 XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
1105 sys->getTime()-newestHit()
1114 hn->add(h->createXML());
1122 // -----------------------------------
1123 XML::Node *Channel::createRelayXML(bool showStat)
1126 ststr = getStatusStr();
1128 if ((status == S_RECEIVING) || (status == S_BROADCASTING))
1131 ChanHitList *chl = chanMgr->findHitList(info);
1133 return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
1136 (chl!=NULL)?chl->numHits():0,
1141 // -----------------------------------
1142 void ChanMeta::fromXML(XML &xml)
1144 MemoryStream tout(data,MAX_DATALEN);
1149 // -----------------------------------
1150 void ChanMeta::fromMem(void *p, int l)
1155 // -----------------------------------
1156 void ChanMeta::addMem(void *p, int l)
1158 if ((len+l) <= MAX_DATALEN)
1160 memcpy(data+len,p,l);
1164 // -----------------------------------
1165 void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
1167 unsigned int ctime = sys->getTime();
1169 if (((ctime-lastTrackerUpdate) > 30) || (force))
1173 MemoryStream mem(pack.data,sizeof(pack));
1175 AtomStream atom(mem);
1179 ChanHitList *chl = chanMgr->findHitListByID(info.id);
1181 throw StreamException("Broadcast channel has no hitlist");
1183 int numListeners = stealth ? -1 : totalListeners(); //JP-MOD
\83\8a\83X
\83i
\81[
\90\94\89B
\95Á
\8b@
\94\
1184 int numRelays = stealth ? -1 : totalRelays(); //JP-MOD
\83\8a\83\8c\81[
\90\94\89B
\95Á
\8b@
\94\
1186 unsigned int oldp = rawData.getOldestPos();
1187 unsigned int newp = rawData.getLatestPos();
1189 hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
1192 if (version_ex == 0)
1194 atom.writeParent(PCP_BCST,8);
1197 atom.writeParent(PCP_BCST,10);
1199 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
1200 atom.writeChar(PCP_BCST_HOPS,0);
1201 atom.writeChar(PCP_BCST_TTL,11);
1202 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1203 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1204 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1208 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1209 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1211 atom.writeParent(PCP_CHAN,4);
1212 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1213 atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
1214 info.writeInfoAtoms(atom);
1215 info.writeTrackAtoms(atom);
1216 hit.writeAtoms(atom,info.id);
1220 pack.type = ChanPacket::T_PCP;
1224 int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
1228 LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
1229 lastTrackerUpdate = ctime;
1234 // -----------------------------------
1235 bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
1238 && (!cid.isSet() || info.id.isSame(cid))
1239 && (!sid.isSet() || !remoteID.isSame(sid))
1242 return sourceStream->sendPacket(pack,did);
1247 // -----------------------------------
1248 void Channel::updateInfo(ChanInfo &newInfo)
1250 if (info.update(newInfo))
1252 if (isBroadcasting())
1254 unsigned int ctime = sys->getTime();
1255 if ((ctime-lastMetaUpdate) > 30)
1257 lastMetaUpdate = ctime;
1261 MemoryStream mem(pack.data,sizeof(pack));
1263 AtomStream atom(mem);
1265 if (version_ex == 0)
1267 atom.writeParent(PCP_BCST,8);
1270 atom.writeParent(PCP_BCST,10);
1272 atom.writeChar(PCP_BCST_HOPS,0);
1273 atom.writeChar(PCP_BCST_TTL,7);
1274 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
1275 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1276 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1277 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1280 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1281 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1283 atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
1284 atom.writeParent(PCP_CHAN,3);
1285 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1286 info.writeInfoAtoms(atom);
1287 info.writeTrackAtoms(atom);
1290 pack.type = ChanPacket::T_PCP;
1293 servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
1295 broadcastTrackerUpdate(noID);
1299 ChanHitList *chl = chanMgr->findHitList(info);
1303 peercastApp->channelUpdate(&info);
1308 // -----------------------------------
1309 ChannelStream *Channel::createSource()
1311 // if (servMgr->relayBroadcast)
1312 // chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
1315 ChannelStream *source=NULL;
1317 if (info.srcProtocol == ChanInfo::SP_PEERCAST)
1319 LOG_CHANNEL("Channel is Peercast");
1320 if (servMgr->allowConnectPCST) //JP-EX
1321 source = new PeercastStream();
1323 throw StreamException("Channel is not allowed");
1325 else if (info.srcProtocol == ChanInfo::SP_PCP)
1327 LOG_CHANNEL("Channel is PCP");
1328 PCPStream *pcp = new PCPStream(remoteID);
1331 else if (info.srcProtocol == ChanInfo::SP_MMS)
1333 LOG_CHANNEL("Channel is MMS");
1334 source = new MMSStream();
1337 switch(info.contentType)
1339 case ChanInfo::T_MP3:
1340 LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
1341 source = new MP3Stream();
1343 case ChanInfo::T_NSV:
1344 LOG_CHANNEL("Channel is NSV");
1345 source = new NSVStream();
1347 case ChanInfo::T_WMA:
1348 case ChanInfo::T_WMV:
1349 throw StreamException("Channel is WMA/WMV - but not MMS");
1351 case ChanInfo::T_OGG:
1352 case ChanInfo::T_OGM:
1353 LOG_CHANNEL("Channel is OGG");
1354 source = new OGGStream();
1357 LOG_CHANNEL("Channel is Raw");
1358 source = new RawStream();
1363 source->parent = this;
1367 // ------------------------------------------
1368 void ChannelStream::updateStatus(Channel *ch)
1371 if (getStatus(ch,pack))
1373 if (!ch->isBroadcasting())
1377 int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
1378 LOG_CHANNEL("Sent channel status update to %d clients",cnt);
1383 // ------------------------------------------
1384 bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
1386 unsigned int ctime = sys->getTime();
1388 ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
1393 /* int newLocalListeners = ch->localListeners();
1394 int newLocalRelays = ch->localRelays();
1398 (numListeners != newLocalListeners)
1399 || (numRelays != newLocalRelays)
1400 || (ch->isPlaying() != isPlaying)
1401 || (servMgr->getFirewall() != fwState)
1402 || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1404 && ((ctime-lastUpdate) > 10)
1408 numListeners = newLocalListeners;
1409 numRelays = newLocalRelays;
1410 isPlaying = ch->isPlaying();
1411 fwState = servMgr->getFirewall();
1416 hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
1417 hit.tracker = ch->isBroadcasting();*/
1419 int newLocalListeners = ch->localListeners();
1420 int newLocalRelays = ch->localRelays();
1422 if ((ch->isPlaying() == isPlaying)){
1423 if ((ctime-lastUpdate) < 10){
1427 if ((ctime-lastCheckTime) < 10){
1430 lastCheckTime = ctime;
1433 unsigned int oldp = ch->rawData.getOldestPos();
1434 unsigned int newp = ch->rawData.getLatestPos();
1438 // LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
1440 hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
1442 if(!(ch->info.ppFlags & ServMgr::bcstClap))
1444 hit.initLocal_pp(ch->stealth, ch->bClap ? 1 : 0);
1446 hit.tracker = ch->isBroadcasting();
1448 if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1449 || (newLocalListeners != numListeners)
1450 || (newLocalRelays != numRelays)
1451 || (ch->isPlaying() != isPlaying)
1452 || (servMgr->getFirewall() != fwState)
1453 || (ch->chDisp.relay != hit.relay)
1454 || (ch->chDisp.relayfull != hit.relayfull)
1455 || (ch->chDisp.chfull != hit.chfull)
1456 || (ch->chDisp.ratefull != hit.ratefull)
1457 || (ch->bClap && ((ctime-lastClapped) > 60)) //JP-MOD
1459 numListeners = newLocalListeners;
1460 numRelays = newLocalRelays;
1461 isPlaying = ch->isPlaying();
1462 fwState = servMgr->getFirewall();
1465 if(ch->bClap){ //JP-MOD
1466 lastClapped = ctime;
1472 if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
1473 ch->stayConnected = true;
1475 if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
1476 ch->stayConnected = false;
1478 MemoryStream pmem(pack.data,sizeof(pack.data));
1479 AtomStream atom(pmem);
1484 if (version_ex == 0)
1486 atom.writeParent(PCP_BCST,8);
1489 atom.writeParent(PCP_BCST,10);
1491 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
1492 atom.writeChar(PCP_BCST_HOPS,0);
1493 atom.writeChar(PCP_BCST_TTL,11);
1494 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1495 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1496 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1499 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1500 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1502 atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
1503 hit.writeAtoms(atom,noID);
1505 pack.len = pmem.pos;
1506 pack.type = ChanPacket::T_PCP;
1511 // -----------------------------------
1512 bool Channel::checkBump()
1514 unsigned int maxIdleTime = 30;
1515 if (isIndexTxt(this)) maxIdleTime = 60;
1517 if (!isBroadcasting() && (!sourceHost.tracker))
1518 if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > maxIdleTime))
1520 LOG_ERROR("Channel Auto bumped");
1532 // -----------------------------------
1533 int Channel::readStream(Stream &in,ChannelStream *source)
1541 source->readHeader(in,this);
1543 peercastApp->channelStart(&info);
1545 rawData.lastWriteTime = 0;
1547 bool wasBroadcasting=false;
1549 unsigned int receiveStartTime = 0;
1551 unsigned int ptime = 0;
1552 unsigned int upsize = 0;
1556 while (thread.active && !peercastInst->isQuitting)
1560 LOG_DEBUG("Channel idle");
1566 LOG_DEBUG("Channel bumped");
1574 LOG_DEBUG("Channel eof");
1580 error = source->readPacket(in,this);
1585 //if (rawData.writePos > 0)
1586 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1588 if (isBroadcasting())
1590 if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
1594 broadcastTrackerUpdate(noID);
1596 wasBroadcasting = true;
1600 /* if (status != Channel::S_RECEIVING){
1601 receiveStartTime = sys->getTime();
1602 } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
1603 chanMgr->hitlistlock.on();
1604 ChanHitList *hl = chanMgr->findHitList(info);
1606 hl->clearHits(true);
1608 chanMgr->hitlistlock.off();
1609 receiveStartTime = 0;
1611 setStatus(Channel::S_RECEIVING);
1614 source->updateStatus(this);
1618 unsigned int t = sys->getTime();
1621 upsize = Servent::MAX_OUTWARD_SIZE;
1624 unsigned int len = source->flushUb(in, upsize);
1629 }catch(StreamException &e)
1631 LOG_ERROR("readStream: %s",e.msg);
1635 if (!servMgr->keepDownstreams) {
1636 if (status == Channel::S_RECEIVING){
1637 chanMgr->hitlistlock.on();
1638 ChanHitList *hl = chanMgr->findHitList(info);
1640 hl->clearHits(false);
1642 chanMgr->hitlistlock.off();
1646 // setStatus(S_CLOSING);
1649 if (wasBroadcasting)
1653 broadcastTrackerUpdate(noID,true);
1656 peercastApp->channelStop(&info);
1658 source->readEnd(in,this);
1663 // -----------------------------------
1664 void PeercastStream::readHeader(Stream &in,Channel *ch)
1666 if (in.readTag() != 'PCST')
1667 throw StreamException("Not PeerCast stream");
1670 // -----------------------------------
1671 void PeercastStream::readEnd(Stream &,Channel *)
1675 // -----------------------------------
1676 int PeercastStream::readPacket(Stream &in,Channel *ch)
1682 pack.readPeercast(in);
1684 MemoryStream mem(pack.data,pack.len);
1688 case ChanPacket::T_HEAD:
1690 ch->headPack = pack;
1691 pack.pos = ch->streamPos;
1692 ch->newPacket(pack);
1693 ch->streamPos+=pack.len;
1695 case ChanPacket::T_DATA:
1696 pack.pos = ch->streamPos;
1697 ch->newPacket(pack);
1698 ch->streamPos+=pack.len;
1700 case ChanPacket::T_META:
1701 ch->insertMeta.fromMem(pack.data,pack.len);
1707 XML::Node *n = xml.findNode("channel");
1710 ChanInfo newInfo = ch->info;
1711 newInfo.updateFromXML(n);
1712 ChanHitList *chl = chanMgr->findHitList(ch->info);
1714 newInfo.updateFromXML(n);
1715 ch->updateInfo(newInfo);
1721 case ChanPacket::T_SYNC:
1723 unsigned int s = mem.readLong();
1724 if ((s-ch->syncPos) != 1)
1726 LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
1729 ch->info.numSkips++;
1730 if (ch->info.numSkips>50)
1731 throw StreamException("Bumped - Too many skips");
1746 // -----------------------------------
1747 void ChannelStream::readRaw(Stream &in, Channel *ch)
1751 const int readLen = 8192;
1753 pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
1754 in.read(pack.data,pack.len);
1755 ch->newPacket(pack);
1756 ch->checkReadDelay(pack.len);
1758 ch->streamPos+=pack.len;
1761 // ------------------------------------------
1762 void RawStream::readHeader(Stream &,Channel *)
1766 // ------------------------------------------
1767 int RawStream::readPacket(Stream &in,Channel *ch)
1773 // ------------------------------------------
1774 void RawStream::readEnd(Stream &,Channel *)
1780 // -----------------------------------
1781 void ChanPacket::init(ChanPacketv &p)
1785 if (len > MAX_DATALEN)
1786 throw StreamException("Packet data too large");
1790 priority = p.priority;
1791 memcpy(data, p.data, len);
1793 // -----------------------------------
1794 void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
1797 if (l > MAX_DATALEN)
1798 throw StreamException("Packet data too large");
1805 // -----------------------------------
1806 void ChanPacket::writeRaw(Stream &out)
1808 out.write(data,len);
1810 // -----------------------------------
1811 void ChanPacket::writePeercast(Stream &out)
1813 unsigned int tp = 0;
1816 case T_HEAD: tp = 'HEAD'; break;
1817 case T_META: tp = 'META'; break;
1818 case T_DATA: tp = 'DATA'; break;
1821 if (type != T_UNKNOWN)
1824 out.writeShort(len);
1826 out.write(data,len);
1829 // -----------------------------------
1830 void ChanPacket::readPeercast(Stream &in)
1832 unsigned int tp = in.readTag();
1836 case 'HEAD': type = T_HEAD; break;
1837 case 'DATA': type = T_DATA; break;
1838 case 'META': type = T_META; break;
1839 default: type = T_UNKNOWN;
1841 len = in.readShort();
1843 if (len > MAX_DATALEN)
1844 throw StreamException("Bad ChanPacket");
1847 // -----------------------------------
1848 int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
1858 for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
1860 //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
1861 ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
1862 if (src->type & accept)
1864 if (src->pos >= reqPos)
1867 //packets[writePos++] = *src;
1868 packets[writePos++].init(*src);
1877 return lastPos-firstPos;
1880 // -----------------------------------
1881 bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
1888 unsigned int bound = packets[0].len * ChanPacketBuffer::MAX_PACKETS * 2; // max packets to wait
1889 unsigned int fpos = getStreamPos(firstPos);
1890 unsigned int lpos = getStreamPos(lastPos);
1891 if (spos < fpos && (fpos < lpos || spos > lpos + bound))
1895 for(unsigned int i=firstPos; i<=lastPos; i++)
1897 //ChanPacket &p = packets[i%MAX_PACKETS];
1898 ChanPacketv &p = packets[i%MAX_PACKETS];
1899 if (p.pos >= spos && p.pos - spos <= bound)
1910 // -----------------------------------
1911 unsigned int ChanPacketBuffer::getLatestPos()
1916 return getStreamPos(lastPos);
1919 // -----------------------------------
1920 unsigned int ChanPacketBuffer::getOldestPos()
1925 return getStreamPos(firstPos);
1928 // -----------------------------------
1929 unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos)
1931 unsigned int min = getStreamPos(safePos);
1932 unsigned int max = getStreamPos(lastPos);
1943 // -----------------------------------
1944 unsigned int ChanPacketBuffer::getStreamPos(unsigned int index)
1946 return packets[index%MAX_PACKETS].pos;
1948 // -----------------------------------
1949 unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index)
1951 return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
1953 // -----------------------------------
1954 bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
1958 if (servMgr->keepDownstreams) {
1959 unsigned int lpos = getLatestPos();
1960 unsigned int diff = pack.pos - lpos;
1961 if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
1962 if (lpos && (diff == 0 || diff > 0xfff00000)) {
1963 LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
1964 lastSkipTime = sys->getTime();
1969 if (willSkip()) // too far behind
1971 lastSkipTime = sys->getTime();
1977 pack.sync = writePos;
1978 packets[writePos%MAX_PACKETS].init(pack);
1980 // LOG_DEBUG("packet.len = %d",pack.len);
1986 if (writePos >= MAX_PACKETS)
1987 firstPos = writePos-MAX_PACKETS;
1991 if (writePos >= NUM_SAFEPACKETS)
1992 safePos = writePos - NUM_SAFEPACKETS;
1999 lastWriteTime = sys->getTime();
2007 // -----------------------------------
2008 void ChanPacketBuffer::readPacket(ChanPacket &pack)
2011 unsigned int tim = sys->getTime();
2013 if (readPos < firstPos)
2014 throw StreamException("Read too far behind");
2016 while (readPos >= writePos)
2019 if ((sys->getTime() - tim) > 30)
2020 throw TimeoutException();
2023 pack.init(packets[readPos%MAX_PACKETS]);
2028 // -----------------------------------
2029 void ChanPacketBuffer::readPacketPri(ChanPacket &pack)
2031 unsigned int tim = sys->getTime();
2033 if (readPos < firstPos)
2034 throw StreamException("Read too far behind");
2036 while (readPos >= writePos)
2039 if ((sys->getTime() - tim) > 30)
2040 throw TimeoutException();
2043 ChanPacketv *best = &packets[readPos % MAX_PACKETS];
2044 for (unsigned int i = readPos + 1; i < writePos; i++) {
2045 if (packets[i % MAX_PACKETS].priority > best->priority)
2046 best = &packets[i % MAX_PACKETS];
2049 best->init(packets[readPos % MAX_PACKETS]);
2054 // -----------------------------------
2055 bool ChanPacketBuffer::willSkip()
2057 return ((writePos-readPos) >= MAX_PACKETS);
2060 // -----------------------------------
2061 void Channel::getStreamPath(char *str)
2067 sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
2072 // -----------------------------------
2073 void ChanMgr::startSearch(ChanInfo &info)
2080 searchActive = true;
2082 // -----------------------------------
2083 void ChanMgr::quit()
2085 LOG_DEBUG("ChanMgr is quitting..");
2088 // -----------------------------------
2089 int ChanMgr::numIdleChannels()
2092 Channel *ch = channel;
2096 if (ch->thread.active)
2097 if (ch->status == Channel::S_IDLE)
2103 // -----------------------------------
2104 void ChanMgr::closeOldestIdle()
2106 unsigned int idleTime = (unsigned int)-1;
2107 Channel *ch = channel,*oldest=NULL;
2111 if (ch->thread.active)
2112 if (ch->status == Channel::S_IDLE)
2113 if (ch->lastIdleTime < idleTime)
2116 idleTime = ch->lastIdleTime;
2122 oldest->thread.active = false;
2125 // -----------------------------------
2126 void ChanMgr::closeAll()
2128 Channel *ch = channel;
2131 if (ch->thread.active)
2132 ch->thread.shutdown();
2136 // -----------------------------------
2137 Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
2139 Channel *ch = channel;
2143 if (ch->info.matchNameID(info))
2150 // -----------------------------------
2151 Channel *ChanMgr::findChannelByName(const char *n)
2153 Channel *ch = channel;
2157 if (stricmp(ch->info.name,n)==0)
2164 // -----------------------------------
2165 Channel *ChanMgr::findChannelByIndex(int index)
2168 Channel *ch = channel;
2181 // -----------------------------------
2182 Channel *ChanMgr::findChannelByMount(const char *str)
2184 Channel *ch = channel;
2188 if (strcmp(ch->mount,str)==0)
2195 // -----------------------------------
2196 Channel *ChanMgr::findChannelByID(GnuID &id)
2198 Channel *ch = channel;
2202 if (ch->info.id.isSame(id))
2208 // -----------------------------------
2209 Channel *ChanMgr::findChannelByChannelID(int id)
2212 Channel *ch = channel;
2215 if (ch->isActive()){
2216 if (ch->channel_id == id){
2224 // -----------------------------------
2225 int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
2228 Channel *ch = channel;
2232 if (ch->info.match(info))
2242 // -----------------------------------
2243 int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
2246 Channel *ch = channel;
2250 if (ch->status == status)
2260 // -----------------------------------
2261 Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
2263 Channel *c = chanMgr->createChannel(info,NULL);
2266 c->stayConnected = stayConnected;
2272 // -----------------------------------
2273 Channel *ChanMgr::findAndRelay(ChanInfo &info)
2276 info.id.toStr(idStr);
2277 LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
2279 if(!isIndexTxt(&info)) // for PCRaw (popup)
2280 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
2285 WLockBlock wb(&(chanMgr->channellock));
2289 c = findChannelByNameID(info);
2293 c = chanMgr->createChannel(info,NULL);
2296 c->setStatus(Channel::S_SEARCHING);
2299 } else if (!(c->thread.active)){
2300 c->thread.active = true;
2301 c->thread.finish = false;
2302 c->info.lastPlayStart = 0; // reconnect
2303 c->info.lastPlayEnd = 0;
2305 c->finthread->finish = true;
2306 c->finthread = NULL;
2308 if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
2309 c->setStatus(Channel::S_SEARCHING);
2316 for(int i=0; i<600; i++) // search for 1 minute.
2321 c = findChannelByNameID(info);
2325 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
2330 if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
2340 // -----------------------------------
2347 currFindAndPlayChannel.clear();
2349 broadcastMsg.clear();
2350 broadcastMsgInterval=10;
2352 broadcastID.generate(PCP_BROADCAST_FLAGS);
2357 icyMetaInterval = 8192;
2358 maxRelaysPerChannel = 1;
2362 minBroadcastTTL = 1;
2363 maxBroadcastTTL = 7;
2365 pushTimeout = 60; // 1 minute
2366 pushTries = 5; // 5 times
2367 maxPushHops = 8; // max 8 hops away
2368 maxUptime = 0; // 0 = none
2370 prefetchTime = 10; // n seconds
2372 hostUpdateInterval = 120; // 2 minutes
2384 // -----------------------------------
2385 bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
2388 if (var == "numHitLists")
2389 sprintf(buf,"%d",numHitLists());
2391 else if (var == "numChannels")
2392 sprintf(buf,"%d",numChannels());
2393 else if (var == "djMessage")
2395 String utf8 = broadcastMsg;
2396 utf8.convertTo(String::T_UNICODESAFE);
2397 strcpy(buf,utf8.cstr());
2399 else if (var == "icyMetaInterval")
2400 sprintf(buf,"%d",icyMetaInterval);
2401 else if (var == "maxRelaysPerChannel")
2402 sprintf(buf,"%d",maxRelaysPerChannel);
2403 else if (var == "hostUpdateInterval")
2404 sprintf(buf,"%d",hostUpdateInterval);
2405 else if (var == "broadcastID")
2406 broadcastID.toStr(buf);
2412 out.writeString(buf);
2416 // -----------------------------------
2417 bool Channel::writeVariable(Stream &out, const String &var, int index)
2428 utf8.convertTo(String::T_UNICODESAFE);
2429 strcpy(buf,utf8.cstr());
2431 }else if (var == "bitrate")
2433 sprintf(buf,"%d",info.bitrate);
2435 }else if (var == "srcrate")
2439 unsigned int tot = sourceData->getSourceRate();
2440 sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
2444 }else if (var == "genre")
2447 utf8.convertTo(String::T_UNICODESAFE);
2448 strcpy(buf,utf8.cstr());
2449 }else if (var == "desc")
2452 utf8.convertTo(String::T_UNICODESAFE);
2453 strcpy(buf,utf8.cstr());
2454 }else if (var == "comment")
2456 utf8 = info.comment;
2457 utf8.convertTo(String::T_UNICODESAFE);
2458 strcpy(buf,utf8.cstr());
2459 }else if (var == "bcstClap") //JP-MOD
2461 strcpy(buf,info.ppFlags & ServMgr::bcstClap ? "1":"0");
2462 }else if (var == "uptime")
2465 if (info.lastPlayStart)
2466 uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
2469 strcpy(buf,uptime.cstr());
2471 else if (var == "type")
2472 sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
2473 else if (var == "ext")
2474 sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
2475 else if (var == "proto") {
2476 switch(info.contentType) {
2477 case ChanInfo::T_WMA:
2478 case ChanInfo::T_WMV:
2479 sprintf(buf, "mms://");
2482 sprintf(buf, "http://");
2485 else if (var == "localRelays")
2486 sprintf(buf,"%d",localRelays());
2487 else if (var == "localListeners")
2488 sprintf(buf,"%d",localListeners());
2490 else if (var == "totalRelays")
2491 sprintf(buf,"%d",totalRelays());
2492 else if (var == "totalListeners")
2493 sprintf(buf,"%d",totalListeners());
2494 else if (var == "totalClaps") //JP-MOD
2495 sprintf(buf,"%d",totalClaps());
2496 else if (var == "status")
2497 sprintf(buf,"%s",getStatusStr());
2498 else if (var == "keep")
2499 sprintf(buf,"%s",stayConnected?"Yes":"No");
2500 else if (var == "id")
2502 else if (var.startsWith("track."))
2505 if (var == "track.title")
2506 utf8 = info.track.title;
2507 else if (var == "track.artist")
2508 utf8 = info.track.artist;
2509 else if (var == "track.album")
2510 utf8 = info.track.album;
2511 else if (var == "track.genre")
2512 utf8 = info.track.genre;
2513 else if (var == "track.contactURL")
2514 utf8 = info.track.contact;
2516 utf8.convertTo(String::T_UNICODESAFE);
2517 strcpy(buf,utf8.cstr());
2519 }else if (var == "contactURL")
2520 sprintf(buf,"%s",info.url.cstr());
2521 else if (var == "streamPos")
2522 sprintf(buf,"%d",streamPos);
2523 else if (var == "sourceType")
2524 strcpy(buf,getSrcTypeStr());
2525 else if (var == "sourceProtocol")
2526 strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
2527 else if (var == "sourceURL")
2529 if (sourceURL.isEmpty())
2530 sourceHost.host.toStr(buf);
2532 strcpy(buf,sourceURL.cstr());
2534 else if (var == "headPos")
2535 sprintf(buf,"%d",headPack.pos);
2536 else if (var == "headLen")
2537 sprintf(buf,"%d",headPack.len);
2538 else if (var == "numHits")
2540 ChanHitList *chl = chanMgr->findHitListByID(info.id);
2543 // numHits = chl->numHits();
2551 sprintf(buf,"%d",numHits);
2552 } else if (var == "isBroadcast")
2553 strcpy(buf, (type == T_BROADCAST) ? "1":"0");
2557 out.writeString(buf);
2561 // -----------------------------------
2562 void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
2564 Channel *c = channel;
2567 if ( c->isActive() && c->isBroadcasting() )
2568 c->broadcastTrackerUpdate(svID,force);
2574 // -----------------------------------
2575 int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
2579 Channel *c = channel;
2582 if (c->sendPacketUp(pack,chanID,srcID,destID))
2590 // -----------------------------------
2591 void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
2593 //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
2596 Host sh = servMgr->serverHost;
2597 bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
2598 bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
2599 bool stable = servMgr->totalStreams>0;
2606 Channel *c = channel;
2612 bool tracker = c->isBroadcasting();
2614 int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds
2622 if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
2628 serv->outputPacket(hit,false);
2632 LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);
2639 // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);
2642 // -----------------------------------
2643 void ChanMgr::setUpdateInterval(unsigned int v)
2645 hostUpdateInterval = v;
2649 // -----------------------------------
2653 MemoryStream mem(pack.data,sizeof(pack.data));
2654 AtomStream atom(mem);
2655 atom.writeParent(PCP_BCST,3);
2656 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
2657 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
2658 atom.writeParent(PCP_MESG,1);
2659 atom.writeString(PCP_MESG_DATA,msg.cstr());
2669 PCPStream::readAtom(atom,bcs);
2670 //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2671 //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
2672 //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2673 //LOG_DEBUG("Sent message to %d clients",cnt);
2675 // -----------------------------------
2676 void ChanMgr::setBroadcastMsg(String &msg)
2678 if (!msg.isSame(broadcastMsg))
2682 Channel *c = channel;
2685 if (c->isActive() && c->isBroadcasting())
2687 ChanInfo newInfo = c->info;
2688 newInfo.comment = broadcastMsg;
2689 c->updateInfo(newInfo);
2698 // -----------------------------------
2699 void ChanMgr::clearHitLists()
2702 // LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
2703 chanMgr->hitlistlock.on();
2706 peercastApp->delChannel(&hitlist->info);
2708 ChanHitList *next = hitlist->next;
2714 // LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
2715 chanMgr->hitlistlock.off();
2717 // -----------------------------------
2718 Channel *ChanMgr::deleteChannel(Channel *delchan)
2722 Channel *ch = channel,*prev=NULL,*next=NULL;
2728 Channel *next = ch->next;
2734 if (delchan->sourceStream){
2735 delchan->sourceStream->parent = NULL;
2751 // -----------------------------------
2752 Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
2765 nc->info.lastPlayStart = 0;
2766 nc->info.lastPlayEnd = 0;
2767 nc->info.status = ChanInfo::S_UNKNOWN;
2769 nc->mount.set(mount);
2770 nc->setStatus(Channel::S_WAIT);
2771 nc->type = Channel::T_ALLOCATED;
2772 nc->info.createdTime = sys->getTime();
2774 LOG_CHANNEL("New channel created");
2779 // -----------------------------------
2780 int ChanMgr::pickHits(ChanHitSearch &chs)
2782 ChanHitList *chl = hitlist;
2786 if (chl->pickHits(chs))
2796 // -----------------------------------
2797 ChanHitList *ChanMgr::findHitList(ChanInfo &info)
2799 ChanHitList *chl = hitlist;
2803 if (chl->info.matchNameID(info))
2810 // -----------------------------------
2811 ChanHitList *ChanMgr::findHitListByID(GnuID &id)
2813 ChanHitList *chl = hitlist;
2817 if (chl->info.id.isSame(id))
2823 // -----------------------------------
2824 int ChanMgr::numHitLists()
2827 ChanHitList *chl = hitlist;
2836 // -----------------------------------
2837 ChanHitList *ChanMgr::addHitList(ChanInfo &info)
2839 ChanHitList *chl = new ChanHitList();
2842 chl->next = hitlist;
2847 chl->info.createdTime = sys->getTime();
2848 peercastApp->addChannel(&chl->info);
2853 // -----------------------------------
2854 void ChanMgr::clearDeadHits(bool clearTrackers)
2856 unsigned int interval;
2858 if (servMgr->isRoot)
2859 interval = 1200; // mainly for old 0.119 clients
2861 interval = hostUpdateInterval+120;
2863 chanMgr->hitlistlock.on();
2864 ChanHitList *chl = hitlist,*prev = NULL;
2869 if (chl->clearDeadHits(interval,clearTrackers) == 0)
2871 if (!isBroadcasting(chl->info.id))
2873 if (!chanMgr->findChannelByID(chl->info.id))
2875 peercastApp->delChannel(&chl->info);
2877 ChanHitList *next = chl->next;
2893 chanMgr->hitlistlock.off();
2895 // -----------------------------------
2896 bool ChanMgr::isBroadcasting(GnuID &id)
2898 Channel *ch = findChannelByID(id);
2900 return ch->isBroadcasting();
2904 // -----------------------------------
2905 bool ChanMgr::isBroadcasting()
2907 Channel *ch = channel;
2911 if (ch->isBroadcasting())
2919 // -----------------------------------
2920 int ChanMgr::numChannels()
2923 Channel *ch = channel;
2933 // -----------------------------------
2934 void ChanMgr::deadHit(ChanHit &hit)
2936 ChanHitList *chl = findHitListByID(hit.chanID);
2940 // -----------------------------------
2941 void ChanMgr::delHit(ChanHit &hit)
2943 ChanHitList *chl = findHitListByID(hit.chanID);
2948 // -----------------------------------
2949 void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
2955 hit.rhost[1].init();
2956 hit.tracker = tracker;
2961 // -----------------------------------
2962 ChanHit *ChanMgr::addHit(ChanHit &h)
2965 lastHit = sys->getTime();
2967 ChanHitList *hl=NULL;
2969 hl = findHitListByID(h.chanID);
2975 hl = addHitList(info);
2980 return hl->addHit(h);
2985 // -----------------------------------
2986 bool ChanMgr::findParentHit(ChanHit &p)
2988 ChanHitList *hl=NULL;
2990 chanMgr->hitlistlock.on();
2992 hl = findHitListByID(p.chanID);
2996 ChanHit *ch = hl->hit;
2999 if (!ch->dead && (ch->rhost[0].ip == p.uphost.ip)
3000 && (ch->rhost[0].port == p.uphost.port))
3002 chanMgr->hitlistlock.off();
3009 chanMgr->hitlistlock.off();
3014 // -----------------------------------
3015 class ChanFindInfo : public ThreadInfo
3021 // -----------------------------------
3022 THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
3024 ChanFindInfo *cfi = (ChanFindInfo *)th;
3030 Channel *ch = chanMgr->findChannelByNameID(info);
3032 chanMgr->currFindAndPlayChannel = info.id;
3035 ch = chanMgr->findAndRelay(info);
3039 // check that a different channel hasn`t be selected already.
3040 if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
3041 chanMgr->playChannel(ch->info);
3044 ch->stayConnected = cfi->keep;
3050 // -----------------------------------
3051 void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
3053 ChanFindInfo *cfi = new ChanFindInfo;
3056 cfi->func = findAndPlayChannelProc;
3059 sys->startThread(cfi);
3061 // -----------------------------------
3062 void ChanMgr::playChannel(ChanInfo &info)
3065 char str[128],fname[256],idStr[128];
3067 sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
3068 info.id.toStr(idStr);
3070 PlayList::TYPE type;
3073 if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
3075 type = PlayList::T_ASX;
3076 // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
3077 // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
3078 if (servMgr->getModulePath) //JP-EX
3080 peercastApp->getDirectory();
3081 sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);
3083 sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
3084 }else if (info.contentType == ChanInfo::T_OGM)
3086 type = PlayList::T_RAM;
3087 if (servMgr->getModulePath) //JP-EX
3089 peercastApp->getDirectory();
3090 sprintf(fname,"%s/play.ram",servMgr->modulePath);
3092 sprintf(fname,"%s/play.ram",peercastApp->getPath());
3096 type = PlayList::T_SCPLS;
3097 if (servMgr->getModulePath) //JP-EX
3099 peercastApp->getDirectory();
3100 sprintf(fname,"%s/play.pls",servMgr->modulePath);
3102 sprintf(fname,"%s/play.pls",peercastApp->getPath());
3106 PlayList *pls = new PlayList(type,1);
3107 pls->addChannel(str,info);
3110 LOG_DEBUG("Writing %s",fname);
3112 file.openWriteReplace(fname);
3117 LOG_DEBUG("Executing: %s",fname);
3118 sys->executeFile(fname);
3123 // -----------------------------------
3124 ChanHitList::ChanHitList()
3131 // -----------------------------------
3132 ChanHitList::~ChanHitList()
3134 chanMgr->hitlistlock.on();
3136 hit = deleteHit(hit);
3137 chanMgr->hitlistlock.off();
3139 // -----------------------------------
3140 void ChanHit::pickNearestIP(Host &h)
3142 for(int i=0; i<2; i++)
3144 if (h.classType() == rhost[i].classType())
3152 // -----------------------------------
3153 void ChanHit::init()
3164 clap_pp = 0; //JP-MOD
3166 dead = tracker = firewalled = stable = yp = false;
3167 recv = cin = direct = relay = true;
3168 relayfull = chfull = ratefull = false;
3177 version_ex_prefix[0] = ' ';
3178 version_ex_prefix[1] = ' ';
3179 version_ex_number = 0;
3188 oldestPos = newestPos = 0;
3193 // -----------------------------------
3194 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)
3197 firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
3198 numListeners = numl;
3201 stable = servMgr->totalStreams>0;
3202 sessionID = servMgr->sessionID;
3205 direct = !servMgr->directFull();
3206 // relay = !servMgr->relaysFull();
3207 cin = !servMgr->controlInFull();
3209 relayfull = servMgr->relaysFull();
3212 Channel *c = chanMgr->channel;
3214 unsigned int needRate = 0;
3215 unsigned int allRate = 0;
3217 if (c->isPlaying()){
3218 allRate += c->info.bitrate * c->localRelays();
3219 if ((c != ch) && (c->localRelays() == 0)){
3220 if(!isIndexTxt(c)) // for PCRaw (relay)
3222 needRate+=c->info.bitrate;
3227 unsigned int numRelay = servMgr->numStreams(Servent::T_RELAY,false);
3228 int diff = servMgr->maxRelays - numRelay;
3229 if (ch->localRelays()){
3230 if (noRelay > diff){
3238 // ratefull = servMgr->bitrateFull(needRate+bitrate);
3239 ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
3241 if (!isIndexTxt(ch))
3242 relay = (!relayfull) && (!chfull) && (!ratefull) && (numRelay + noRelay < servMgr->maxRelays);
3244 relay = (!chfull) && (!ratefull); // for PCRaw (relay)
3247 LOG_DEBUG("Reject by relay full");
3250 LOG_DEBUG("Reject by channel full");
3253 LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
3256 host = servMgr->serverHost;
3258 version = PCP_CLIENT_VERSION;
3259 version_vp = PCP_CLIENT_VERSION_VP;
3262 strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
3263 version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
3266 version_ex_prefix[0] = ' ';
3267 version_ex_prefix[1] = ' ';
3268 version_ex_number = 0;
3271 status = ch->status;
3273 rhost[0] = Host(host.ip,host.port);
3274 rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
3282 uphost.ip = ch->sourceHost.host.ip;
3283 uphost.port = ch->sourceHost.host.port;
3287 // -----------------------------------
3288 void ChanHit::initLocal_pp(bool isStealth, int numClaps) //JP-MOD
3290 numListeners = numListeners && !isStealth ? 1 : 0;
3294 // -----------------------------------
3295 void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
3297 bool addChan=chanID.isSet();
3298 bool uphostdata=(uphost.ip != 0);
3301 if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
3302 if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
3303 if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
3304 if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
3305 if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
3306 if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
3308 atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0) + (clap_pp?1:0/*JP-MOD*/));
3311 atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
3312 atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
3313 atom.writeInt(PCP_HOST_IP,rhost[0].ip);
3314 atom.writeShort(PCP_HOST_PORT,rhost[0].port);
3315 atom.writeInt(PCP_HOST_IP,rhost[1].ip);
3316 atom.writeShort(PCP_HOST_PORT,rhost[1].port);
3317 atom.writeInt(PCP_HOST_NUML,numListeners);
3318 atom.writeInt(PCP_HOST_NUMR,numRelays);
3319 atom.writeInt(PCP_HOST_UPTIME,upTime);
3320 atom.writeInt(PCP_HOST_VERSION,version);
3321 atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
3322 if (version_ex_number){
3323 atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
3324 atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
3326 atom.writeChar(PCP_HOST_FLAGS1,fl1);
3327 atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
3328 atom.writeInt(PCP_HOST_NEWPOS,newestPos);
3330 atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
3331 atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
3332 atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
3334 if (clap_pp){ //JP-MOD
3335 atom.writeInt(PCP_HOST_CLAP_PP,clap_pp);
3338 // -----------------------------------
3339 bool ChanHit::writeVariable(Stream &out, const String &var)
3343 if (var == "rhost0")
3345 if (servMgr->enableGetName) //JP-EX s
3351 strcpy(buf,"<font color=red>");
3353 strcpy(buf,"<font color=orange>");
3358 strcpy(buf,"<font color=purple>");
3360 strcpy(buf,"<font color=blue>");
3363 strcpy(buf,"<font color=green>");
3367 rhost[0].toStr(buf2);
3371 if (ClientSocket::getHostname(h_name,sizeof(h_name),rhost[0].ip)) // BOF
\91Î
\8dô
\82Á
\82Û
\82¢
3377 strcat(buf,"</font>");
3380 rhost[0].toStr(buf);
3382 else if (var == "rhost1")
3383 rhost[1].toStr(buf);
3384 else if (var == "numHops")
3385 sprintf(buf,"%d",numHops);
3386 else if (var == "numListeners")
3387 sprintf(buf,"%d",numListeners);
3388 else if (var == "numRelays")
3389 sprintf(buf,"%d",numRelays);
3390 else if (var == "uptime")
3393 timeStr.setFromStopwatch(upTime);
3394 strcpy(buf,timeStr.cstr());
3395 }else if (var == "update")
3399 timeStr.setFromStopwatch(sys->getTime()-time);
3402 strcpy(buf,timeStr.cstr());
3403 }else if (var == "isFirewalled"){
3404 sprintf(buf,"%d",firewalled?1:0);
3405 }else if (var == "version"){
3406 sprintf(buf,"%d",version);
3407 }else if (var == "agent"){
3409 if (version_ex_number){
3410 sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
3411 } else if (version_vp){
3412 sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
3414 sprintf(buf,"v0.%d", version);
3420 else if (var == "check")
3423 strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
3424 rhost[0].IPtoStr(buf2);
3426 strcat(buf, "')\">_</a>");
3428 else if (var == "uphost") // tree
3430 else if (var == "uphostHops") // tree
3431 sprintf(buf,"%d",uphostHops);
3432 else if (var == "canRelay") // tree
3433 sprintf(buf, "%d",relay);
3437 out.writeString(buf);
3441 // -----------------------------------
3442 int ChanHitList::getTotalListeners()
3449 cnt+=h->numListeners;
3454 // -----------------------------------
3455 int ChanHitList::getTotalRelays()
3467 // -----------------------------------
3468 int ChanHitList::getTotalFirewalled()
3482 // -----------------------------------
3483 int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
3488 void ChanHitList::clearHits(bool flg)
3490 ChanHit *c = hit, *prev = NULL;
3493 if (flg || (c->numHops != 0)){
3494 ChanHit *next = c->next;
3509 // -----------------------------------
3510 ChanHit *ChanHitList::deleteHit(ChanHit *ch)
3512 ChanHit *c = hit,*prev=NULL;
3517 ChanHit *next = c->next;
3533 // -----------------------------------
3534 ChanHit *ChanHitList::addHit(ChanHit &h)
3536 char ip0str[64],ip1str[64];
3537 h.rhost[0].toStr(ip0str);
3538 h.rhost[1].toStr(ip1str);
3540 h.uphost.toStr(uphostStr);
3542 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
3544 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
3547 // dont add our own hits
3548 if (servMgr->sessionID.isSame(h.sessionID))
3552 lastHitTime = sys->getTime();
3553 h.time = lastHitTime;
3558 if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
3559 if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
3563 if (ch->numHops > 0 && h.numHops == 0)
3564 // downstream hit recieved as RelayHost
3566 ChanHit *next = ch->next;
3575 // clear hits with same session ID (IP may have changed)
3576 if (h.sessionID.isSet())
3582 if (ch->sessionID.isSame(h.sessionID))
3594 ChanHit *ch = new ChanHit();
3596 ch->chanID = info.id;
3606 // -----------------------------------
3607 int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
3610 unsigned int ctime = sys->getTime();
3612 // LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
3613 chanMgr->hitlistlock.on();
3619 if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
3621 // ch = deleteHit(ch);
3623 if (ch->firewalled){
3624 // LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
3625 if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
3629 ch->numListeners = 0;
3642 // LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
3643 chanMgr->hitlistlock.off();
3648 // -----------------------------------
3649 void ChanHitList::deadHit(ChanHit &h)
3651 char ip0str[64],ip1str[64];
3652 h.rhost[0].toStr(ip0str);
3653 h.rhost[1].toStr(ip1str);
3654 LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
3660 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3667 // -----------------------------------
3668 void ChanHitList::delHit(ChanHit &h)
3670 char ip0str[64],ip1str[64];
3671 h.rhost[0].toStr(ip0str);
3672 h.rhost[1].toStr(ip1str);
3673 LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
3679 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3687 // -----------------------------------
3688 int ChanHitList::numHits()
3694 if (ch->host.ip && !ch->dead && ch->numHops)
3701 // -----------------------------------
3702 int ChanHitList::numListeners()
3708 if (ch->host.ip && !ch->dead && ch->numHops)
3709 cnt += (unsigned int)ch->numListeners > 3 ? 3 : ch->numListeners;
3716 // -----------------------------------
3717 int ChanHitList::numClaps() //JP-MOD
3723 if (ch->host.ip && !ch->dead && ch->numHops && (ch->clap_pp & 1)){
3731 // -----------------------------------
3732 int ChanHitList::numRelays()
3738 if (ch->host.ip && !ch->dead)
3739 cnt += ch->numRelays;
3746 // -----------------------------------
3747 int ChanHitList::numTrackers()
3753 if ((ch->host.ip && !ch->dead) && (ch->tracker))
3759 // -----------------------------------
3760 int ChanHitList::numFirewalled()
3766 if (ch->host.ip && !ch->dead)
3767 cnt += ch->firewalled?1:0;
3772 // -----------------------------------
3773 int ChanHitList::closestHit()
3775 unsigned int hop=10000;
3779 if (ch->host.ip && !ch->dead)
3780 if (ch->numHops < hop)
3787 // -----------------------------------
3788 int ChanHitList::furthestHit()
3794 if (ch->host.ip && !ch->dead)
3795 if (ch->numHops > hop)
3802 // -----------------------------------
3803 unsigned int ChanHitList::newestHit()
3805 unsigned int time=0;
3809 if (ch->host.ip && !ch->dead)
3810 if (ch->time > time)
3817 // -----------------------------------
3818 int ChanHitList::pickHits(ChanHitSearch &chs)
3820 ChanHit best,*bestP=NULL;
3825 unsigned int ctime = sys->getTime();
3830 if (c->host.ip && !c->dead)
3832 if (!chs.excludeID.isSame(c->sessionID))
3833 if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
3834 if ((c->numHops<=best.numHops)) // (c->time>=best.time))
3835 if (c->relay || (!c->relay && chs.useBusyRelays))
3836 if (c->cin || (!c->cin && chs.useBusyControls))
3839 if (chs.trackersOnly && c->tracker)
3841 if (chs.matchHost.ip)
3843 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3847 best.host = best.rhost[1]; // use lan ip
3849 }else if (c->firewalled == chs.useFirewalled)
3853 best.host = best.rhost[0]; // use wan ip
3855 }else if (!chs.trackersOnly && !c->tracker)
3857 if (chs.matchHost.ip)
3859 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3863 best.host = best.rhost[1]; // use lan ip
3865 }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
3869 best.host = best.rhost[0]; // use wan ip
3879 if (chs.numResults < ChanHitSearch::MAX_RESULTS)
3882 bestP->lastContact = ctime;
3883 chs.best[chs.numResults++] = best;
3893 // -----------------------------------
3894 int ChanHitList::pickSourceHits(ChanHitSearch &chs)
3896 if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
3901 // -----------------------------------
3902 const char *ChanInfo::getTypeStr(TYPE t)
3906 case T_RAW: return "RAW";
3908 case T_MP3: return "MP3";
3909 case T_OGG: return "OGG";
3910 case T_OGM: return "OGM";
3911 case T_WMA: return "WMA";
3913 case T_MOV: return "MOV";
3914 case T_MPG: return "MPG";
3915 case T_NSV: return "NSV";
3916 case T_WMV: return "WMV";
3918 case T_PLS: return "PLS";
3919 case T_ASX: return "ASX";
3921 default: return "UNKNOWN";
3924 // -----------------------------------
3925 const char *ChanInfo::getProtocolStr(PROTOCOL t)
3929 case SP_PEERCAST: return "PEERCAST";
3930 case SP_HTTP: return "HTTP";
3931 case SP_FILE: return "FILE";
3932 case SP_MMS: return "MMS";
3933 case SP_PCP: return "PCP";
3934 default: return "UNKNOWN";
3937 // -----------------------------------
3938 ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
3940 if (stricmp(str,"PEERCAST")==0)
3942 else if (stricmp(str,"HTTP")==0)
3944 else if (stricmp(str,"FILE")==0)
3946 else if (stricmp(str,"MMS")==0)
3948 else if (stricmp(str,"PCP")==0)
3954 // -----------------------------------
3955 const char *ChanInfo::getTypeExt(TYPE t)
3959 case ChanInfo::T_OGM:
3960 case ChanInfo::T_OGG:
3962 case ChanInfo::T_MP3:
3964 case ChanInfo::T_MOV:
3966 case ChanInfo::T_NSV:
3968 case ChanInfo::T_WMV:
3970 case ChanInfo::T_WMA:
3976 // -----------------------------------
3977 ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
3979 if (stricmp(str,"MP3")==0)
3981 else if (stricmp(str,"OGG")==0)
3983 else if (stricmp(str,"OGM")==0)
3985 else if (stricmp(str,"RAW")==0)
3987 else if (stricmp(str,"NSV")==0)
3989 else if (stricmp(str,"WMA")==0)
3991 else if (stricmp(str,"WMV")==0)
3993 else if (stricmp(str,"PLS")==0)
3995 else if (stricmp(str,"M3U")==0)
3997 else if (stricmp(str,"ASX")==0)
4002 // -----------------------------------
4003 bool ChanInfo::matchNameID(ChanInfo &inf)
4006 if (id.isSame(inf.id))
4009 if (!inf.name.isEmpty())
4010 if (name.contains(inf.name))
4015 // -----------------------------------
4016 bool ChanInfo::match(ChanInfo &inf)
4020 if (inf.status != S_UNKNOWN)
4022 if (status != inf.status)
4026 if (inf.bitrate != 0)
4028 if (bitrate == inf.bitrate)
4035 if (id.isSame(inf.id))
4040 if (inf.contentType != T_UNKNOWN)
4042 if (contentType == inf.contentType)
4047 if (!inf.name.isEmpty())
4049 if (name.contains(inf.name))
4054 if (!inf.genre.isEmpty())
4056 if (genre.contains(inf.genre))
4063 // -----------------------------------
4064 bool TrackInfo::update(TrackInfo &inf)
4066 bool changed = false;
4068 if (!contact.isSame(inf.contact))
4070 contact = inf.contact;
4074 if (!title.isSame(inf.title))
4080 if (!artist.isSame(inf.artist))
4082 artist = inf.artist;
4086 if (!album.isSame(inf.album))
4092 if (!genre.isSame(inf.genre))
4103 // -----------------------------------
4104 bool ChanInfo::update(ChanInfo &info)
4106 bool changed = false;
4111 if (!info.id.isSet())
4114 // only update from chaninfo that has full name etc..
4115 if (info.name.isEmpty())
4118 // check valid broadcaster key
4121 if (!bcID.isSame(info.bcID))
4123 LOG_ERROR("ChanInfo BC key not valid");
4133 if (bitrate != info.bitrate)
4135 bitrate = info.bitrate;
4139 if (contentType != info.contentType)
4141 contentType = info.contentType;
4145 if(ppFlags != info.ppFlags) //JP-MOD
4147 ppFlags = info.ppFlags;
4151 if (!desc.isSame(info.desc)) //JP-EX
4157 if (!name.isSame(info.name))
4163 if (!comment.isSame(info.comment))
4165 comment = info.comment;
4169 if (!genre.isSame(info.genre))
4175 if (!url.isSame(info.url))
4181 if (track.update(info.track))
4187 // -----------------------------------
4188 void ChanInfo::initNameID(const char *n)
4196 // -----------------------------------
4197 void ChanInfo::init()
4202 contentType = T_UNKNOWN;
4203 srcProtocol = SP_UNKNOWN;
4214 ppFlags = 0; //JP-MOD
4216 // -----------------------------------
4217 void ChanInfo::readTrackXML(XML::Node *n)
4220 readXMLString(track.title,n,"title");
4221 readXMLString(track.contact,n,"contact");
4222 readXMLString(track.artist,n,"artist");
4223 readXMLString(track.album,n,"album");
4224 readXMLString(track.genre,n,"genre");
4226 // -----------------------------------
4227 unsigned int ChanInfo::getUptime()
4229 // calculate uptime and cap if requested by settings.
4231 upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
4232 if (chanMgr->maxUptime)
4233 if (upt > chanMgr->maxUptime)
4234 upt = chanMgr->maxUptime;
4237 // -----------------------------------
4238 unsigned int ChanInfo::getAge()
4240 return sys->getTime()-createdTime;
4243 // ------------------------------------------
4244 void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
4246 for(int i=0; i<numc; i++)
4249 ID4 id = atom.read(c,d);
4250 if (id == PCP_CHAN_TRACK_TITLE)
4252 atom.readString(track.title.data,sizeof(track.title.data),d);
4253 }else if (id == PCP_CHAN_TRACK_CREATOR)
4255 atom.readString(track.artist.data,sizeof(track.artist.data),d);
4256 }else if (id == PCP_CHAN_TRACK_URL)
4258 atom.readString(track.contact.data,sizeof(track.contact.data),d);
4259 }else if (id == PCP_CHAN_TRACK_ALBUM)
4261 atom.readString(track.album.data,sizeof(track.album.data),d);
4266 // ------------------------------------------
4267 void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
4269 for(int i=0; i<numc; i++)
4272 ID4 id = atom.read(c,d);
4273 if (id == PCP_CHAN_INFO_NAME)
4275 atom.readString(name.data,sizeof(name.data),d);
4276 }else if (id == PCP_CHAN_INFO_BITRATE)
4278 bitrate = atom.readInt();
4279 }else if (id == PCP_CHAN_INFO_GENRE)
4281 atom.readString(genre.data,sizeof(genre.data),d);
4282 }else if (id == PCP_CHAN_INFO_URL)
4284 atom.readString(url.data,sizeof(url.data),d);
4285 }else if (id == PCP_CHAN_INFO_DESC)
4287 atom.readString(desc.data,sizeof(desc.data),d);
4288 }else if (id == PCP_CHAN_INFO_COMMENT)
4290 atom.readString(comment.data,sizeof(comment.data),d);
4291 }else if (id == PCP_CHAN_INFO_TYPE)
4294 atom.readString(type,sizeof(type),d);
4295 contentType = ChanInfo::getTypeFromStr(type);
4296 }else if (id == PCP_CHAN_INFO_PPFLAGS) //JP-MOD
4298 ppFlags = (unsigned int)atom.readInt();
4304 // -----------------------------------
4305 void ChanInfo::writeInfoAtoms(AtomStream &atom)
4307 atom.writeParent(PCP_CHAN_INFO,7 + (ppFlags ? 1:0/*JP-MOD*/));
4308 atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
4309 atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
4310 atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
4311 atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
4312 atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
4313 atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
4314 atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));
4316 atom.writeInt(PCP_CHAN_INFO_PPFLAGS,ppFlags); //JP-MOD
4319 // -----------------------------------
4320 void ChanInfo::writeTrackAtoms(AtomStream &atom)
4322 atom.writeParent(PCP_CHAN_TRACK,4);
4323 atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
4324 atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
4325 atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
4326 atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
4330 // -----------------------------------
4331 XML::Node *ChanInfo::createChannelXML()
4335 String nameUNI = name;
4336 nameUNI.convertTo(String::T_UNICODESAFE);
4338 String urlUNI = url;
4339 urlUNI.convertTo(String::T_UNICODESAFE);
4341 String genreUNI = genre;
4342 genreUNI.convertTo(String::T_UNICODESAFE);
4344 String descUNI = desc;
4345 descUNI.convertTo(String::T_UNICODESAFE);
4348 commentUNI = comment;
4349 commentUNI.convertTo(String::T_UNICODESAFE);
4355 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\"",
4359 getTypeStr(contentType),
4371 // -----------------------------------
4372 XML::Node *ChanInfo::createQueryXML()
4378 String nameHTML = name;
4379 nameHTML.convertTo(String::T_HTML);
4380 String genreHTML = genre;
4381 genreHTML.convertTo(String::T_HTML);
4384 if (!nameHTML.isEmpty())
4386 strcat(buf," name=\"");
4387 strcat(buf,nameHTML.cstr());
4391 if (!genreHTML.isEmpty())
4393 strcat(buf," genre=\"");
4394 strcat(buf,genreHTML.cstr());
4401 strcat(buf," id=\"");
4407 return new XML::Node("channel %s",buf);
4410 // -----------------------------------
4411 XML::Node *ChanInfo::createRelayChannelXML()
4418 return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
4424 }// -----------------------------------
4425 XML::Node *ChanInfo::createTrackXML()
4427 String titleUNI = track.title;
4428 titleUNI.convertTo(String::T_UNICODESAFE);
4430 String artistUNI = track.artist;
4431 artistUNI.convertTo(String::T_UNICODESAFE);
4433 String albumUNI = track.album;
4434 albumUNI.convertTo(String::T_UNICODESAFE);
4436 String genreUNI = track.genre;
4437 genreUNI.convertTo(String::T_UNICODESAFE);
4439 String contactUNI = track.contact;
4440 contactUNI.convertTo(String::T_UNICODESAFE);
4444 return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
4453 // -----------------------------------
4454 void ChanInfo::init(XML::Node *n)
4460 // -----------------------------------
4461 void ChanInfo::updateFromXML(XML::Node *n)
4463 String typeStr,idStr;
4465 readXMLString(name,n,"name");
4466 readXMLString(genre,n,"genre");
4467 readXMLString(url,n,"url");
4468 readXMLString(desc,n,"desc");
4471 int br = n->findAttrInt("bitrate");
4476 ppFlags = ServMgr::bcstNone;
4478 if (n->findAttrInt("bcstClap"))
4479 ppFlags |= ServMgr::bcstClap;
4482 readXMLString(typeStr,n,"type");
4483 if (!typeStr.isEmpty())
4484 contentType = getTypeFromStr(typeStr.cstr());
4487 readXMLString(idStr,n,"id");
4488 if (!idStr.isEmpty())
4489 id.fromStr(idStr.cstr());
4491 readXMLString(comment,n,"comment");
4493 XML::Node *tn = n->findNode("track");
4499 // -----------------------------------
4500 void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
4510 // -----------------------------------
4511 void ChanInfo::init(const char *fn)
4518 // -----------------------------------
4519 void PlayList::readASX(Stream &in)
4521 LOG_DEBUG("Reading ASX");
4527 }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
4531 XML::Node *n = xml.root->child;
4534 if (stricmp("entry",n->getName())==0)
4536 XML::Node *rf = n->findNode("ref");
4539 char *hr = rf->findAttr("href");
4543 //LOG("asx url %s",hr);
4552 // -----------------------------------
4553 void PlayList::readSCPLS(Stream &in)
4556 while (in.readLine(tmp,sizeof(tmp)))
4558 if (strnicmp(tmp,"file",4)==0)
4560 char *p = strstr(tmp,"=");
4566 // -----------------------------------
4567 void PlayList::readPLS(Stream &in)
4570 while (in.readLine(tmp,sizeof(tmp)))
4576 // -----------------------------------
4577 void PlayList::writeSCPLS(Stream &out)
4579 out.writeLine("[playlist]");
4581 out.writeLineF("NumberOfEntries=%d",numURLs);
4583 for(int i=0; i<numURLs; i++)
4585 out.writeLineF("File%d=%s",i+1,urls[i].cstr());
4586 out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
4587 out.writeLineF("Length%d=-1",i+1);
4589 out.writeLine("Version=2");
4591 // -----------------------------------
4592 void PlayList::writePLS(Stream &out)
4594 for(int i=0; i<numURLs; i++)
4595 out.writeLineF("%s",urls[i].cstr());
4597 // -----------------------------------
4598 void PlayList::writeRAM(Stream &out)
4600 for(int i=0; i<numURLs; i++)
4601 out.writeLineF("%s",urls[i].cstr());
4604 // -----------------------------------
4605 #define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
4606 static void SJIStoSJISSAFE(char *string, size_t size)
4610 (string[pos] != '\0') && (pos < size);
4613 if(isHTMLSPECIAL(string[pos]))
4618 // -----------------------------------
4619 static void WriteASXInfo(Stream &out, String &title, String &contacturl, String::TYPE tEncoding = String::T_UNICODESAFE) //JP-MOD
4621 if(!title.isEmpty())
4624 titleEncode = title;
4625 titleEncode.convertTo(tEncoding);
4626 if(tEncoding == String::T_SJIS)
4627 SJIStoSJISSAFE(titleEncode.cstr(), String::MAX_LEN);
4628 out.writeLineF("<TITLE>%s</TITLE>", titleEncode.cstr());
4631 if(!contacturl.isEmpty())
4633 String contacturlEncode;
4634 contacturlEncode = contacturl;
4635 contacturlEncode.convertTo(tEncoding);
4636 if(tEncoding == String::T_SJIS)
4637 SJIStoSJISSAFE(contacturlEncode.cstr(), String::MAX_LEN);
4638 out.writeLineF("<MOREINFO HREF = \"%s\" />", contacturlEncode.cstr());
4642 // -----------------------------------
4643 void PlayList::writeASX(Stream &out)
4645 out.writeLine("<ASX Version=\"3.0\">");
4647 String::TYPE tEncoding = String::T_SJIS;
4648 if(servMgr->asxDetailedMode == 2)
4650 out.writeLine("<PARAM NAME = \"Encoding\" VALUE = \"utf-8\" />"); //JP-MOD Memo: UTF-8 cannot be used in some recording software.
4651 tEncoding = String::T_UNICODESAFE;
4654 if(servMgr->asxDetailedMode)
4655 WriteASXInfo(out, titles[0], contacturls[0], tEncoding); //JP-MOD
4657 for(int i=0; i<numURLs; i++)
4659 out.writeLine("<ENTRY>");
4660 if(servMgr->asxDetailedMode)
4661 WriteASXInfo(out, titles[i], contacturls[i], tEncoding); //JP-MOD
4662 out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
4663 out.writeLine("</ENTRY>");
4665 out.writeLine("</ASX>");
4669 // -----------------------------------
4670 void PlayList::addChannel(const char *path, ChanInfo &info)
4676 info.id.toStr(idStr);
4677 char *nid = info.id.isSet()?idStr:info.name.cstr();
4679 sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
4680 addURL(url.cstr(),info.name,info.url);
4683 // -----------------------------------
4684 void ChanHitSearch::init()
4688 useFirewalled = false;
4689 trackersOnly = false;
4690 useBusyRelays = true;
4691 useBusyControls = true;
4695 //seed = sys->getTime();
4699 int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
4706 static int base = 0x400;
4707 ChanHit tmpHit[MAX_RESULTS];
4708 static WLock seqLock;
4709 static unsigned int riSequence = 0;
4717 riSequence &= 0xffffff;
4720 Servent *s = servMgr->servents;
4722 if (s->serventHit.rhost[0].port && s->type == Servent::T_RELAY
4723 && s->chanID.isSame(chl->info.id)) {
4724 int i = index % MAX_RESULTS;
4725 if (index < MAX_RESULTS
4726 || tmpHit[i].lastSendSeq > s->serventHit.lastSendSeq) {
4727 s->serventHit.lastSendSeq = seq;
4728 tmpHit[i] = s->serventHit;
4729 tmpHit[i].host = s->serventHit.rhost[0];
4736 ChanHit *hit = chl->hit;
4739 if (hit->host.ip && !hit->dead){
4741 (!exID.isSame(hit->sessionID))
4744 && (!hit->firewalled)
4745 && (hit->numHops != 0)
4747 if ( (hit->rhost[0].ip == host1.ip)
4748 && hit->rhost[1].isValid()
4749 && (host2.ip != hit->rhost[1].ip)
4752 best[0].host = hit->rhost[1];
4755 if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
4757 best[0].host = hit->rhost[1];
4761 loop = (index / MAX_RESULTS) + 1;
4762 //prob = (float)1 / (float)loop;
4764 //rnd = (float)rand() / (float)RAND_MAX;
4765 rnd = rand() % base;
4766 if (hit->numHops == 1){
4768 if (tmpHit[index % MAX_RESULTS].numHops == 1){
4770 tmpHit[index % MAX_RESULTS] = *hit;
4771 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4775 tmpHit[index % MAX_RESULTS] = *hit;
4776 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4781 if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob) || rnd == 0){
4782 tmpHit[index % MAX_RESULTS] = *hit;
4783 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4789 // hit->host.toStr(tmp);
4790 // LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
4796 if (index > MAX_RESULTS){
4802 /* int use[MAX_RESULTS];
4803 memset(use, 0, sizeof(use));
4805 for (i = 0; i < cnt; i++){
4809 for (i = 0; i < cnt; i++){
4812 // LOG_DEBUG("%d",r);
4820 for (i = 0; i < cnt; i++){
4821 // LOG_DEBUG("%d", use[i]);
4822 best[use[i]] = tmpHit[i];
4825 int use[MAX_RESULTS];
4827 for (i = 0; i < cnt; i++) {
4828 use[i] = (i + seq) % cnt;
4831 for (i = 0; i < cnt; i++){
4832 // LOG_DEBUG("%d", use[i]);
4833 best[use[i]] = tmpHit[i];
4835 // for (i = 0; i < cnt; i++){
4837 // best[i].host.toStr(tmp);
4838 // LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);