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 // ------------------------------------------------
49 #include "chkMemoryLeak.h"
50 #define DEBUG_NEW new(__FILE__, __LINE__)
54 #include "win32/seh.h"
56 // -----------------------------------
57 char *Channel::srcTypes[]=
65 // -----------------------------------
66 char *Channel::statusMsgs[]=
85 bool isIndexTxt(ChanInfo *info)
90 info->contentType == ChanInfo::T_RAW &&
91 info->bitrate <= 32 &&
92 (len = strlen(info->name.cstr())) >= 9 &&
93 !memcmp(info->name.cstr(), "index", 5) &&
94 !memcmp(info->name.cstr()+len-4, ".txt", 4))
104 bool isIndexTxt(Channel *ch)
106 if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
112 int numMaxRelaysIndexTxt(Channel *ch)
114 return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
117 int canStreamIndexTxt(Channel *ch)
121 //
\8e©
\95ª
\82ª
\94z
\90M
\82µ
\82Ä
\82¢
\82é
\8fê
\8d\87\82Í
\8aÖ
\8cW
\82È
\82¢
122 if(!ch || ch->isBroadcasting())
125 ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
133 // -----------------------------------
134 void readXMLString(String &str, XML::Node *n, const char *arg)
137 p = n->findAttr(arg);
140 str.set(p,String::T_HTML);
141 str.convertTo(String::T_ASCII);
146 // -----------------------------------------------------------------------------
147 // Initialise the channel to its default settings of unallocated and reset.
148 // -----------------------------------------------------------------------------
149 Channel::Channel() : maxRelays(0)
153 channel_id = channel_count++;
155 // -----------------------------------------------------------------------------
156 void Channel::endThread(bool flg)
180 chanMgr->channellock.on();
181 chanMgr->deleteChannel(this);
182 chanMgr->channellock.off();
184 sys->endThread(&thread);
187 // -----------------------------------------------------------------------------
188 void Channel::resetPlayTime()
190 info.lastPlayStart = sys->getTime();
192 // -----------------------------------------------------------------------------
193 void Channel::setStatus(STATUS s)
197 bool wasPlaying = isPlaying();
203 info.status = ChanInfo::S_PLAY;
208 info.lastPlayEnd = sys->getTime();
209 info.status = ChanInfo::S_UNKNOWN;
212 if (isBroadcasting())
214 ChanHitList *chl = chanMgr->findHitListByID(info.id);
216 chanMgr->addHitList(info);
219 peercastApp->channelUpdate(&info);
224 // -----------------------------------------------------------------------------
225 // Reset channel and make it available
226 // -----------------------------------------------------------------------------
227 void Channel::reset()
240 stayConnected = false;
241 stealth = false; //JP-MOD
242 overrideMaxRelaysPerChannel = -1; //JP-MOD
243 bClap = false; //JP-MOD
247 skipCount = 0; //JP-EX
257 rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
269 lastTrackerUpdate = 0;
284 // -----------------------------------
285 void Channel::newPacket(ChanPacket &pack)
287 if (pack.type != ChanPacket::T_PCP)
289 rawData.writePacket(pack,true);
294 // -----------------------------------
295 bool Channel::checkIdle()
297 return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
300 // -----------------------------------
301 bool Channel::isFull()
303 // for PCRaw (relay) start.
306 int ret = canStreamIndexTxt(this);
313 // for PCRaw (relay) end.
315 //
\83`
\83\83\83\93\83l
\83\8b\8cÅ
\97L
\82Ì
\83\8a\83\8c\81[
\8fã
\8cÀ
\90Ý
\92è
\82ª
\82 \82é
\82©
318 return localRelays() >= maxRelays;
321 return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
324 // -----------------------------------
325 int Channel::localRelays()
327 return servMgr->numStreams(info.id,Servent::T_RELAY,true);
329 // -----------------------------------
330 int Channel::localListeners()
332 return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
335 // -----------------------------------
336 int Channel::totalRelays()
339 ChanHitList *chl = chanMgr->findHitListByID(info.id);
341 tot += chl->numHits();
344 // -----------------------------------
345 int Channel::totalListeners()
347 int tot = localListeners();
348 ChanHitList *chl = chanMgr->findHitListByID(info.id);
350 tot += chl->numListeners();
354 // -----------------------------------
355 int Channel::totalClaps() //JP-MOD
357 ChanHitList *chl = chanMgr->findHitListByID(info.id);
358 return chl ? chl->numClaps() : 0;
361 // -----------------------------------
362 void Channel::startGet()
364 srcType = SRC_PEERCAST;
366 info.srcProtocol = ChanInfo::SP_PCP;
369 sourceData = new PeercastSource();
373 // -----------------------------------
374 void Channel::startURL(const char *u)
380 stayConnected = true;
384 sourceData = new URLSource(u);
389 // -----------------------------------
390 void Channel::startStream()
393 thread.func = stream;
394 if (!sys->startThread(&thread))
398 // -----------------------------------
399 void Channel::sleepUntil(double time)
401 double sleepTime = time - (sys->getDTime()-startTime);
403 // LOG("sleep %g",sleepTime);
406 if (sleepTime > 60) sleepTime = 60;
408 double sleepMS = sleepTime*1000;
410 sys->sleep((int)sleepMS);
415 // -----------------------------------
416 void Channel::checkReadDelay(unsigned int len)
420 unsigned int time = (len*1000)/((info.bitrate*1024)/8);
428 // -----------------------------------
429 THREAD_PROC Channel::streamMain(ThreadInfo *thread)
433 Channel *ch = (Channel *)thread->data;
435 LOG_CHANNEL("Channel started");
437 while (thread->active && !peercastInst->isQuitting && !thread->finish)
439 ChanHitList *chl = chanMgr->findHitList(ch->info);
441 chanMgr->addHitList(ch->info);
443 ch->sourceData->stream(ch);
445 LOG_CHANNEL("Channel stopped");
448 if (!ch->stayConnected)
450 thread->active = false;
454 if (!ch->info.lastPlayEnd)
455 ch->info.lastPlayEnd = sys->getTime();
457 unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
459 LOG_DEBUG("Channel sleeping for %d seconds",diff);
460 for(unsigned int i=0; i<diff; i++)
462 if (ch->info.lastPlayEnd == 0) // reconnected
464 if (!thread->active || peercastInst->isQuitting){
465 thread->active = false;
473 LOG_DEBUG("thread.active = %d, thread.finish = %d",
474 ch->thread.active, ch->thread.finish);
476 if (!thread->finish){
477 ch->endThread(false);
480 ch->finthread = new ThreadInfo();
481 ch->finthread->func = waitFinish;
482 ch->finthread->data = ch;
483 sys->startThread(ch->finthread);
491 // -----------------------------------
492 THREAD_PROC Channel::stream(ThreadInfo *thread)
494 SEH_THREAD(streamMain, Channel::stream);
497 // -----------------------------------
498 THREAD_PROC Channel::waitFinishMain(ThreadInfo *thread)
500 Channel *ch = (Channel*)thread->data;
501 LOG_DEBUG("Wait channel finish");
503 while(!(ch->thread.finish) && !thread->finish){
507 if (ch->thread.finish){
508 LOG_DEBUG("channel finish");
511 LOG_DEBUG("channel restart");
518 // -----------------------------------
519 THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
521 SEH_THREAD(waitFinishMain, Channel::waitFinish);
525 // -----------------------------------
526 bool Channel::acceptGIV(ClientSocket *givSock)
535 // -----------------------------------
536 void Channel::connectFetch()
538 sock = sys->createSocket();
541 throw StreamException("Can`t create socket");
543 if (sourceHost.tracker || sourceHost.yp)
545 sock->setReadTimeout(30000);
546 sock->setWriteTimeout(30000);
547 LOG_CHANNEL("Channel using longer timeouts");
549 sock->setReadTimeout(5000);
550 sock->setWriteTimeout(5000);
553 sock->open(sourceHost.host);
558 // -----------------------------------
559 int Channel::handshakeFetch()
562 info.id.toStr(idStr);
565 servMgr->sessionID.toStr(sidStr);
567 sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
568 sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
569 sock->writeLineF("%s %d",PCX_HS_PCP,1);
570 sock->writeLineF("%s %d",PCX_HS_PORT,servMgr->serverHost.port);
576 int r = http.readResponse();
578 LOG_CHANNEL("Got response: %d",r);
580 while (http.nextHeader())
582 char *arg = http.getArgStr();
586 if (http.isHeader(PCX_HS_POS))
587 streamPos = atoi(arg);
589 Servent::readICYHeader(http, info, NULL, 0);
591 LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
594 if ((r != 200) && (r != 503))
597 if (!servMgr->keepDownstreams) {
598 if (rawData.getLatestPos() > streamPos)
602 AtomStream atom(*sock);
606 Host rhost = sock->host;
608 if (info.srcProtocol == ChanInfo::SP_PCP)
610 // don`t need PCP_CONNECT here
611 Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
614 if (r == 503) return 503;
619 // -----------------------------------
620 void PeercastSource::stream(Channel *ch)
624 bool next_yp = false;
625 bool tracker_check = (ch->trackerHit.host.ip != 0);
627 int keepDownstreamTime = 7;
629 if (isIndexTxt(&ch->info))
630 keepDownstreamTime = 30;
632 ch->lastStopTime = 0;
635 while (ch->thread.active)
637 ch->skipCount = 0; //JP-EX
638 ch->lastSkipTime = 0;
640 ChanHitList *chl = NULL;
642 ch->sourceHost.init();
644 if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
645 ch->lastIdleTime = sys->getTime();
646 ch->setStatus(Channel::S_IDLE);
648 ch->lastSkipTime = 0;
652 if (!servMgr->keepDownstreams && !ch->bumped) {
653 ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
656 ch->setStatus(Channel::S_SEARCHING);
657 LOG_CHANNEL("Channel searching for hit..");
663 ch->sock = ch->pushSock;
665 ch->sourceHost.host = ch->sock->host;
669 chanMgr->hitlistlock.on();
671 chl = chanMgr->findHitList(ch->info);
677 if (!ch->sourceHost.host.ip){
679 chs.matchHost = servMgr->serverHost;
680 chs.waitDelay = MIN_RELAY_RETRY;
681 chs.excludeID = servMgr->sessionID;
682 if (chl->pickSourceHits(chs)){
683 ch->sourceHost = chs.best[0];
684 LOG_DEBUG("use local hit");
688 // else find global hit
689 if (!ch->sourceHost.host.ip)
692 chs.waitDelay = MIN_RELAY_RETRY;
693 chs.excludeID = servMgr->sessionID;
694 if (chl->pickSourceHits(chs)){
695 ch->sourceHost = chs.best[0];
696 LOG_DEBUG("use global hit");
701 // else find local tracker
702 if (!ch->sourceHost.host.ip)
705 chs.matchHost = servMgr->serverHost;
706 chs.waitDelay = MIN_TRACKER_RETRY;
707 chs.excludeID = servMgr->sessionID;
708 chs.trackersOnly = true;
709 if (chl->pickSourceHits(chs)){
710 ch->sourceHost = chs.best[0];
711 LOG_DEBUG("use local tracker");
715 // else find global tracker
716 if (!ch->sourceHost.host.ip)
719 chs.waitDelay = MIN_TRACKER_RETRY;
720 chs.excludeID = servMgr->sessionID;
721 chs.trackersOnly = true;
722 if (chl->pickSourceHits(chs)){
723 ch->sourceHost = chs.best[0];
724 tracker_check = true;
725 ch->trackerHit = chs.best[0];
726 LOG_DEBUG("use global tracker");
731 unsigned int ctime = sys->getTime();
732 if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
733 if (ch->trackerHit.lastContact + 30 < ctime){
734 ch->sourceHost = ch->trackerHit;
735 ch->trackerHit.lastContact = ctime;
736 LOG_DEBUG("use saved tracker");
741 chanMgr->hitlistlock.off();
743 if (servMgr->keepDownstreams && ch->lastStopTime
744 && ch->lastStopTime < sys->getTime() - keepDownstreamTime)
746 ch->lastStopTime = 0;
747 LOG_DEBUG("------------ disconnect all downstreams");
749 MemoryStream mem(pack.data,sizeof(pack.data));
750 AtomStream atom(mem);
751 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
753 pack.type = ChanPacket::T_PCP;
756 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
758 chanMgr->hitlistlock.on();
759 ChanHitList *hl = chanMgr->findHitList(ch->info);
761 hl->clearHits(false);
763 chanMgr->hitlistlock.off();
766 // no trackers found so contact YP
767 if (!tracker_check && !ch->sourceHost.host.ip)
770 if (servMgr->rootHost.isEmpty())
776 if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
779 unsigned int ctime=sys->getTime();
780 if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
782 ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
783 ch->sourceHost.yp = true;
784 chanMgr->lastYPConnect=ctime;
792 // no trackers found so contact YP2
793 if (!tracker_check && !ch->sourceHost.host.ip)
796 if (servMgr->rootHost2.isEmpty())
799 if (numYPTries2 >= 3)
802 unsigned int ctime=sys->getTime();
803 if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
805 ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
806 ch->sourceHost.yp = true;
807 chanMgr->lastYPConnect2=ctime;
814 if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
818 }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
820 if (!ch->sourceHost.host.ip)
822 LOG_ERROR("Channel giving up");
823 ch->setStatus(Channel::S_ERROR);
827 if (ch->sourceHost.yp)
829 LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
832 LOG_CHANNEL("Channel found hit");
837 if (ch->sourceHost.host.ip)
839 bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
842 //if (ch->sourceHost.tracker)
843 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
846 ch->sourceHost.host.toStr(ipstr);
849 if (ch->sourceHost.tracker)
851 else if (ch->sourceHost.yp)
858 ch->setStatus(Channel::S_CONNECTING);
859 ch->sourceHost.lastContact = sys->getTime();
863 LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
867 error = ch->handshakeFetch();
873 throw StreamException("Handshake error");
874 if (ch->sourceHost.tracker) connFailCnt = 0;
876 if (servMgr->autoMaxRelaySetting) //JP-EX
878 double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
879 if ((unsigned int)setMaxRelays == 0)
880 servMgr->maxRelays = 1;
881 else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
882 servMgr->maxRelays = servMgr->autoMaxRelaySetting;
884 servMgr->maxRelays = (unsigned int)setMaxRelays;
887 ch->sourceStream = ch->createSource();
889 error = ch->readStream(*ch->sock,ch->sourceStream);
891 throw StreamException("Stream error");
893 error = 0; // no errors, closing normally.
894 // ch->setStatus(Channel::S_CLOSING);
895 ch->setStatus(Channel::S_IDLE);
897 LOG_CHANNEL("Channel closed normally");
898 }catch(StreamException &e)
900 ch->setStatus(Channel::S_ERROR);
901 LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
902 if (!servMgr->allowConnectPCST) //JP-EX
904 if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
905 ch->thread.active = false;
907 //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
908 if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
909 chanMgr->deadHit(ch->sourceHost);
910 if (ch->sourceHost.tracker && error == -1) {
911 LOG_ERROR("can't connect to tracker");
916 unsigned int ctime = sys->getTime();
917 if (ch->rawData.lastWriteTime) {
918 ch->lastStopTime = ch->rawData.lastWriteTime;
919 if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
920 ch->lastStopTime = ctime;
923 if (tracker_check && ch->sourceHost.tracker)
924 ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
926 // broadcast source host
927 if (!got503 && !error && ch->sourceHost.host.ip) { // if closed normally
929 MemoryStream mem(pack.data,sizeof(pack.data));
930 AtomStream atom(mem);
931 ch->sourceHost.writeAtoms(atom, ch->info.id);
933 pack.type = ChanPacket::T_PCP;
936 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
937 LOG_DEBUG("stream: broadcast sourceHost");
940 // broadcast quit to any connected downstream servents
941 if (!servMgr->keepDownstreams || !got503 && (ch->sourceHost.tracker || !error)) {
943 MemoryStream mem(pack.data,sizeof(pack.data));
944 AtomStream atom(mem);
945 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
947 pack.type = ChanPacket::T_PCP;
950 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
951 LOG_DEBUG("------------ broadcast quit to all downstreams");
953 chanMgr->hitlistlock.on();
954 ChanHitList *hl = chanMgr->findHitList(ch->info);
956 hl->clearHits(false);
958 chanMgr->hitlistlock.off();
962 if (ch->sourceStream)
968 ch->sourceStream->updateStatus(ch);
969 ch->sourceStream->flush(*ch->sock);
971 }catch(StreamException &)
973 ChannelStream *cs = ch->sourceStream;
974 ch->sourceStream = NULL;
988 LOG_ERROR("Channel not found");
990 if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
991 chanMgr->hitlistlock.on();
992 ChanHitList *hl = chanMgr->findHitList(ch->info);
996 chanMgr->hitlistlock.off();
998 if(!isIndexTxt(&ch->info)) // for PCRaw (popup)
999 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
1007 ch->lastIdleTime = sys->getTime();
1008 ch->setStatus(Channel::S_IDLE);
1009 ch->skipCount = 0; //JP-EX
1010 ch->lastSkipTime = 0;
1011 while ((ch->checkIdle()) && (ch->thread.active))
1020 // -----------------------------------
1021 void Channel::startICY(ClientSocket *cs, SRC_TYPE st)
1025 cs->setReadTimeout(0); // stay connected even when theres no data coming through
1027 info.srcProtocol = ChanInfo::SP_HTTP;
1029 streamIndex = ++chanMgr->icyIndex;
1031 sourceData = new ICYSource();
1035 // -----------------------------------
1036 static char *nextMetaPart(char *str,char delim)
1049 // -----------------------------------
1050 static void copyStr(char *to,char *from,int max)
1053 while ((c=*from++) && (--max))
1060 // -----------------------------------
1061 void Channel::processMp3Metadata(char *str)
1063 ChanInfo newInfo = info;
1068 char *arg = nextMetaPart(cmd,'=');
1072 char *next = nextMetaPart(arg,';');
1074 if (strcmp(cmd,"StreamTitle")==0)
1076 newInfo.track.title.setUnquote(arg,String::T_ASCII);
1077 newInfo.track.title.convertTo(String::T_UNICODE);
1079 }else if (strcmp(cmd,"StreamUrl")==0)
1081 newInfo.track.contact.setUnquote(arg,String::T_ASCII);
1082 newInfo.track.contact.convertTo(String::T_UNICODE);
1089 updateInfo(newInfo);
1092 // -----------------------------------
1093 XML::Node *ChanHit::createXML()
1099 return new XML::Node("host ip=\"%s\" hops=\"%d\" listeners=\"%d\" relays=\"%d\" uptime=\"%d\" push=\"%d\" relay=\"%d\" direct=\"%d\" cin=\"%d\" stable=\"%d\" version=\"%d\" update=\"%d\" tracker=\"%d\"",
1111 sys->getTime()-time,
1117 // -----------------------------------
1118 XML::Node *ChanHitList::createXML(bool addHits)
1120 XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
1127 sys->getTime()-newestHit()
1136 hn->add(h->createXML());
1144 // -----------------------------------
1145 XML::Node *Channel::createRelayXML(bool showStat)
1148 ststr = getStatusStr();
1150 if ((status == S_RECEIVING) || (status == S_BROADCASTING))
1153 ChanHitList *chl = chanMgr->findHitList(info);
1155 return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
1158 (chl!=NULL)?chl->numHits():0,
1163 // -----------------------------------
1164 void ChanMeta::fromXML(XML &xml)
1166 MemoryStream tout(data,MAX_DATALEN);
1171 // -----------------------------------
1172 void ChanMeta::fromMem(void *p, int l)
1177 // -----------------------------------
1178 void ChanMeta::addMem(void *p, int l)
1180 if ((len+l) <= MAX_DATALEN)
1182 memcpy(data+len,p,l);
1186 // -----------------------------------
1187 void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
1189 unsigned int ctime = sys->getTime();
1191 if (((ctime-lastTrackerUpdate) > 30) || (force))
1195 MemoryStream mem(pack.data,sizeof(pack));
1197 AtomStream atom(mem);
1201 ChanHitList *chl = chanMgr->findHitListByID(info.id);
1203 throw StreamException("Broadcast channel has no hitlist");
1205 int numListeners = stealth ? -1 : totalListeners(); //JP-MOD
\83\8a\83X
\83i
\81[
\90\94\89B
\95Á
\8b@
\94\
1206 int numRelays = stealth ? -1 : totalRelays(); //JP-MOD
\83\8a\83\8c\81[
\90\94\89B
\95Á
\8b@
\94\
1208 unsigned int oldp = rawData.getOldestPos();
1209 unsigned int newp = rawData.getLatestPos();
1211 hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
1214 if (version_ex == 0)
1216 atom.writeParent(PCP_BCST,8);
1219 atom.writeParent(PCP_BCST,10);
1221 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
1222 atom.writeChar(PCP_BCST_HOPS,0);
1223 atom.writeChar(PCP_BCST_TTL,11);
1224 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1225 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1226 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1230 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1231 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1233 atom.writeParent(PCP_CHAN,4);
1234 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1235 atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
1236 info.writeInfoAtoms(atom);
1237 info.writeTrackAtoms(atom);
1238 hit.writeAtoms(atom,info.id);
1242 pack.type = ChanPacket::T_PCP;
1246 int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
1250 LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
1251 lastTrackerUpdate = ctime;
1256 // -----------------------------------
1257 bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
1260 && (!cid.isSet() || info.id.isSame(cid))
1261 && (!sid.isSet() || !remoteID.isSame(sid))
1264 return sourceStream->sendPacket(pack,did);
1269 // -----------------------------------
1270 void Channel::updateInfo(ChanInfo &newInfo)
1272 if (info.update(newInfo))
1274 if (isBroadcasting())
1276 unsigned int ctime = sys->getTime();
1277 if ((ctime-lastMetaUpdate) > 30)
1279 lastMetaUpdate = ctime;
1283 MemoryStream mem(pack.data,sizeof(pack));
1285 AtomStream atom(mem);
1287 if (version_ex == 0)
1289 atom.writeParent(PCP_BCST,8);
1292 atom.writeParent(PCP_BCST,10);
1294 atom.writeChar(PCP_BCST_HOPS,0);
1295 atom.writeChar(PCP_BCST_TTL,7);
1296 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
1297 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1298 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1299 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1302 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1303 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1305 atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
1306 atom.writeParent(PCP_CHAN,3);
1307 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1308 info.writeInfoAtoms(atom);
1309 info.writeTrackAtoms(atom);
1312 pack.type = ChanPacket::T_PCP;
1315 servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
1317 broadcastTrackerUpdate(noID);
1321 ChanHitList *chl = chanMgr->findHitList(info);
1325 peercastApp->channelUpdate(&info);
1330 // -----------------------------------
1331 ChannelStream *Channel::createSource()
1333 // if (servMgr->relayBroadcast)
1334 // chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
1337 ChannelStream *source=NULL;
1339 if (info.srcProtocol == ChanInfo::SP_PEERCAST)
1341 LOG_CHANNEL("Channel is Peercast");
1342 if (servMgr->allowConnectPCST) //JP-EX
1343 source = new PeercastStream();
1345 throw StreamException("Channel is not allowed");
1347 else if (info.srcProtocol == ChanInfo::SP_PCP)
1349 LOG_CHANNEL("Channel is PCP");
1350 PCPStream *pcp = new PCPStream(remoteID);
1353 else if (info.srcProtocol == ChanInfo::SP_MMS)
1355 LOG_CHANNEL("Channel is MMS");
1356 source = new MMSStream();
1359 switch(info.contentType)
1361 case ChanInfo::T_MP3:
1362 LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
1363 source = new MP3Stream();
1365 case ChanInfo::T_NSV:
1366 LOG_CHANNEL("Channel is NSV");
1367 source = new NSVStream();
1369 case ChanInfo::T_WMA:
1370 case ChanInfo::T_WMV:
1371 throw StreamException("Channel is WMA/WMV - but not MMS");
1373 case ChanInfo::T_OGG:
1374 case ChanInfo::T_OGM:
1375 LOG_CHANNEL("Channel is OGG");
1376 source = new OGGStream();
1378 case ChanInfo::T_FLV:
1379 LOG_CHANNEL("Channel is FLV");
1380 source = new FLVStream();
1383 LOG_CHANNEL("Channel is Raw");
1384 source = new RawStream();
1389 source->parent = this;
1393 // ------------------------------------------
1394 void ChannelStream::updateStatus(Channel *ch)
1397 if (getStatus(ch,pack))
1399 if (!ch->isBroadcasting())
1403 int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
1404 LOG_CHANNEL("Sent channel status update to %d clients",cnt);
1409 // ------------------------------------------
1410 bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
1412 unsigned int ctime = sys->getTime();
1414 if ((ch->isPlaying() == isPlaying)){
1415 if ((ctime-lastUpdate) < 10){
1419 if ((ctime-lastCheckTime) < 5){
1422 lastCheckTime = ctime;
1425 ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
1430 /* int newLocalListeners = ch->localListeners();
1431 int newLocalRelays = ch->localRelays();
1435 (numListeners != newLocalListeners)
1436 || (numRelays != newLocalRelays)
1437 || (ch->isPlaying() != isPlaying)
1438 || (servMgr->getFirewall() != fwState)
1439 || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1441 && ((ctime-lastUpdate) > 10)
1445 numListeners = newLocalListeners;
1446 numRelays = newLocalRelays;
1447 isPlaying = ch->isPlaying();
1448 fwState = servMgr->getFirewall();
1453 hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
1454 hit.tracker = ch->isBroadcasting();*/
1456 int newLocalListeners = ch->localListeners();
1457 int newLocalRelays = ch->localRelays();
1459 unsigned int oldp = ch->rawData.getOldestPos();
1460 unsigned int newp = ch->rawData.getLatestPos();
1464 // LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
1466 hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
1468 if(!(ch->info.ppFlags & ServMgr::bcstClap))
1470 hit.initLocal_pp(ch->stealth, ch->bClap ? 1 : 0);
1472 hit.tracker = ch->isBroadcasting();
1474 if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1475 || (newLocalListeners != numListeners)
1476 || (newLocalRelays != numRelays)
1477 || (ch->isPlaying() != isPlaying)
1478 || (servMgr->getFirewall() != fwState)
1479 || (ch->chDisp.relay != hit.relay)
1480 || (ch->chDisp.relayfull != hit.relayfull)
1481 || (ch->chDisp.chfull != hit.chfull)
1482 || (ch->chDisp.ratefull != hit.ratefull)
1483 || (ch->bClap && ((ctime-lastClapped) > 60)) //JP-MOD
1485 numListeners = newLocalListeners;
1486 numRelays = newLocalRelays;
1487 isPlaying = ch->isPlaying();
1488 fwState = servMgr->getFirewall();
1491 if(ch->bClap){ //JP-MOD
1492 lastClapped = ctime;
1498 if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
1499 ch->stayConnected = true;
1501 if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
1502 ch->stayConnected = false;
1504 MemoryStream pmem(pack.data,sizeof(pack.data));
1505 AtomStream atom(pmem);
1510 if (version_ex == 0)
1512 atom.writeParent(PCP_BCST,8);
1515 atom.writeParent(PCP_BCST,10);
1517 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
1518 atom.writeChar(PCP_BCST_HOPS,0);
1519 atom.writeChar(PCP_BCST_TTL,11);
1520 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1521 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1522 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1525 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1526 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1528 atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
1529 hit.writeAtoms(atom,noID);
1531 pack.len = pmem.pos;
1532 pack.type = ChanPacket::T_PCP;
1537 // -----------------------------------
1538 bool Channel::checkBump()
1540 unsigned int maxIdleTime = 30;
1541 if (isIndexTxt(this)) maxIdleTime = 60;
1543 if (!isBroadcasting() && (!sourceHost.tracker))
1544 if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > maxIdleTime))
1546 LOG_ERROR("Channel Auto bumped");
1558 // -----------------------------------
1559 int Channel::readStream(Stream &in,ChannelStream *source)
1567 source->readHeader(in,this);
1569 peercastApp->channelStart(&info);
1571 rawData.lastWriteTime = 0;
1573 bool wasBroadcasting=false;
1575 unsigned int receiveStartTime = 0;
1577 unsigned int ptime = 0;
1578 unsigned int upsize = 0;
1582 while (thread.active && !peercastInst->isQuitting)
1586 LOG_DEBUG("Channel idle");
1592 LOG_DEBUG("Channel bumped");
1600 LOG_DEBUG("Channel eof");
1606 error = source->readPacket(in,this);
1611 //if (rawData.writePos > 0)
1612 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1614 if (isBroadcasting())
1616 if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
1620 broadcastTrackerUpdate(noID);
1622 wasBroadcasting = true;
1626 /* if (status != Channel::S_RECEIVING){
1627 receiveStartTime = sys->getTime();
1628 } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
1629 chanMgr->hitlistlock.on();
1630 ChanHitList *hl = chanMgr->findHitList(info);
1632 hl->clearHits(true);
1634 chanMgr->hitlistlock.off();
1635 receiveStartTime = 0;
1637 setStatus(Channel::S_RECEIVING);
1640 //source->updateStatus(this);
1643 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1644 source->updateStatus(this);
1646 unsigned int t = sys->getTime();
1649 upsize = Servent::MAX_OUTWARD_SIZE;
1652 unsigned int len = source->flushUb(in, upsize);
1657 }catch(StreamException &e)
1659 LOG_ERROR("readStream: %s",e.msg);
1663 if (!servMgr->keepDownstreams) {
1664 if (status == Channel::S_RECEIVING){
1665 chanMgr->hitlistlock.on();
1666 ChanHitList *hl = chanMgr->findHitList(info);
1668 hl->clearHits(false);
1670 chanMgr->hitlistlock.off();
1674 // setStatus(S_CLOSING);
1677 if (wasBroadcasting)
1681 broadcastTrackerUpdate(noID,true);
1684 peercastApp->channelStop(&info);
1686 source->readEnd(in,this);
1691 // -----------------------------------
1692 void PeercastStream::readHeader(Stream &in,Channel *ch)
1694 if (in.readTag() != 'PCST')
1695 throw StreamException("Not PeerCast stream");
1698 // -----------------------------------
1699 void PeercastStream::readEnd(Stream &,Channel *)
1703 // -----------------------------------
1704 int PeercastStream::readPacket(Stream &in,Channel *ch)
1710 pack.readPeercast(in);
1712 MemoryStream mem(pack.data,pack.len);
1716 case ChanPacket::T_HEAD:
1718 ch->headPack = pack;
1719 pack.pos = ch->streamPos;
1720 ch->newPacket(pack);
1721 ch->streamPos+=pack.len;
1723 case ChanPacket::T_DATA:
1724 pack.pos = ch->streamPos;
1725 ch->newPacket(pack);
1726 ch->streamPos+=pack.len;
1728 case ChanPacket::T_META:
1729 ch->insertMeta.fromMem(pack.data,pack.len);
1735 XML::Node *n = xml.findNode("channel");
1738 ChanInfo newInfo = ch->info;
1739 newInfo.updateFromXML(n);
1740 ChanHitList *chl = chanMgr->findHitList(ch->info);
1742 newInfo.updateFromXML(n);
1743 ch->updateInfo(newInfo);
1749 case ChanPacket::T_SYNC:
1751 unsigned int s = mem.readLong();
1752 if ((s-ch->syncPos) != 1)
1754 LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
1757 ch->info.numSkips++;
1758 if (ch->info.numSkips>50)
1759 throw StreamException("Bumped - Too many skips");
1774 // -----------------------------------
1775 void ChannelStream::readRaw(Stream &in, Channel *ch)
1779 const int readLen = 8192;
1781 pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
1782 in.read(pack.data,pack.len);
1783 ch->newPacket(pack);
1784 ch->checkReadDelay(pack.len);
1786 ch->streamPos+=pack.len;
1789 // ------------------------------------------
1790 void RawStream::readHeader(Stream &,Channel *)
1794 // ------------------------------------------
1795 int RawStream::readPacket(Stream &in,Channel *ch)
1801 // ------------------------------------------
1802 void RawStream::readEnd(Stream &,Channel *)
1808 // -----------------------------------
1809 void ChanPacket::init(ChanPacketv &p)
1813 if (len > MAX_DATALEN)
1814 throw StreamException("Packet data too large");
1818 priority = p.priority;
1819 memcpy(data, p.data, len);
1821 // -----------------------------------
1822 void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
1825 if (l > MAX_DATALEN)
1826 throw StreamException("Packet data too large");
1833 // -----------------------------------
1834 void ChanPacket::writeRaw(Stream &out)
1836 out.write(data,len);
1838 // -----------------------------------
1839 void ChanPacket::writePeercast(Stream &out)
1841 unsigned int tp = 0;
1844 case T_HEAD: tp = 'HEAD'; break;
1845 case T_META: tp = 'META'; break;
1846 case T_DATA: tp = 'DATA'; break;
1849 if (type != T_UNKNOWN)
1852 out.writeShort(len);
1854 out.write(data,len);
1857 // -----------------------------------
1858 void ChanPacket::readPeercast(Stream &in)
1860 unsigned int tp = in.readTag();
1864 case 'HEAD': type = T_HEAD; break;
1865 case 'DATA': type = T_DATA; break;
1866 case 'META': type = T_META; break;
1867 default: type = T_UNKNOWN;
1869 len = in.readShort();
1871 if (len > MAX_DATALEN)
1872 throw StreamException("Bad ChanPacket");
1875 // -----------------------------------
1876 int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
1886 for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
1888 //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
1889 ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
1890 if (src->type & accept)
1892 if (src->pos >= reqPos)
1895 //packets[writePos++] = *src;
1896 packets[writePos++].init(*src);
1905 return lastPos-firstPos;
1908 // -----------------------------------
1909 bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
1916 unsigned int bound = packets[0].len * ChanPacketBuffer::MAX_PACKETS * 2; // max packets to wait
1917 unsigned int fpos = getFirstDataPos();
1918 unsigned int lpos = getLatestPos();
1919 if ((spos < fpos && fpos <= lpos && spos != getStreamPosEnd(lastPos)) // --s-----f---l--
1920 || (spos < fpos && lpos < fpos && spos > lpos + bound) // -l-------s--f--
1921 || (spos > lpos && lpos >= fpos && spos - lpos > bound)) // --f---l------s-
1925 for(unsigned int i=firstPos; i<=lastPos; i++)
1927 //ChanPacket &p = packets[i%MAX_PACKETS];
1928 ChanPacketv &p = packets[i%MAX_PACKETS];
1929 if (p.pos >= spos && p.pos - spos <= bound)
1940 // -----------------------------------
1941 unsigned int ChanPacketBuffer::getLatestPos()
1946 return getStreamPos(lastPos);
1949 // -----------------------------------
1950 unsigned int ChanPacketBuffer::getFirstDataPos()
1954 for(unsigned int i=firstPos; i<=lastPos; i++)
1956 if (packets[i%MAX_PACKETS].type == ChanPacket::T_DATA)
1957 return packets[i%MAX_PACKETS].pos;
1961 // -----------------------------------
1962 unsigned int ChanPacketBuffer::getOldestPos()
1967 return getStreamPos(firstPos);
1970 // -----------------------------------
1971 unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos)
1973 unsigned int min = getStreamPos(safePos);
1974 unsigned int max = getStreamPos(lastPos);
1985 // -----------------------------------
1986 unsigned int ChanPacketBuffer::getStreamPos(unsigned int index)
1988 return packets[index%MAX_PACKETS].pos;
1990 // -----------------------------------
1991 unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index)
1993 return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
1995 // -----------------------------------
1996 bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
2000 if (servMgr->keepDownstreams) {
2001 unsigned int lpos = getLatestPos();
2002 unsigned int diff = pack.pos - lpos;
2003 if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
2004 if (lpos && (diff == 0 || diff > 0xfff00000)) {
2005 LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
2006 lastSkipTime = sys->getTime();
2011 if (willSkip()) // too far behind
2013 lastSkipTime = sys->getTime();
2019 pack.sync = writePos;
2020 packets[writePos%MAX_PACKETS].init(pack);
2022 // LOG_DEBUG("packet.len = %d",pack.len);
2028 if (writePos >= MAX_PACKETS)
2029 firstPos = writePos-MAX_PACKETS;
2033 if (writePos >= NUM_SAFEPACKETS)
2034 safePos = writePos - NUM_SAFEPACKETS;
2041 lastWriteTime = sys->getTime();
2049 // -----------------------------------
2050 void ChanPacketBuffer::readPacket(ChanPacket &pack)
2053 unsigned int tim = sys->getTime();
2055 if (readPos < firstPos)
2056 throw StreamException("Read too far behind");
2058 while (readPos >= writePos)
2061 if ((sys->getTime() - tim) > 30)
2062 throw TimeoutException();
2065 pack.init(packets[readPos%MAX_PACKETS]);
2070 // -----------------------------------
2071 void ChanPacketBuffer::readPacketPri(ChanPacket &pack)
2073 unsigned int tim = sys->getTime();
2075 if (readPos < firstPos)
2076 throw StreamException("Read too far behind");
2078 while (readPos >= writePos)
2081 if ((sys->getTime() - tim) > 30)
2082 throw TimeoutException();
2085 ChanPacketv *best = &packets[readPos % MAX_PACKETS];
2086 for (unsigned int i = readPos + 1; i < writePos; i++) {
2087 if (packets[i % MAX_PACKETS].priority > best->priority)
2088 best = &packets[i % MAX_PACKETS];
2091 best->init(packets[readPos % MAX_PACKETS]);
2096 // -----------------------------------
2097 bool ChanPacketBuffer::willSkip()
2099 return ((writePos-readPos) >= MAX_PACKETS);
2102 // -----------------------------------
2103 void Channel::getStreamPath(char *str)
2109 sprintf(str,"/stream/%s%s",idStr,info.getTypeExt());
2114 // -----------------------------------
2115 void ChanMgr::startSearch(ChanInfo &info)
2122 searchActive = true;
2124 // -----------------------------------
2125 void ChanMgr::quit()
2127 LOG_DEBUG("ChanMgr is quitting..");
2130 // -----------------------------------
2131 int ChanMgr::numIdleChannels()
2134 Channel *ch = channel;
2138 if (ch->thread.active)
2139 if (ch->status == Channel::S_IDLE)
2145 // -----------------------------------
2146 void ChanMgr::closeOldestIdle()
2148 unsigned int idleTime = (unsigned int)-1;
2149 Channel *ch = channel,*oldest=NULL;
2153 if (ch->thread.active)
2154 if (ch->status == Channel::S_IDLE)
2155 if (ch->lastIdleTime < idleTime)
2158 idleTime = ch->lastIdleTime;
2164 oldest->thread.active = false;
2167 // -----------------------------------
2168 void ChanMgr::closeAll()
2170 Channel *ch = channel;
2173 if (ch->thread.active)
2174 ch->thread.shutdown();
2178 // -----------------------------------
2179 Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
2181 Channel *ch = channel;
2185 if (ch->info.matchNameID(info))
2192 // -----------------------------------
2193 Channel *ChanMgr::findChannelByName(const char *n)
2195 Channel *ch = channel;
2199 if (stricmp(ch->info.name,n)==0)
2206 // -----------------------------------
2207 Channel *ChanMgr::findChannelByIndex(int index)
2210 Channel *ch = channel;
2223 // -----------------------------------
2224 Channel *ChanMgr::findChannelByMount(const char *str)
2226 Channel *ch = channel;
2230 if (strcmp(ch->mount,str)==0)
2237 // -----------------------------------
2238 Channel *ChanMgr::findChannelByID(GnuID &id)
2240 Channel *ch = channel;
2244 if (ch->info.id.isSame(id))
2250 // -----------------------------------
2251 Channel *ChanMgr::findChannelByChannelID(int id)
2254 Channel *ch = channel;
2257 if (ch->isActive()){
2258 if (ch->channel_id == id){
2266 // -----------------------------------
2267 int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
2270 Channel *ch = channel;
2274 if (ch->info.match(info))
2284 // -----------------------------------
2285 int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
2288 Channel *ch = channel;
2292 if (ch->status == status)
2302 // -----------------------------------
2303 Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
2305 Channel *c = chanMgr->createChannel(info,NULL);
2308 c->stayConnected = stayConnected;
2314 // -----------------------------------
2315 Channel *ChanMgr::findAndRelay(ChanInfo &info)
2318 info.id.toStr(idStr);
2319 LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
2321 if(!isIndexTxt(&info)) // for PCRaw (popup)
2322 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
2327 WLockBlock wb(&(chanMgr->channellock));
2331 c = findChannelByNameID(info);
2335 c = chanMgr->createChannel(info,NULL);
2338 c->setStatus(Channel::S_SEARCHING);
2341 } else if (!(c->thread.active)){
2342 c->thread.active = true;
2343 c->thread.finish = false;
2344 c->info.lastPlayStart = 0; // reconnect
2345 c->info.lastPlayEnd = 0;
2347 c->finthread->finish = true;
2348 c->finthread = NULL;
2350 if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
2351 c->setStatus(Channel::S_SEARCHING);
2358 for(int i=0; i<600; i++) // search for 1 minute.
2363 c = findChannelByNameID(info);
2367 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
2371 if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
2381 // -----------------------------------
2388 currFindAndPlayChannel.clear();
2390 broadcastMsg.clear();
2391 broadcastMsgInterval=10;
2393 broadcastID.generate(PCP_BROADCAST_FLAGS);
2398 icyMetaInterval = 8192;
2399 maxRelaysPerChannel = 1;
2403 minBroadcastTTL = 1;
2404 maxBroadcastTTL = 7;
2406 pushTimeout = 60; // 1 minute
2407 pushTries = 5; // 5 times
2408 maxPushHops = 8; // max 8 hops away
2409 maxUptime = 0; // 0 = none
2411 prefetchTime = 10; // n seconds
2413 hostUpdateInterval = 120; // 2 minutes
2425 // -----------------------------------
2426 bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
2429 if (var == "numHitLists")
2430 sprintf(buf,"%d",numHitLists());
2432 else if (var == "numChannels")
2433 sprintf(buf,"%d",numChannels());
2434 else if (var == "djMessage")
2436 String utf8 = broadcastMsg;
2437 utf8.convertTo(String::T_UNICODESAFE);
2438 strcpy(buf,utf8.cstr());
2440 else if (var == "icyMetaInterval")
2441 sprintf(buf,"%d",icyMetaInterval);
2442 else if (var == "maxRelaysPerChannel")
2443 sprintf(buf,"%d",maxRelaysPerChannel);
2444 else if (var == "hostUpdateInterval")
2445 sprintf(buf,"%d",hostUpdateInterval);
2446 else if (var == "broadcastID")
2447 broadcastID.toStr(buf);
2453 out.writeString(buf);
2457 // -----------------------------------
2458 bool Channel::writeVariable(Stream &out, const String &var, int index)
2469 utf8.convertTo(String::T_UNICODESAFE);
2470 strcpy(buf,utf8.cstr());
2472 }else if (var == "bitrate")
2474 sprintf(buf,"%d",info.bitrate);
2476 }else if (var == "srcrate")
2480 unsigned int tot = sourceData->getSourceRate();
2481 sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
2485 }else if (var == "genre")
2488 utf8.convertTo(String::T_UNICODESAFE);
2489 strcpy(buf,utf8.cstr());
2490 }else if (var == "desc")
2493 utf8.convertTo(String::T_UNICODESAFE);
2494 strcpy(buf,utf8.cstr());
2495 }else if (var == "comment")
2497 utf8 = info.comment;
2498 utf8.convertTo(String::T_UNICODESAFE);
2499 strcpy(buf,utf8.cstr());
2500 }else if (var == "bcstClap") //JP-MOD
2502 strcpy(buf,info.ppFlags & ServMgr::bcstClap ? "1":"0");
2503 }else if (var == "uptime")
2506 if (info.lastPlayStart)
2507 uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
2510 strcpy(buf,uptime.cstr());
2512 else if (var == "type")
2513 sprintf(buf,"%s",info.getTypeStr());
2514 else if (var == "ext")
2515 sprintf(buf,"%s",info.getTypeExt());
2516 else if (var == "proto") {
2517 switch(info.contentType) {
2518 case ChanInfo::T_WMA:
2519 case ChanInfo::T_WMV:
2520 sprintf(buf, "mms://");
2523 sprintf(buf, "http://");
2526 else if (var == "localRelays")
2527 sprintf(buf,"%d",localRelays());
2528 else if (var == "localListeners")
2529 sprintf(buf,"%d",localListeners());
2531 else if (var == "totalRelays")
2532 sprintf(buf,"%d",totalRelays());
2533 else if (var == "totalListeners")
2534 sprintf(buf,"%d",totalListeners());
2535 else if (var == "totalClaps") //JP-MOD
2536 sprintf(buf,"%d",totalClaps());
2537 else if (var == "status")
2538 sprintf(buf,"%s",getStatusStr());
2539 else if (var == "keep")
2540 sprintf(buf,"%s",stayConnected?"Yes":"No");
2541 else if (var == "id")
2543 else if (var.startsWith("track."))
2546 if (var == "track.title")
2547 utf8 = info.track.title;
2548 else if (var == "track.artist")
2549 utf8 = info.track.artist;
2550 else if (var == "track.album")
2551 utf8 = info.track.album;
2552 else if (var == "track.genre")
2553 utf8 = info.track.genre;
2554 else if (var == "track.contactURL")
2555 utf8 = info.track.contact;
2557 utf8.convertTo(String::T_UNICODESAFE);
2558 strcpy(buf,utf8.cstr());
2560 }else if (var == "contactURL")
2561 sprintf(buf,"%s",info.url.cstr());
2562 else if (var == "streamPos")
2563 sprintf(buf,"%d",streamPos);
2564 else if (var == "sourceType")
2565 strcpy(buf,getSrcTypeStr());
2566 else if (var == "sourceProtocol")
2567 strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
2568 else if (var == "sourceURL")
2570 if (sourceURL.isEmpty())
2571 sourceHost.host.toStr(buf);
2573 strcpy(buf,sourceURL.cstr());
2575 else if (var == "headPos")
2576 sprintf(buf,"%d",headPack.pos);
2577 else if (var == "headLen")
2578 sprintf(buf,"%d",headPack.len);
2579 else if (var == "numHits")
2581 ChanHitList *chl = chanMgr->findHitListByID(info.id);
2584 // numHits = chl->numHits();
2592 sprintf(buf,"%d",numHits);
2593 } else if (var == "isBroadcast")
2594 strcpy(buf, (type == T_BROADCAST) ? "1":"0");
2598 out.writeString(buf);
2602 // -----------------------------------
2603 void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
2605 Channel *c = channel;
2608 if ( c->isActive() && c->isBroadcasting() )
2609 c->broadcastTrackerUpdate(svID,force);
2615 // -----------------------------------
2616 int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
2620 Channel *c = channel;
2623 if (c->sendPacketUp(pack,chanID,srcID,destID))
2631 // -----------------------------------
2632 void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
2634 //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
2637 Host sh = servMgr->serverHost;
2638 bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
2639 bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
2640 bool stable = servMgr->totalStreams>0;
2647 Channel *c = channel;
2653 bool tracker = c->isBroadcasting();
2655 int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds
2663 if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
2669 serv->outputPacket(hit,false);
2673 LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);
2680 // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);
2683 // -----------------------------------
2684 void ChanMgr::setUpdateInterval(unsigned int v)
2686 hostUpdateInterval = v;
2690 // -----------------------------------
2694 MemoryStream mem(pack.data,sizeof(pack.data));
2695 AtomStream atom(mem);
2696 atom.writeParent(PCP_BCST,3);
2697 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
2698 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
2699 atom.writeParent(PCP_MESG,1);
2700 atom.writeString(PCP_MESG_DATA,msg.cstr());
2710 PCPStream::readAtom(atom,bcs);
2711 //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2712 //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
2713 //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2714 //LOG_DEBUG("Sent message to %d clients",cnt);
2716 // -----------------------------------
2717 void ChanMgr::setBroadcastMsg(String &msg)
2719 if (!msg.isSame(broadcastMsg))
2723 Channel *c = channel;
2726 if (c->isActive() && c->isBroadcasting())
2728 ChanInfo newInfo = c->info;
2729 newInfo.comment = broadcastMsg;
2730 c->updateInfo(newInfo);
2739 // -----------------------------------
2740 void ChanMgr::clearHitLists()
2743 // LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
2744 chanMgr->hitlistlock.on();
2747 peercastApp->delChannel(&hitlist->info);
2749 ChanHitList *next = hitlist->next;
2755 // LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
2756 chanMgr->hitlistlock.off();
2758 // -----------------------------------
2759 Channel *ChanMgr::deleteChannel(Channel *delchan)
2763 Channel *ch = channel,*prev=NULL,*next=NULL;
2769 Channel *next = ch->next;
2775 if (delchan->sourceStream){
2776 delchan->sourceStream->parent = NULL;
2792 // -----------------------------------
2793 Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
2806 nc->info.lastPlayStart = 0;
2807 nc->info.lastPlayEnd = 0;
2808 nc->info.status = ChanInfo::S_UNKNOWN;
2810 nc->mount.set(mount);
2811 nc->setStatus(Channel::S_WAIT);
2812 nc->type = Channel::T_ALLOCATED;
2813 nc->info.createdTime = sys->getTime();
2815 LOG_CHANNEL("New channel created");
2820 // -----------------------------------
2821 int ChanMgr::pickHits(ChanHitSearch &chs)
2823 ChanHitList *chl = hitlist;
2827 if (chl->pickHits(chs))
2837 // -----------------------------------
2838 ChanHitList *ChanMgr::findHitList(ChanInfo &info)
2840 ChanHitList *chl = hitlist;
2844 if (chl->info.matchNameID(info))
2851 // -----------------------------------
2852 ChanHitList *ChanMgr::findHitListByID(GnuID &id)
2854 ChanHitList *chl = hitlist;
2858 if (chl->info.id.isSame(id))
2864 // -----------------------------------
2865 int ChanMgr::numHitLists()
2868 ChanHitList *chl = hitlist;
2877 // -----------------------------------
2878 ChanHitList *ChanMgr::addHitList(ChanInfo &info)
2880 ChanHitList *chl = new ChanHitList();
2883 chl->next = hitlist;
2888 chl->info.createdTime = sys->getTime();
2889 peercastApp->addChannel(&chl->info);
2894 // -----------------------------------
2895 void ChanMgr::clearDeadHits(bool clearTrackers)
2897 unsigned int interval;
2899 if (servMgr->isRoot)
2900 interval = 1200; // mainly for old 0.119 clients
2902 interval = hostUpdateInterval+120;
2904 chanMgr->hitlistlock.on();
2905 ChanHitList *chl = hitlist,*prev = NULL;
2910 if (chl->clearDeadHits(interval,clearTrackers) == 0)
2912 if (!isBroadcasting(chl->info.id))
2914 if (!chanMgr->findChannelByID(chl->info.id))
2916 peercastApp->delChannel(&chl->info);
2918 ChanHitList *next = chl->next;
2934 chanMgr->hitlistlock.off();
2936 // -----------------------------------
2937 bool ChanMgr::isBroadcasting(GnuID &id)
2939 Channel *ch = findChannelByID(id);
2941 return ch->isBroadcasting();
2945 // -----------------------------------
2946 bool ChanMgr::isBroadcasting()
2948 Channel *ch = channel;
2952 if (ch->isBroadcasting())
2960 // -----------------------------------
2961 int ChanMgr::numChannels()
2964 Channel *ch = channel;
2974 // -----------------------------------
2975 void ChanMgr::deadHit(ChanHit &hit)
2977 ChanHitList *chl = findHitListByID(hit.chanID);
2981 // -----------------------------------
2982 void ChanMgr::delHit(ChanHit &hit)
2984 ChanHitList *chl = findHitListByID(hit.chanID);
2989 // -----------------------------------
2990 void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
2996 hit.rhost[1].init();
2997 hit.tracker = tracker;
3002 // -----------------------------------
3003 ChanHit *ChanMgr::addHit(ChanHit &h)
3006 lastHit = sys->getTime();
3008 ChanHitList *hl=NULL;
3010 hl = findHitListByID(h.chanID);
3016 hl = addHitList(info);
3021 return hl->addHit(h);
3026 // -----------------------------------
3027 bool ChanMgr::findParentHit(ChanHit &p)
3029 ChanHitList *hl=NULL;
3031 chanMgr->hitlistlock.on();
3033 hl = findHitListByID(p.chanID);
3037 ChanHit *ch = hl->hit;
3040 if (!ch->dead && (ch->rhost[0].ip == p.uphost.ip)
3041 && (ch->rhost[0].port == p.uphost.port))
3043 chanMgr->hitlistlock.off();
3050 chanMgr->hitlistlock.off();
3055 // -----------------------------------
3056 class ChanFindInfo : public ThreadInfo
3062 // -----------------------------------
3063 THREAD_PROC findAndPlayChannelProcMain(ThreadInfo *th)
3065 ChanFindInfo *cfi = (ChanFindInfo *)th;
3071 Channel *ch = chanMgr->findChannelByNameID(info);
3073 chanMgr->currFindAndPlayChannel = info.id;
3076 ch = chanMgr->findAndRelay(info);
3080 // check that a different channel hasn`t be selected already.
3081 if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
3082 chanMgr->playChannel(ch->info);
3085 ch->stayConnected = cfi->keep;
3092 // -----------------------------------
3093 THREAD_PROC findAndPlayChannelProc(ThreadInfo *thread)
3095 SEH_THREAD(findAndPlayChannelProcMain, findAndPlayChannel);
3098 // -----------------------------------
3099 void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
3101 ChanFindInfo *cfi = new ChanFindInfo;
3104 cfi->func = findAndPlayChannelProc;
3107 sys->startThread(cfi);
3109 // -----------------------------------
3110 void ChanMgr::playChannel(ChanInfo &info)
3113 char str[128],fname[256],idStr[128];
3115 sprintf(str,"http://127.0.0.1:%d",servMgr->serverHost.port);
3116 info.id.toStr(idStr);
3118 PlayList::TYPE type;
3121 if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
3123 type = PlayList::T_ASX;
3124 // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
3125 // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
3126 if (servMgr->getModulePath) //JP-EX
3128 peercastApp->getDirectory();
3129 sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);
3131 sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
3132 }else if (info.contentType == ChanInfo::T_OGM)
3134 type = PlayList::T_RAM;
3135 if (servMgr->getModulePath) //JP-EX
3137 peercastApp->getDirectory();
3138 sprintf(fname,"%s/play.ram",servMgr->modulePath);
3140 sprintf(fname,"%s/play.ram",peercastApp->getPath());
3144 type = PlayList::T_SCPLS;
3145 if (servMgr->getModulePath) //JP-EX
3147 peercastApp->getDirectory();
3148 sprintf(fname,"%s/play.pls",servMgr->modulePath);
3150 sprintf(fname,"%s/play.pls",peercastApp->getPath());
3154 PlayList *pls = new PlayList(type,1);
3155 pls->addChannel(str,info);
3158 LOG_DEBUG("Writing %s",fname);
3160 file.openWriteReplace(fname);
3165 LOG_DEBUG("Executing: %s",fname);
3166 sys->executeFile(fname);
3171 // -----------------------------------
3172 ChanHitList::ChanHitList()
3179 // -----------------------------------
3180 ChanHitList::~ChanHitList()
3182 chanMgr->hitlistlock.on();
3184 hit = deleteHit(hit);
3185 chanMgr->hitlistlock.off();
3187 // -----------------------------------
3188 void ChanHit::pickNearestIP(Host &h)
3190 for(int i=0; i<2; i++)
3192 if (h.classType() == rhost[i].classType())
3200 // -----------------------------------
3201 void ChanHit::init()
3212 clap_pp = 0; //JP-MOD
3214 dead = tracker = firewalled = stable = yp = false;
3215 recv = cin = direct = relay = true;
3216 relayfull = chfull = ratefull = false;
3225 version_ex_prefix[0] = ' ';
3226 version_ex_prefix[1] = ' ';
3227 version_ex_number = 0;
3236 oldestPos = newestPos = 0;
3241 // -----------------------------------
3242 void ChanHit::initLocal(int numl,int numr,int,int uptm,bool connected,bool isFull,unsigned int bitrate, Channel* ch, unsigned int oldp,unsigned int newp)
3245 firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
3246 numListeners = numl;
3249 stable = servMgr->totalStreams>0;
3250 sessionID = servMgr->sessionID;
3253 direct = !servMgr->directFull();
3254 // relay = !servMgr->relaysFull();
3255 cin = !servMgr->controlInFull();
3257 relayfull = servMgr->relaysFull();
3260 Channel *c = chanMgr->channel;
3262 unsigned int needRate = 0;
3263 unsigned int allRate = 0;
3265 if (c->isPlaying()){
3266 allRate += c->info.bitrate * c->localRelays();
3267 if ((c != ch) && (c->localRelays() == 0)){
3268 if(!isIndexTxt(c)) // for PCRaw (relay)
3270 needRate+=c->info.bitrate;
3275 unsigned int numRelay = servMgr->numStreams(Servent::T_RELAY,false);
3276 int diff = servMgr->maxRelays - numRelay;
3277 if (ch->localRelays()){
3278 if (noRelay > diff){
3286 // ratefull = servMgr->bitrateFull(needRate+bitrate);
3287 ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
3289 if (!isIndexTxt(ch))
3290 relay = (!relayfull) && (!chfull) && (!ratefull) && (numRelay + noRelay < servMgr->maxRelays);
3292 relay = (!chfull) && (!ratefull); // for PCRaw (relay)
3295 LOG_DEBUG("Reject by relay full");
3298 LOG_DEBUG("Reject by channel full");
3301 LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
3304 host = servMgr->serverHost;
3306 version = PCP_CLIENT_VERSION;
3307 version_vp = PCP_CLIENT_VERSION_VP;
3310 strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
3311 version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
3314 version_ex_prefix[0] = ' ';
3315 version_ex_prefix[1] = ' ';
3316 version_ex_number = 0;
3319 status = ch->status;
3321 rhost[0] = Host(host.ip,host.port);
3322 rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
3330 uphost.ip = ch->sourceHost.host.ip;
3331 uphost.port = ch->sourceHost.host.port;
3335 // -----------------------------------
3336 void ChanHit::initLocal_pp(bool isStealth, int numClaps) //JP-MOD
3338 numListeners = numListeners && !isStealth ? 1 : 0;
3342 // -----------------------------------
3343 void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
3345 bool addChan=chanID.isSet();
3346 bool uphostdata=(uphost.ip != 0);
3349 if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
3350 if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
3351 if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
3352 if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
3353 if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
3354 if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
3356 atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0) + (clap_pp?1:0/*JP-MOD*/));
3359 atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
3360 atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
3361 atom.writeInt(PCP_HOST_IP,rhost[0].ip);
3362 atom.writeShort(PCP_HOST_PORT,rhost[0].port);
3363 atom.writeInt(PCP_HOST_IP,rhost[1].ip);
3364 atom.writeShort(PCP_HOST_PORT,rhost[1].port);
3365 atom.writeInt(PCP_HOST_NUML,numListeners);
3366 atom.writeInt(PCP_HOST_NUMR,numRelays);
3367 atom.writeInt(PCP_HOST_UPTIME,upTime);
3368 atom.writeInt(PCP_HOST_VERSION,version);
3369 atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
3370 if (version_ex_number){
3371 atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
3372 atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
3374 atom.writeChar(PCP_HOST_FLAGS1,fl1);
3375 atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
3376 atom.writeInt(PCP_HOST_NEWPOS,newestPos);
3378 atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
3379 atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
3380 atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
3382 if (clap_pp){ //JP-MOD
3383 atom.writeInt(PCP_HOST_CLAP_PP,clap_pp);
3386 // -----------------------------------
3387 bool ChanHit::writeVariable(Stream &out, const String &var)
3391 if (var == "rhost0")
3393 if (servMgr->enableGetName) //JP-EX s
3399 strcpy(buf,"<font color=red>");
3401 strcpy(buf,"<font color=orange>");
3406 strcpy(buf,"<font color=purple>");
3408 strcpy(buf,"<font color=blue>");
3411 strcpy(buf,"<font color=green>");
3415 rhost[0].toStr(buf2);
3419 if (ClientSocket::getHostname(h_name,sizeof(h_name),rhost[0].ip)) // BOF
\91Î
\8dô
\82Á
\82Û
\82¢
3425 strcat(buf,"</font>");
3428 rhost[0].toStr(buf);
3430 else if (var == "rhost1")
3431 rhost[1].toStr(buf);
3432 else if (var == "numHops")
3433 sprintf(buf,"%d",numHops);
3434 else if (var == "numListeners")
3435 sprintf(buf,"%d",numListeners);
3436 else if (var == "numRelays")
3437 sprintf(buf,"%d",numRelays);
3438 else if (var == "uptime")
3441 timeStr.setFromStopwatch(upTime);
3442 strcpy(buf,timeStr.cstr());
3443 }else if (var == "update")
3447 timeStr.setFromStopwatch(sys->getTime()-time);
3450 strcpy(buf,timeStr.cstr());
3451 }else if (var == "isFirewalled"){
3452 sprintf(buf,"%d",firewalled?1:0);
3453 }else if (var == "version"){
3454 sprintf(buf,"%d",version);
3455 }else if (var == "agent"){
3457 if (version_ex_number){
3458 sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
3459 } else if (version_vp){
3460 sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
3462 sprintf(buf,"v0.%d", version);
3468 else if (var == "check")
3471 strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
3472 rhost[0].IPtoStr(buf2);
3474 strcat(buf, "')\">_</a>");
3476 else if (var == "uphost") // tree
3478 else if (var == "uphostHops") // tree
3479 sprintf(buf,"%d",uphostHops);
3480 else if (var == "canRelay") // tree
3481 sprintf(buf, "%d",relay);
3485 out.writeString(buf);
3489 // -----------------------------------
3490 int ChanHitList::getTotalListeners()
3497 cnt+=h->numListeners;
3502 // -----------------------------------
3503 int ChanHitList::getTotalRelays()
3515 // -----------------------------------
3516 int ChanHitList::getTotalFirewalled()
3530 // -----------------------------------
3531 int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
3536 void ChanHitList::clearHits(bool flg)
3538 ChanHit *c = hit, *prev = NULL;
3541 if (flg || (c->numHops != 0)){
3542 ChanHit *next = c->next;
3557 // -----------------------------------
3558 ChanHit *ChanHitList::deleteHit(ChanHit *ch)
3560 ChanHit *c = hit,*prev=NULL;
3565 ChanHit *next = c->next;
3581 // -----------------------------------
3582 ChanHit *ChanHitList::addHit(ChanHit &h)
3584 char ip0str[64],ip1str[64];
3585 h.rhost[0].toStr(ip0str);
3586 h.rhost[1].toStr(ip1str);
3588 h.uphost.toStr(uphostStr);
3590 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
3592 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
3595 // dont add our own hits
3596 if (servMgr->sessionID.isSame(h.sessionID))
3600 lastHitTime = sys->getTime();
3601 h.time = lastHitTime;
3606 if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
3607 if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
3611 if (ch->numHops > 0 && h.numHops == 0)
3612 // downstream hit recieved as RelayHost
3614 ChanHit *next = ch->next;
3623 // clear hits with same session ID (IP may have changed)
3624 if (h.sessionID.isSet())
3630 if (ch->sessionID.isSame(h.sessionID))
3642 ChanHit *ch = new ChanHit();
3644 ch->chanID = info.id;
3654 // -----------------------------------
3655 int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
3658 unsigned int ctime = sys->getTime();
3660 // LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
3661 chanMgr->hitlistlock.on();
3667 if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
3669 // ch = deleteHit(ch);
3671 if (ch->firewalled){
3672 // LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
3673 if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
3677 ch->numListeners = 0;
3690 // LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
3691 chanMgr->hitlistlock.off();
3696 // -----------------------------------
3697 void ChanHitList::deadHit(ChanHit &h)
3699 char ip0str[64],ip1str[64];
3700 h.rhost[0].toStr(ip0str);
3701 h.rhost[1].toStr(ip1str);
3702 LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
3708 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3715 // -----------------------------------
3716 void ChanHitList::delHit(ChanHit &h)
3718 char ip0str[64],ip1str[64];
3719 h.rhost[0].toStr(ip0str);
3720 h.rhost[1].toStr(ip1str);
3721 LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
3727 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3735 // -----------------------------------
3736 int ChanHitList::numHits()
3742 if (ch->host.ip && !ch->dead && ch->numHops)
3749 // -----------------------------------
3750 int ChanHitList::numListeners()
3756 if (ch->host.ip && !ch->dead && ch->numHops)
3757 cnt += (unsigned int)ch->numListeners > 3 ? 3 : ch->numListeners;
3764 // -----------------------------------
3765 int ChanHitList::numClaps() //JP-MOD
3771 if (ch->host.ip && !ch->dead && ch->numHops && (ch->clap_pp & 1)){
3779 // -----------------------------------
3780 int ChanHitList::numRelays()
3786 if (ch->host.ip && !ch->dead)
3787 cnt += ch->numRelays;
3794 // -----------------------------------
3795 int ChanHitList::numTrackers()
3801 if ((ch->host.ip && !ch->dead) && (ch->tracker))
3807 // -----------------------------------
3808 int ChanHitList::numFirewalled()
3814 if (ch->host.ip && !ch->dead)
3815 cnt += ch->firewalled?1:0;
3820 // -----------------------------------
3821 int ChanHitList::closestHit()
3823 unsigned int hop=10000;
3827 if (ch->host.ip && !ch->dead)
3828 if (ch->numHops < hop)
3835 // -----------------------------------
3836 int ChanHitList::furthestHit()
3842 if (ch->host.ip && !ch->dead)
3843 if (ch->numHops > hop)
3850 // -----------------------------------
3851 unsigned int ChanHitList::newestHit()
3853 unsigned int time=0;
3857 if (ch->host.ip && !ch->dead)
3858 if (ch->time > time)
3865 // -----------------------------------
3866 int ChanHitList::pickHits(ChanHitSearch &chs)
3868 ChanHit best,*bestP=NULL;
3873 unsigned int ctime = sys->getTime();
3878 if (c->host.ip && !c->dead)
3880 if (!chs.excludeID.isSame(c->sessionID))
3881 if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
3882 if ((c->numHops<=best.numHops)) // (c->time>=best.time))
3883 if (c->relay || (!c->relay && chs.useBusyRelays))
3884 if (c->cin || (!c->cin && chs.useBusyControls))
3887 if (chs.trackersOnly && c->tracker)
3889 if (chs.matchHost.ip)
3891 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3895 best.host = best.rhost[1]; // use lan ip
3897 }else if (c->firewalled == chs.useFirewalled)
3901 best.host = best.rhost[0]; // use wan ip
3903 }else if (!chs.trackersOnly && !c->tracker)
3905 if (chs.matchHost.ip)
3907 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3911 best.host = best.rhost[1]; // use lan ip
3913 }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
3917 best.host = best.rhost[0]; // use wan ip
3927 if (chs.numResults < ChanHitSearch::MAX_RESULTS)
3930 bestP->lastContact = ctime;
3931 chs.best[chs.numResults++] = best;
3941 // -----------------------------------
3942 int ChanHitList::pickSourceHits(ChanHitSearch &chs)
3944 if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
3948 // -----------------------------------
3949 unsigned int ChanHitList::getSeq()
3953 seq = riSequence = (riSequence + 1) & 0xffffff;
3958 // -----------------------------------
3959 const char *ChanInfo::getTypeStr()
3961 if (contentTypeStr.isEmpty()) {
3962 return getTypeStr(contentType);
3965 return contentTypeStr.cstr();
3968 // -----------------------------------
3969 const char *ChanInfo::getTypeExt()
3971 if (streamExt.isEmpty()) {
3972 return getTypeExt(contentType);
3975 return streamExt.cstr();
3978 // -----------------------------------
3979 const char *ChanInfo::getMIMEType()
3981 if (streamType.isEmpty()) {
3982 return getMIMEType(contentType);
3985 return streamType.cstr();
3988 // -----------------------------------
3989 const char *ChanInfo::getTypeStr(TYPE t)
3993 case T_RAW: return "RAW";
3995 case T_MP3: return "MP3";
3996 case T_OGG: return "OGG";
3997 case T_OGM: return "OGM";
3998 case T_WMA: return "WMA";
4000 case T_MOV: return "MOV";
4001 case T_MPG: return "MPG";
4002 case T_NSV: return "NSV";
4003 case T_WMV: return "WMV";
4004 case T_FLV: return "FLV";
4006 case T_PLS: return "PLS";
4007 case T_ASX: return "ASX";
4009 default: return "UNKNOWN";
4012 // -----------------------------------
4013 const char *ChanInfo::getProtocolStr(PROTOCOL t)
4017 case SP_PEERCAST: return "PEERCAST";
4018 case SP_HTTP: return "HTTP";
4019 case SP_FILE: return "FILE";
4020 case SP_MMS: return "MMS";
4021 case SP_PCP: return "PCP";
4022 default: return "UNKNOWN";
4025 // -----------------------------------
4026 ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
4028 if (stricmp(str,"PEERCAST")==0)
4030 else if (stricmp(str,"HTTP")==0)
4032 else if (stricmp(str,"FILE")==0)
4034 else if (stricmp(str,"MMS")==0)
4036 else if (stricmp(str,"PCP")==0)
4042 // -----------------------------------
4043 const char *ChanInfo::getTypeExt(TYPE t)
4047 case ChanInfo::T_OGM:
4048 case ChanInfo::T_OGG:
4050 case ChanInfo::T_MP3:
4052 case ChanInfo::T_MOV:
4054 case ChanInfo::T_NSV:
4056 case ChanInfo::T_WMV:
4058 case ChanInfo::T_WMA:
4060 case ChanInfo::T_FLV:
4066 // -----------------------------------
4067 const char *ChanInfo::getMIMEType(TYPE t)
4071 case ChanInfo::T_OGG:
4073 case ChanInfo::T_OGM:
4075 case ChanInfo::T_MP3:
4077 case ChanInfo::T_MOV:
4079 case ChanInfo::T_MPG:
4081 case ChanInfo::T_NSV:
4083 case ChanInfo::T_ASX:
4085 case ChanInfo::T_WMA:
4087 case ChanInfo::T_WMV:
4090 return "application/octet-stream";
4093 // -----------------------------------
4094 ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
4096 if (stricmp(str,"MP3")==0)
4098 else if (stricmp(str,"OGG")==0)
4100 else if (stricmp(str,"OGM")==0)
4102 else if (stricmp(str,"RAW")==0)
4104 else if (stricmp(str,"NSV")==0)
4106 else if (stricmp(str,"WMA")==0)
4108 else if (stricmp(str,"WMV")==0)
4110 else if (stricmp(str,"FLV")==0)
4112 else if (stricmp(str,"PLS")==0)
4114 else if (stricmp(str,"M3U")==0)
4116 else if (stricmp(str,"ASX")==0)
4121 // -----------------------------------
4122 bool ChanInfo::matchNameID(ChanInfo &inf)
4125 if (id.isSame(inf.id))
4128 if (!inf.name.isEmpty())
4129 if (name.contains(inf.name))
4134 // -----------------------------------
4135 bool ChanInfo::match(ChanInfo &inf)
4139 if (inf.status != S_UNKNOWN)
4141 if (status != inf.status)
4145 if (inf.bitrate != 0)
4147 if (bitrate == inf.bitrate)
4154 if (id.isSame(inf.id))
4159 if (inf.contentType != T_UNKNOWN)
4161 if (contentType == inf.contentType)
4166 if (!inf.name.isEmpty())
4168 if (name.contains(inf.name))
4173 if (!inf.genre.isEmpty())
4175 if (genre.contains(inf.genre))
4182 // -----------------------------------
4183 bool TrackInfo::update(TrackInfo &inf)
4185 bool changed = false;
4187 if (!contact.isSame(inf.contact))
4189 contact = inf.contact;
4193 if (!title.isSame(inf.title))
4199 if (!artist.isSame(inf.artist))
4201 artist = inf.artist;
4205 if (!album.isSame(inf.album))
4211 if (!genre.isSame(inf.genre))
4222 // -----------------------------------
4223 bool ChanInfo::update(ChanInfo &info)
4225 bool changed = false;
4230 if (!info.id.isSet())
4233 // only update from chaninfo that has full name etc..
4234 if (info.name.isEmpty())
4237 // check valid broadcaster key
4240 if (!bcID.isSame(info.bcID))
4242 LOG_ERROR("ChanInfo BC key not valid");
4252 if (bitrate != info.bitrate)
4254 bitrate = info.bitrate;
4258 if (contentType != info.contentType)
4260 contentType = info.contentType;
4264 if (!contentTypeStr.isSame(info.contentTypeStr))
4266 contentTypeStr = info.contentTypeStr;
4270 if (!streamType.isSame(info.streamType))
4272 streamType = info.streamType;
4276 if (!streamExt.isSame(info.streamExt))
4278 streamExt = info.streamExt;
4282 if(ppFlags != info.ppFlags) //JP-MOD
4284 ppFlags = info.ppFlags;
4288 if (!desc.isSame(info.desc)) //JP-EX
4294 if (!name.isSame(info.name))
4300 if (!comment.isSame(info.comment))
4302 comment = info.comment;
4306 if (!genre.isSame(info.genre))
4312 if (!url.isSame(info.url))
4318 if (track.update(info.track))
4324 // -----------------------------------
4325 void ChanInfo::initNameID(const char *n)
4333 // -----------------------------------
4334 void ChanInfo::init()
4339 contentType = T_UNKNOWN;
4340 contentTypeStr.clear();
4343 srcProtocol = SP_UNKNOWN;
4354 ppFlags = 0; //JP-MOD
4356 // -----------------------------------
4357 void ChanInfo::readTrackXML(XML::Node *n)
4360 readXMLString(track.title,n,"title");
4361 readXMLString(track.contact,n,"contact");
4362 readXMLString(track.artist,n,"artist");
4363 readXMLString(track.album,n,"album");
4364 readXMLString(track.genre,n,"genre");
4366 // -----------------------------------
4367 unsigned int ChanInfo::getUptime()
4369 // calculate uptime and cap if requested by settings.
4371 upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
4372 if (chanMgr->maxUptime)
4373 if (upt > chanMgr->maxUptime)
4374 upt = chanMgr->maxUptime;
4377 // -----------------------------------
4378 unsigned int ChanInfo::getAge()
4380 return sys->getTime()-createdTime;
4383 // ------------------------------------------
4384 void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
4386 for(int i=0; i<numc; i++)
4389 ID4 id = atom.read(c,d);
4390 if (id == PCP_CHAN_TRACK_TITLE)
4392 atom.readString(track.title.data,sizeof(track.title.data),d);
4393 }else if (id == PCP_CHAN_TRACK_CREATOR)
4395 atom.readString(track.artist.data,sizeof(track.artist.data),d);
4396 }else if (id == PCP_CHAN_TRACK_URL)
4398 atom.readString(track.contact.data,sizeof(track.contact.data),d);
4399 }else if (id == PCP_CHAN_TRACK_ALBUM)
4401 atom.readString(track.album.data,sizeof(track.album.data),d);
4406 // ------------------------------------------
4407 void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
4409 for(int i=0; i<numc; i++)
4412 ID4 id = atom.read(c,d);
4413 if (id == PCP_CHAN_INFO_NAME)
4415 atom.readString(name.data,sizeof(name.data),d);
4416 }else if (id == PCP_CHAN_INFO_BITRATE)
4418 bitrate = atom.readInt();
4419 }else if (id == PCP_CHAN_INFO_GENRE)
4421 atom.readString(genre.data,sizeof(genre.data),d);
4422 }else if (id == PCP_CHAN_INFO_URL)
4424 atom.readString(url.data,sizeof(url.data),d);
4425 }else if (id == PCP_CHAN_INFO_DESC)
4427 atom.readString(desc.data,sizeof(desc.data),d);
4428 }else if (id == PCP_CHAN_INFO_COMMENT)
4430 atom.readString(comment.data,sizeof(comment.data),d);
4431 }else if (id == PCP_CHAN_INFO_TYPE)
4434 atom.readString(type,sizeof(type),d);
4435 contentType = ChanInfo::getTypeFromStr(type);
4436 contentTypeStr = type;
4437 }else if (id == PCP_CHAN_INFO_STREAMTYPE)
4439 atom.readString(streamType.data,sizeof(streamType.data),d);
4440 }else if (id == PCP_CHAN_INFO_STREAMEXT)
4442 atom.readString(streamExt.data,sizeof(streamExt.data),d);
4443 }else if (id == PCP_CHAN_INFO_PPFLAGS) //JP-MOD
4445 ppFlags = (unsigned int)atom.readInt();
4451 // -----------------------------------
4452 void ChanInfo::writeInfoAtoms(AtomStream &atom)
4454 atom.writeParent(PCP_CHAN_INFO,7 + (ppFlags ? 1:0/*JP-MOD*/));
4455 atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
4456 atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
4457 atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
4458 atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
4459 atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
4460 atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
4461 atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr());
4462 if (!streamType.isEmpty())
4463 atom.writeString(PCP_CHAN_INFO_STREAMTYPE,streamType.cstr());
4464 if (!streamExt.isEmpty())
4465 atom.writeString(PCP_CHAN_INFO_STREAMEXT,streamExt.cstr());
4467 atom.writeInt(PCP_CHAN_INFO_PPFLAGS,ppFlags); //JP-MOD
4470 // -----------------------------------
4471 void ChanInfo::writeTrackAtoms(AtomStream &atom)
4473 atom.writeParent(PCP_CHAN_TRACK,4);
4474 atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
4475 atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
4476 atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
4477 atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
4481 // -----------------------------------
4482 XML::Node *ChanInfo::createChannelXML()
4486 String nameUNI = name;
4487 nameUNI.convertTo(String::T_UNICODESAFE);
4489 String urlUNI = url;
4490 urlUNI.convertTo(String::T_UNICODESAFE);
4492 String genreUNI = genre;
4493 genreUNI.convertTo(String::T_UNICODESAFE);
4495 String descUNI = desc;
4496 descUNI.convertTo(String::T_UNICODESAFE);
4499 commentUNI = comment;
4500 commentUNI.convertTo(String::T_UNICODESAFE);
4506 return new XML::Node("channel name=\"%s\" id=\"%s\" bitrate=\"%d\" type=\"%s\" genre=\"%s\" desc=\"%s\" url=\"%s\" uptime=\"%d\" comment=\"%s\" skips=\"%d\" age=\"%d\" bcflags=\"%d\"",
4522 // -----------------------------------
4523 XML::Node *ChanInfo::createQueryXML()
4529 String nameHTML = name;
4530 nameHTML.convertTo(String::T_HTML);
4531 String genreHTML = genre;
4532 genreHTML.convertTo(String::T_HTML);
4535 if (!nameHTML.isEmpty())
4537 strcat(buf," name=\"");
4538 strcat(buf,nameHTML.cstr());
4542 if (!genreHTML.isEmpty())
4544 strcat(buf," genre=\"");
4545 strcat(buf,genreHTML.cstr());
4552 strcat(buf," id=\"");
4558 return new XML::Node("channel %s",buf);
4561 // -----------------------------------
4562 XML::Node *ChanInfo::createRelayChannelXML()
4569 return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
4575 }// -----------------------------------
4576 XML::Node *ChanInfo::createTrackXML()
4578 String titleUNI = track.title;
4579 titleUNI.convertTo(String::T_UNICODESAFE);
4581 String artistUNI = track.artist;
4582 artistUNI.convertTo(String::T_UNICODESAFE);
4584 String albumUNI = track.album;
4585 albumUNI.convertTo(String::T_UNICODESAFE);
4587 String genreUNI = track.genre;
4588 genreUNI.convertTo(String::T_UNICODESAFE);
4590 String contactUNI = track.contact;
4591 contactUNI.convertTo(String::T_UNICODESAFE);
4595 return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
4604 // -----------------------------------
4605 void ChanInfo::init(XML::Node *n)
4611 // -----------------------------------
4612 void ChanInfo::updateFromXML(XML::Node *n)
4614 String typeStr,idStr;
4616 readXMLString(name,n,"name");
4617 readXMLString(genre,n,"genre");
4618 readXMLString(url,n,"url");
4619 readXMLString(desc,n,"desc");
4622 int br = n->findAttrInt("bitrate");
4627 ppFlags = ServMgr::bcstNone;
4629 if (n->findAttrInt("bcstClap"))
4630 ppFlags |= ServMgr::bcstClap;
4633 readXMLString(typeStr,n,"type");
4634 if (!typeStr.isEmpty()) {
4635 contentType = getTypeFromStr(typeStr.cstr());
4636 contentTypeStr = typeStr;
4639 readXMLString(idStr,n,"id");
4640 if (!idStr.isEmpty())
4641 id.fromStr(idStr.cstr());
4643 readXMLString(comment,n,"comment");
4645 XML::Node *tn = n->findNode("track");
4651 // -----------------------------------
4652 void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
4662 // -----------------------------------
4663 void ChanInfo::init(const char *fn)
4670 // -----------------------------------
4671 void PlayList::readASX(Stream &in)
4673 LOG_DEBUG("Reading ASX");
4679 }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
4683 XML::Node *n = xml.root->child;
4686 if (stricmp("entry",n->getName())==0)
4688 XML::Node *rf = n->findNode("ref");
4691 char *hr = rf->findAttr("href");
4695 //LOG("asx url %s",hr);
4704 // -----------------------------------
4705 void PlayList::readSCPLS(Stream &in)
4708 while (in.readLine(tmp,sizeof(tmp)))
4710 if (strnicmp(tmp,"file",4)==0)
4712 char *p = strstr(tmp,"=");
4718 // -----------------------------------
4719 void PlayList::readPLS(Stream &in)
4722 while (in.readLine(tmp,sizeof(tmp)))
4728 // -----------------------------------
4729 void PlayList::writeSCPLS(Stream &out)
4731 out.writeLine("[playlist]");
4733 out.writeLineF("NumberOfEntries=%d",numURLs);
4735 for(int i=0; i<numURLs; i++)
4737 out.writeLineF("File%d=%s",i+1,urls[i].cstr());
4738 out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
4739 out.writeLineF("Length%d=-1",i+1);
4741 out.writeLine("Version=2");
4743 // -----------------------------------
4744 void PlayList::writePLS(Stream &out)
4746 for(int i=0; i<numURLs; i++)
4747 out.writeLineF("%s",urls[i].cstr());
4749 // -----------------------------------
4750 void PlayList::writeRAM(Stream &out)
4752 for(int i=0; i<numURLs; i++)
4753 out.writeLineF("%s",urls[i].cstr());
4756 // -----------------------------------
4757 #define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
4758 static void SJIStoSJISSAFE(char *string, size_t size)
4762 (string[pos] != '\0') && (pos < size);
4765 if(isHTMLSPECIAL(string[pos]))
4770 // -----------------------------------
4771 static void WriteASXInfo(Stream &out, String &title, String &contacturl, String::TYPE tEncoding = String::T_UNICODESAFE) //JP-MOD
4773 if(!title.isEmpty())
4776 titleEncode = title;
4777 titleEncode.convertTo(tEncoding);
4778 if(tEncoding == String::T_SJIS)
4779 SJIStoSJISSAFE(titleEncode.cstr(), String::MAX_LEN);
4780 out.writeLineF("<TITLE>%s</TITLE>", titleEncode.cstr());
4783 if(!contacturl.isEmpty())
4785 String contacturlEncode;
4786 contacturlEncode = contacturl;
4787 contacturlEncode.convertTo(tEncoding);
4788 if(tEncoding == String::T_SJIS)
4789 SJIStoSJISSAFE(contacturlEncode.cstr(), String::MAX_LEN);
4790 out.writeLineF("<MOREINFO HREF = \"%s\" />", contacturlEncode.cstr());
4794 // -----------------------------------
4795 void PlayList::writeASX(Stream &out)
4797 out.writeLine("<ASX Version=\"3.0\">");
4799 String::TYPE tEncoding = String::T_SJIS;
4800 if(servMgr->asxDetailedMode == 2)
4802 out.writeLine("<PARAM NAME = \"Encoding\" VALUE = \"utf-8\" />"); //JP-MOD Memo: UTF-8 cannot be used in some recording software.
4803 tEncoding = String::T_UNICODESAFE;
4806 if(servMgr->asxDetailedMode)
4807 WriteASXInfo(out, titles[0], contacturls[0], tEncoding); //JP-MOD
4809 for(int i=0; i<numURLs; i++)
4811 out.writeLine("<ENTRY>");
4812 if(servMgr->asxDetailedMode)
4813 WriteASXInfo(out, titles[i], contacturls[i], tEncoding); //JP-MOD
4814 out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
4815 out.writeLine("</ENTRY>");
4817 out.writeLine("</ASX>");
4821 // -----------------------------------
4822 void PlayList::addChannel(const char *path, ChanInfo &info)
4828 info.id.toStr(idStr);
4829 char *nid = info.id.isSet()?idStr:info.name.cstr();
4831 sprintf(url.cstr(),"%s/stream/%s%s",path,nid,info.getTypeExt());
4832 addURL(url.cstr(),info.name,info.url);
4835 // -----------------------------------
4836 void ChanHitSearch::init()
4840 useFirewalled = false;
4841 trackersOnly = false;
4842 useBusyRelays = true;
4843 useBusyControls = true;
4847 //seed = sys->getTime();
4851 int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
4859 ChanHit tmpHit[MAX_RESULTS];
4864 unsigned int seq = chl->getSeq();
4866 ChanHit *hit = chl->hit;
4869 if (hit->rhost[0].ip && !hit->dead) {
4871 (!exID.isSame(hit->sessionID))
4874 && (!hit->firewalled)
4875 && (hit->numHops != 0)
4877 if ( (hit->rhost[0].ip == host1.ip)
4878 && hit->rhost[1].isValid()
4879 && (host2.ip != hit->rhost[1].ip)
4882 best[0].host = hit->rhost[1];
4885 if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
4887 best[0].host = hit->rhost[1];
4891 loop = (index / MAX_RESULTS) + 1;
4892 //prob = (float)1 / (float)loop;
4894 //rnd = (float)rand() / (float)RAND_MAX;
4895 rnd = rand() % base;
4896 if (hit->numHops == 1){
4897 if (tmpHit[index % MAX_RESULTS].numHops == 1){
4899 tmpHit[index % MAX_RESULTS] = *hit;
4900 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4904 tmpHit[index % MAX_RESULTS] = *hit;
4905 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4909 if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
4910 tmpHit[index % MAX_RESULTS] = *hit;
4911 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4917 // hit->host.toStr(tmp);
4918 // LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
4924 if (index > MAX_RESULTS){
4930 /* int use[MAX_RESULTS];
4931 memset(use, 0, sizeof(use));
4933 for (i = 0; i < cnt; i++){
4937 for (i = 0; i < cnt; i++){
4940 // LOG_DEBUG("%d",r);
4948 for (i = 0; i < cnt; i++){
4949 // LOG_DEBUG("%d", use[i]);
4950 best[use[i]] = tmpHit[i];
4953 for (int i = 0; i < cnt; i++){
4954 // LOG_DEBUG("%d", use[i]);
4955 best[(i + seq) % cnt] = tmpHit[i];
4957 // for (i = 0; i < cnt; i++){
4959 // best[i].host.toStr(tmp);
4960 // LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);