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 #include "win32/seh.h"
55 // -----------------------------------
56 char *Channel::srcTypes[]=
64 // -----------------------------------
65 char *Channel::statusMsgs[]=
84 bool isIndexTxt(ChanInfo *info)
89 info->contentType == ChanInfo::T_RAW &&
90 info->bitrate <= 32 &&
91 (len = strlen(info->name.cstr())) >= 9 &&
92 !memcmp(info->name.cstr(), "index", 5) &&
93 !memcmp(info->name.cstr()+len-4, ".txt", 4))
103 bool isIndexTxt(Channel *ch)
105 if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
111 int numMaxRelaysIndexTxt(Channel *ch)
113 return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
116 int canStreamIndexTxt(Channel *ch)
120 //
\8e©
\95ª
\82ª
\94z
\90M
\82µ
\82Ä
\82¢
\82é
\8fê
\8d\87\82Í
\8aÖ
\8cW
\82È
\82¢
121 if(!ch || ch->isBroadcasting())
124 ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
132 // -----------------------------------
133 void readXMLString(String &str, XML::Node *n, const char *arg)
136 p = n->findAttr(arg);
139 str.set(p,String::T_HTML);
140 str.convertTo(String::T_ASCII);
145 // -----------------------------------------------------------------------------
146 // Initialise the channel to its default settings of unallocated and reset.
147 // -----------------------------------------------------------------------------
148 Channel::Channel() : maxRelays(0)
152 channel_id = channel_count++;
154 // -----------------------------------------------------------------------------
155 void Channel::endThread(bool flg)
179 chanMgr->channellock.on();
180 chanMgr->deleteChannel(this);
181 chanMgr->channellock.off();
183 sys->endThread(&thread);
186 // -----------------------------------------------------------------------------
187 void Channel::resetPlayTime()
189 info.lastPlayStart = sys->getTime();
191 // -----------------------------------------------------------------------------
192 void Channel::setStatus(STATUS s)
196 bool wasPlaying = isPlaying();
202 info.status = ChanInfo::S_PLAY;
207 info.lastPlayEnd = sys->getTime();
208 info.status = ChanInfo::S_UNKNOWN;
211 if (isBroadcasting())
213 ChanHitList *chl = chanMgr->findHitListByID(info.id);
215 chanMgr->addHitList(info);
218 peercastApp->channelUpdate(&info);
223 // -----------------------------------------------------------------------------
224 // Reset channel and make it available
225 // -----------------------------------------------------------------------------
226 void Channel::reset()
239 stayConnected = false;
240 stealth = false; //JP-MOD
241 overrideMaxRelaysPerChannel = -1; //JP-MOD
242 bClap = false; //JP-MOD
246 skipCount = 0; //JP-EX
256 rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
268 lastTrackerUpdate = 0;
283 // -----------------------------------
284 void Channel::newPacket(ChanPacket &pack)
286 if (pack.type != ChanPacket::T_PCP)
288 rawData.writePacket(pack,true);
293 // -----------------------------------
294 bool Channel::checkIdle()
296 return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
299 // -----------------------------------
300 bool Channel::isFull()
302 // for PCRaw (relay) start.
305 int ret = canStreamIndexTxt(this);
312 // for PCRaw (relay) end.
314 //
\83`
\83\83\83\93\83l
\83\8b\8cÅ
\97L
\82Ì
\83\8a\83\8c\81[
\8fã
\8cÀ
\90Ý
\92è
\82ª
\82 \82é
\82©
317 return localRelays() >= maxRelays;
320 return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
323 // -----------------------------------
324 int Channel::localRelays()
326 return servMgr->numStreams(info.id,Servent::T_RELAY,true);
328 // -----------------------------------
329 int Channel::localListeners()
331 return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
334 // -----------------------------------
335 int Channel::totalRelays()
338 ChanHitList *chl = chanMgr->findHitListByID(info.id);
340 tot += chl->numHits();
343 // -----------------------------------
344 int Channel::totalListeners()
346 int tot = localListeners();
347 ChanHitList *chl = chanMgr->findHitListByID(info.id);
349 tot += chl->numListeners();
353 // -----------------------------------
354 int Channel::totalClaps() //JP-MOD
356 ChanHitList *chl = chanMgr->findHitListByID(info.id);
357 return chl ? chl->numClaps() : 0;
360 // -----------------------------------
361 void Channel::startGet()
363 srcType = SRC_PEERCAST;
365 info.srcProtocol = ChanInfo::SP_PCP;
368 sourceData = new PeercastSource();
372 // -----------------------------------
373 void Channel::startURL(const char *u)
379 stayConnected = true;
383 sourceData = new URLSource(u);
388 // -----------------------------------
389 void Channel::startStream()
392 thread.func = stream;
393 if (!sys->startThread(&thread))
397 // -----------------------------------
398 void Channel::sleepUntil(double time)
400 double sleepTime = time - (sys->getDTime()-startTime);
402 // LOG("sleep %g",sleepTime);
405 if (sleepTime > 60) sleepTime = 60;
407 double sleepMS = sleepTime*1000;
409 sys->sleep((int)sleepMS);
414 // -----------------------------------
415 void Channel::checkReadDelay(unsigned int len)
419 unsigned int time = (len*1000)/((info.bitrate*1024)/8);
427 // -----------------------------------
428 THREAD_PROC Channel::streamMain(ThreadInfo *thread)
432 Channel *ch = (Channel *)thread->data;
434 LOG_CHANNEL("Channel started");
436 while (thread->active && !peercastInst->isQuitting && !thread->finish)
438 ChanHitList *chl = chanMgr->findHitList(ch->info);
440 chanMgr->addHitList(ch->info);
442 ch->sourceData->stream(ch);
444 LOG_CHANNEL("Channel stopped");
447 if (!ch->stayConnected)
449 thread->active = false;
453 if (!ch->info.lastPlayEnd)
454 ch->info.lastPlayEnd = sys->getTime();
456 unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
458 LOG_DEBUG("Channel sleeping for %d seconds",diff);
459 for(unsigned int i=0; i<diff; i++)
461 if (ch->info.lastPlayEnd == 0) // reconnected
463 if (!thread->active || peercastInst->isQuitting){
464 thread->active = false;
472 LOG_DEBUG("thread.active = %d, thread.finish = %d",
473 ch->thread.active, ch->thread.finish);
475 if (!thread->finish){
476 ch->endThread(false);
479 ch->finthread = new ThreadInfo();
480 ch->finthread->func = waitFinish;
481 ch->finthread->data = ch;
482 sys->startThread(ch->finthread);
490 // -----------------------------------
491 THREAD_PROC Channel::stream(ThreadInfo *thread)
493 SEH_THREAD(streamMain, Channel::stream);
496 // -----------------------------------
497 THREAD_PROC Channel::waitFinishMain(ThreadInfo *thread)
499 Channel *ch = (Channel*)thread->data;
500 LOG_DEBUG("Wait channel finish");
502 while(!(ch->thread.finish) && !thread->finish){
506 if (ch->thread.finish){
507 LOG_DEBUG("channel finish");
510 LOG_DEBUG("channel restart");
517 // -----------------------------------
518 THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
520 SEH_THREAD(waitFinishMain, Channel::waitFinish);
524 // -----------------------------------
525 bool Channel::acceptGIV(ClientSocket *givSock)
534 // -----------------------------------
535 void Channel::connectFetch()
537 sock = sys->createSocket();
540 throw StreamException("Can`t create socket");
542 if (sourceHost.tracker || sourceHost.yp)
544 sock->setReadTimeout(30000);
545 sock->setWriteTimeout(30000);
546 LOG_CHANNEL("Channel using longer timeouts");
548 sock->setReadTimeout(5000);
549 sock->setWriteTimeout(5000);
552 sock->open(sourceHost.host);
557 // -----------------------------------
558 int Channel::handshakeFetch()
561 info.id.toStr(idStr);
564 servMgr->sessionID.toStr(sidStr);
566 sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
567 sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
568 sock->writeLineF("%s %d",PCX_HS_PCP,1);
569 sock->writeLineF("%s %d",PCX_HS_PORT,servMgr->serverHost.port);
575 int r = http.readResponse();
577 LOG_CHANNEL("Got response: %d",r);
579 while (http.nextHeader())
581 char *arg = http.getArgStr();
585 if (http.isHeader(PCX_HS_POS))
586 streamPos = atoi(arg);
588 Servent::readICYHeader(http, info, NULL, 0);
590 LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
593 if ((r != 200) && (r != 503))
596 if (!servMgr->keepDownstreams) {
597 if (rawData.getLatestPos() > streamPos)
601 AtomStream atom(*sock);
605 Host rhost = sock->host;
607 if (info.srcProtocol == ChanInfo::SP_PCP)
609 // don`t need PCP_CONNECT here
610 Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
613 if (r == 503) return 503;
618 // -----------------------------------
619 void PeercastSource::stream(Channel *ch)
623 bool next_yp = false;
624 bool tracker_check = (ch->trackerHit.host.ip != 0);
626 int keepDownstreamTime = 7;
628 if (isIndexTxt(&ch->info))
629 keepDownstreamTime = 30;
631 ch->lastStopTime = 0;
634 while (ch->thread.active)
636 ch->skipCount = 0; //JP-EX
637 ch->lastSkipTime = 0;
639 ChanHitList *chl = NULL;
641 ch->sourceHost.init();
643 if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
644 ch->lastIdleTime = sys->getTime();
645 ch->setStatus(Channel::S_IDLE);
647 ch->lastSkipTime = 0;
651 if (!servMgr->keepDownstreams && !ch->bumped) {
652 ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
655 ch->setStatus(Channel::S_SEARCHING);
656 LOG_CHANNEL("Channel searching for hit..");
662 ch->sock = ch->pushSock;
664 ch->sourceHost.host = ch->sock->host;
668 chanMgr->hitlistlock.on();
670 chl = chanMgr->findHitList(ch->info);
676 if (!ch->sourceHost.host.ip){
678 chs.matchHost = servMgr->serverHost;
679 chs.waitDelay = MIN_RELAY_RETRY;
680 chs.excludeID = servMgr->sessionID;
681 if (chl->pickSourceHits(chs)){
682 ch->sourceHost = chs.best[0];
683 LOG_DEBUG("use local hit");
687 // else find global hit
688 if (!ch->sourceHost.host.ip)
691 chs.waitDelay = MIN_RELAY_RETRY;
692 chs.excludeID = servMgr->sessionID;
693 if (chl->pickSourceHits(chs)){
694 ch->sourceHost = chs.best[0];
695 LOG_DEBUG("use global hit");
700 // else find local tracker
701 if (!ch->sourceHost.host.ip)
704 chs.matchHost = servMgr->serverHost;
705 chs.waitDelay = MIN_TRACKER_RETRY;
706 chs.excludeID = servMgr->sessionID;
707 chs.trackersOnly = true;
708 if (chl->pickSourceHits(chs)){
709 ch->sourceHost = chs.best[0];
710 LOG_DEBUG("use local tracker");
714 // else find global tracker
715 if (!ch->sourceHost.host.ip)
718 chs.waitDelay = MIN_TRACKER_RETRY;
719 chs.excludeID = servMgr->sessionID;
720 chs.trackersOnly = true;
721 if (chl->pickSourceHits(chs)){
722 ch->sourceHost = chs.best[0];
723 tracker_check = true;
724 ch->trackerHit = chs.best[0];
725 LOG_DEBUG("use global tracker");
730 unsigned int ctime = sys->getTime();
731 if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
732 if (ch->trackerHit.lastContact + 30 < ctime){
733 ch->sourceHost = ch->trackerHit;
734 ch->trackerHit.lastContact = ctime;
735 LOG_DEBUG("use saved tracker");
740 chanMgr->hitlistlock.off();
742 if (servMgr->keepDownstreams && ch->lastStopTime
743 && ch->lastStopTime < sys->getTime() - keepDownstreamTime)
745 ch->lastStopTime = 0;
746 LOG_DEBUG("------------ disconnect all downstreams");
748 MemoryStream mem(pack.data,sizeof(pack.data));
749 AtomStream atom(mem);
750 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
752 pack.type = ChanPacket::T_PCP;
755 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
757 chanMgr->hitlistlock.on();
758 ChanHitList *hl = chanMgr->findHitList(ch->info);
760 hl->clearHits(false);
762 chanMgr->hitlistlock.off();
765 // no trackers found so contact YP
766 if (!tracker_check && !ch->sourceHost.host.ip)
769 if (servMgr->rootHost.isEmpty())
775 if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
778 unsigned int ctime=sys->getTime();
779 if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
781 ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
782 ch->sourceHost.yp = true;
783 chanMgr->lastYPConnect=ctime;
791 // no trackers found so contact YP2
792 if (!tracker_check && !ch->sourceHost.host.ip)
795 if (servMgr->rootHost2.isEmpty())
798 if (numYPTries2 >= 3)
801 unsigned int ctime=sys->getTime();
802 if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
804 ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
805 ch->sourceHost.yp = true;
806 chanMgr->lastYPConnect2=ctime;
813 if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
817 }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
819 if (!ch->sourceHost.host.ip)
821 LOG_ERROR("Channel giving up");
822 ch->setStatus(Channel::S_ERROR);
826 if (ch->sourceHost.yp)
828 LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
831 LOG_CHANNEL("Channel found hit");
836 if (ch->sourceHost.host.ip)
838 bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
841 //if (ch->sourceHost.tracker)
842 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
845 ch->sourceHost.host.toStr(ipstr);
848 if (ch->sourceHost.tracker)
850 else if (ch->sourceHost.yp)
857 ch->setStatus(Channel::S_CONNECTING);
858 ch->sourceHost.lastContact = sys->getTime();
862 LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
866 error = ch->handshakeFetch();
872 throw StreamException("Handshake error");
873 if (ch->sourceHost.tracker) connFailCnt = 0;
875 if (servMgr->autoMaxRelaySetting) //JP-EX
877 double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
878 if ((unsigned int)setMaxRelays == 0)
879 servMgr->maxRelays = 1;
880 else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
881 servMgr->maxRelays = servMgr->autoMaxRelaySetting;
883 servMgr->maxRelays = (unsigned int)setMaxRelays;
886 ch->sourceStream = ch->createSource();
888 error = ch->readStream(*ch->sock,ch->sourceStream);
890 throw StreamException("Stream error");
892 error = 0; // no errors, closing normally.
893 // ch->setStatus(Channel::S_CLOSING);
894 ch->setStatus(Channel::S_IDLE);
896 LOG_CHANNEL("Channel closed normally");
897 }catch(StreamException &e)
899 ch->setStatus(Channel::S_ERROR);
900 LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
901 if (!servMgr->allowConnectPCST) //JP-EX
903 if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
904 ch->thread.active = false;
906 //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
907 if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
908 chanMgr->deadHit(ch->sourceHost);
909 if (ch->sourceHost.tracker && error == -1) {
910 LOG_ERROR("can't connect to tracker");
915 unsigned int ctime = sys->getTime();
916 if (ch->rawData.lastWriteTime) {
917 ch->lastStopTime = ch->rawData.lastWriteTime;
918 if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
919 ch->lastStopTime = ctime;
922 if (tracker_check && ch->sourceHost.tracker)
923 ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
925 // broadcast source host
926 if (!got503 && !error && ch->sourceHost.host.ip) { // if closed normally
928 MemoryStream mem(pack.data,sizeof(pack.data));
929 AtomStream atom(mem);
930 ch->sourceHost.writeAtoms(atom, ch->info.id);
932 pack.type = ChanPacket::T_PCP;
935 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
936 LOG_DEBUG("stream: broadcast sourceHost");
939 // broadcast quit to any connected downstream servents
940 if (!servMgr->keepDownstreams || !got503 && (ch->sourceHost.tracker || !error)) {
942 MemoryStream mem(pack.data,sizeof(pack.data));
943 AtomStream atom(mem);
944 atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
946 pack.type = ChanPacket::T_PCP;
949 servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
950 LOG_DEBUG("------------ broadcast quit to all downstreams");
952 chanMgr->hitlistlock.on();
953 ChanHitList *hl = chanMgr->findHitList(ch->info);
955 hl->clearHits(false);
957 chanMgr->hitlistlock.off();
961 if (ch->sourceStream)
967 ch->sourceStream->updateStatus(ch);
968 ch->sourceStream->flush(*ch->sock);
970 }catch(StreamException &)
972 ChannelStream *cs = ch->sourceStream;
973 ch->sourceStream = NULL;
987 LOG_ERROR("Channel not found");
989 if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
990 chanMgr->hitlistlock.on();
991 ChanHitList *hl = chanMgr->findHitList(ch->info);
995 chanMgr->hitlistlock.off();
997 if(!isIndexTxt(&ch->info)) // for PCRaw (popup)
998 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
1006 ch->lastIdleTime = sys->getTime();
1007 ch->setStatus(Channel::S_IDLE);
1008 ch->skipCount = 0; //JP-EX
1009 ch->lastSkipTime = 0;
1010 while ((ch->checkIdle()) && (ch->thread.active))
1019 // -----------------------------------
1020 void Channel::startICY(ClientSocket *cs, SRC_TYPE st)
1024 cs->setReadTimeout(0); // stay connected even when theres no data coming through
1026 info.srcProtocol = ChanInfo::SP_HTTP;
1028 streamIndex = ++chanMgr->icyIndex;
1030 sourceData = new ICYSource();
1034 // -----------------------------------
1035 static char *nextMetaPart(char *str,char delim)
1048 // -----------------------------------
1049 static void copyStr(char *to,char *from,int max)
1052 while ((c=*from++) && (--max))
1059 // -----------------------------------
1060 void Channel::processMp3Metadata(char *str)
1062 ChanInfo newInfo = info;
1067 char *arg = nextMetaPart(cmd,'=');
1071 char *next = nextMetaPart(arg,';');
1073 if (strcmp(cmd,"StreamTitle")==0)
1075 newInfo.track.title.setUnquote(arg,String::T_ASCII);
1076 newInfo.track.title.convertTo(String::T_UNICODE);
1078 }else if (strcmp(cmd,"StreamUrl")==0)
1080 newInfo.track.contact.setUnquote(arg,String::T_ASCII);
1081 newInfo.track.contact.convertTo(String::T_UNICODE);
1088 updateInfo(newInfo);
1091 // -----------------------------------
1092 XML::Node *ChanHit::createXML()
1098 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\"",
1110 sys->getTime()-time,
1116 // -----------------------------------
1117 XML::Node *ChanHitList::createXML(bool addHits)
1119 XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
1126 sys->getTime()-newestHit()
1135 hn->add(h->createXML());
1143 // -----------------------------------
1144 XML::Node *Channel::createRelayXML(bool showStat)
1147 ststr = getStatusStr();
1149 if ((status == S_RECEIVING) || (status == S_BROADCASTING))
1152 ChanHitList *chl = chanMgr->findHitList(info);
1154 return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
1157 (chl!=NULL)?chl->numHits():0,
1162 // -----------------------------------
1163 void ChanMeta::fromXML(XML &xml)
1165 MemoryStream tout(data,MAX_DATALEN);
1170 // -----------------------------------
1171 void ChanMeta::fromMem(void *p, int l)
1176 // -----------------------------------
1177 void ChanMeta::addMem(void *p, int l)
1179 if ((len+l) <= MAX_DATALEN)
1181 memcpy(data+len,p,l);
1185 // -----------------------------------
1186 void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
1188 unsigned int ctime = sys->getTime();
1190 if (((ctime-lastTrackerUpdate) > 30) || (force))
1194 MemoryStream mem(pack.data,sizeof(pack));
1196 AtomStream atom(mem);
1200 ChanHitList *chl = chanMgr->findHitListByID(info.id);
1202 throw StreamException("Broadcast channel has no hitlist");
1204 int numListeners = stealth ? -1 : totalListeners(); //JP-MOD
\83\8a\83X
\83i
\81[
\90\94\89B
\95Á
\8b@
\94\
1205 int numRelays = stealth ? -1 : totalRelays(); //JP-MOD
\83\8a\83\8c\81[
\90\94\89B
\95Á
\8b@
\94\
1207 unsigned int oldp = rawData.getOldestPos();
1208 unsigned int newp = rawData.getLatestPos();
1210 hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
1213 if (version_ex == 0)
1215 atom.writeParent(PCP_BCST,8);
1218 atom.writeParent(PCP_BCST,10);
1220 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
1221 atom.writeChar(PCP_BCST_HOPS,0);
1222 atom.writeChar(PCP_BCST_TTL,11);
1223 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1224 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1225 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1229 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1230 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1232 atom.writeParent(PCP_CHAN,4);
1233 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1234 atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
1235 info.writeInfoAtoms(atom);
1236 info.writeTrackAtoms(atom);
1237 hit.writeAtoms(atom,info.id);
1241 pack.type = ChanPacket::T_PCP;
1245 int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
1249 LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
1250 lastTrackerUpdate = ctime;
1255 // -----------------------------------
1256 bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
1259 && (!cid.isSet() || info.id.isSame(cid))
1260 && (!sid.isSet() || !remoteID.isSame(sid))
1263 return sourceStream->sendPacket(pack,did);
1268 // -----------------------------------
1269 void Channel::updateInfo(ChanInfo &newInfo)
1271 if (info.update(newInfo))
1273 if (isBroadcasting())
1275 unsigned int ctime = sys->getTime();
1276 if ((ctime-lastMetaUpdate) > 30)
1278 lastMetaUpdate = ctime;
1282 MemoryStream mem(pack.data,sizeof(pack));
1284 AtomStream atom(mem);
1286 if (version_ex == 0)
1288 atom.writeParent(PCP_BCST,8);
1291 atom.writeParent(PCP_BCST,10);
1293 atom.writeChar(PCP_BCST_HOPS,0);
1294 atom.writeChar(PCP_BCST_TTL,7);
1295 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
1296 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1297 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1298 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1301 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1302 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1304 atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
1305 atom.writeParent(PCP_CHAN,3);
1306 atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
1307 info.writeInfoAtoms(atom);
1308 info.writeTrackAtoms(atom);
1311 pack.type = ChanPacket::T_PCP;
1314 servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
1316 broadcastTrackerUpdate(noID);
1320 ChanHitList *chl = chanMgr->findHitList(info);
1324 peercastApp->channelUpdate(&info);
1329 // -----------------------------------
1330 ChannelStream *Channel::createSource()
1332 // if (servMgr->relayBroadcast)
1333 // chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
1336 ChannelStream *source=NULL;
1338 if (info.srcProtocol == ChanInfo::SP_PEERCAST)
1340 LOG_CHANNEL("Channel is Peercast");
1341 if (servMgr->allowConnectPCST) //JP-EX
1342 source = new PeercastStream();
1344 throw StreamException("Channel is not allowed");
1346 else if (info.srcProtocol == ChanInfo::SP_PCP)
1348 LOG_CHANNEL("Channel is PCP");
1349 PCPStream *pcp = new PCPStream(remoteID);
1352 else if (info.srcProtocol == ChanInfo::SP_MMS)
1354 LOG_CHANNEL("Channel is MMS");
1355 source = new MMSStream();
1358 switch(info.contentType)
1360 case ChanInfo::T_MP3:
1361 LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
1362 source = new MP3Stream();
1364 case ChanInfo::T_NSV:
1365 LOG_CHANNEL("Channel is NSV");
1366 source = new NSVStream();
1368 case ChanInfo::T_WMA:
1369 case ChanInfo::T_WMV:
1370 throw StreamException("Channel is WMA/WMV - but not MMS");
1372 case ChanInfo::T_OGG:
1373 case ChanInfo::T_OGM:
1374 LOG_CHANNEL("Channel is OGG");
1375 source = new OGGStream();
1378 LOG_CHANNEL("Channel is Raw");
1379 source = new RawStream();
1384 source->parent = this;
1388 // ------------------------------------------
1389 void ChannelStream::updateStatus(Channel *ch)
1392 if (getStatus(ch,pack))
1394 if (!ch->isBroadcasting())
1398 int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
1399 LOG_CHANNEL("Sent channel status update to %d clients",cnt);
1404 // ------------------------------------------
1405 bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
1407 unsigned int ctime = sys->getTime();
1409 if ((ch->isPlaying() == isPlaying)){
1410 if ((ctime-lastUpdate) < 10){
1414 if ((ctime-lastCheckTime) < 5){
1417 lastCheckTime = ctime;
1420 ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
1425 /* int newLocalListeners = ch->localListeners();
1426 int newLocalRelays = ch->localRelays();
1430 (numListeners != newLocalListeners)
1431 || (numRelays != newLocalRelays)
1432 || (ch->isPlaying() != isPlaying)
1433 || (servMgr->getFirewall() != fwState)
1434 || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1436 && ((ctime-lastUpdate) > 10)
1440 numListeners = newLocalListeners;
1441 numRelays = newLocalRelays;
1442 isPlaying = ch->isPlaying();
1443 fwState = servMgr->getFirewall();
1448 hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
1449 hit.tracker = ch->isBroadcasting();*/
1451 int newLocalListeners = ch->localListeners();
1452 int newLocalRelays = ch->localRelays();
1454 unsigned int oldp = ch->rawData.getOldestPos();
1455 unsigned int newp = ch->rawData.getLatestPos();
1459 // LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
1461 hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
1463 if(!(ch->info.ppFlags & ServMgr::bcstClap))
1465 hit.initLocal_pp(ch->stealth, ch->bClap ? 1 : 0);
1467 hit.tracker = ch->isBroadcasting();
1469 if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
1470 || (newLocalListeners != numListeners)
1471 || (newLocalRelays != numRelays)
1472 || (ch->isPlaying() != isPlaying)
1473 || (servMgr->getFirewall() != fwState)
1474 || (ch->chDisp.relay != hit.relay)
1475 || (ch->chDisp.relayfull != hit.relayfull)
1476 || (ch->chDisp.chfull != hit.chfull)
1477 || (ch->chDisp.ratefull != hit.ratefull)
1478 || (ch->bClap && ((ctime-lastClapped) > 60)) //JP-MOD
1480 numListeners = newLocalListeners;
1481 numRelays = newLocalRelays;
1482 isPlaying = ch->isPlaying();
1483 fwState = servMgr->getFirewall();
1486 if(ch->bClap){ //JP-MOD
1487 lastClapped = ctime;
1493 if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
1494 ch->stayConnected = true;
1496 if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
1497 ch->stayConnected = false;
1499 MemoryStream pmem(pack.data,sizeof(pack.data));
1500 AtomStream atom(pmem);
1505 if (version_ex == 0)
1507 atom.writeParent(PCP_BCST,8);
1510 atom.writeParent(PCP_BCST,10);
1512 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
1513 atom.writeChar(PCP_BCST_HOPS,0);
1514 atom.writeChar(PCP_BCST_TTL,11);
1515 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
1516 atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
1517 atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
1520 atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
1521 atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
1523 atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
1524 hit.writeAtoms(atom,noID);
1526 pack.len = pmem.pos;
1527 pack.type = ChanPacket::T_PCP;
1532 // -----------------------------------
1533 bool Channel::checkBump()
1535 unsigned int maxIdleTime = 30;
1536 if (isIndexTxt(this)) maxIdleTime = 60;
1538 if (!isBroadcasting() && (!sourceHost.tracker))
1539 if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > maxIdleTime))
1541 LOG_ERROR("Channel Auto bumped");
1553 // -----------------------------------
1554 int Channel::readStream(Stream &in,ChannelStream *source)
1562 source->readHeader(in,this);
1564 peercastApp->channelStart(&info);
1566 rawData.lastWriteTime = 0;
1568 bool wasBroadcasting=false;
1570 unsigned int receiveStartTime = 0;
1572 unsigned int ptime = 0;
1573 unsigned int upsize = 0;
1577 while (thread.active && !peercastInst->isQuitting)
1581 LOG_DEBUG("Channel idle");
1587 LOG_DEBUG("Channel bumped");
1595 LOG_DEBUG("Channel eof");
1601 error = source->readPacket(in,this);
1606 //if (rawData.writePos > 0)
1607 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1609 if (isBroadcasting())
1611 if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
1615 broadcastTrackerUpdate(noID);
1617 wasBroadcasting = true;
1621 /* if (status != Channel::S_RECEIVING){
1622 receiveStartTime = sys->getTime();
1623 } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
1624 chanMgr->hitlistlock.on();
1625 ChanHitList *hl = chanMgr->findHitList(info);
1627 hl->clearHits(true);
1629 chanMgr->hitlistlock.off();
1630 receiveStartTime = 0;
1632 setStatus(Channel::S_RECEIVING);
1635 //source->updateStatus(this);
1638 if (rawData.lastWriteTime > 0 || rawData.lastSkipTime > 0)
1639 source->updateStatus(this);
1641 unsigned int t = sys->getTime();
1644 upsize = Servent::MAX_OUTWARD_SIZE;
1647 unsigned int len = source->flushUb(in, upsize);
1652 }catch(StreamException &e)
1654 LOG_ERROR("readStream: %s",e.msg);
1658 if (!servMgr->keepDownstreams) {
1659 if (status == Channel::S_RECEIVING){
1660 chanMgr->hitlistlock.on();
1661 ChanHitList *hl = chanMgr->findHitList(info);
1663 hl->clearHits(false);
1665 chanMgr->hitlistlock.off();
1669 // setStatus(S_CLOSING);
1672 if (wasBroadcasting)
1676 broadcastTrackerUpdate(noID,true);
1679 peercastApp->channelStop(&info);
1681 source->readEnd(in,this);
1686 // -----------------------------------
1687 void PeercastStream::readHeader(Stream &in,Channel *ch)
1689 if (in.readTag() != 'PCST')
1690 throw StreamException("Not PeerCast stream");
1693 // -----------------------------------
1694 void PeercastStream::readEnd(Stream &,Channel *)
1698 // -----------------------------------
1699 int PeercastStream::readPacket(Stream &in,Channel *ch)
1705 pack.readPeercast(in);
1707 MemoryStream mem(pack.data,pack.len);
1711 case ChanPacket::T_HEAD:
1713 ch->headPack = pack;
1714 pack.pos = ch->streamPos;
1715 ch->newPacket(pack);
1716 ch->streamPos+=pack.len;
1718 case ChanPacket::T_DATA:
1719 pack.pos = ch->streamPos;
1720 ch->newPacket(pack);
1721 ch->streamPos+=pack.len;
1723 case ChanPacket::T_META:
1724 ch->insertMeta.fromMem(pack.data,pack.len);
1730 XML::Node *n = xml.findNode("channel");
1733 ChanInfo newInfo = ch->info;
1734 newInfo.updateFromXML(n);
1735 ChanHitList *chl = chanMgr->findHitList(ch->info);
1737 newInfo.updateFromXML(n);
1738 ch->updateInfo(newInfo);
1744 case ChanPacket::T_SYNC:
1746 unsigned int s = mem.readLong();
1747 if ((s-ch->syncPos) != 1)
1749 LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
1752 ch->info.numSkips++;
1753 if (ch->info.numSkips>50)
1754 throw StreamException("Bumped - Too many skips");
1769 // -----------------------------------
1770 void ChannelStream::readRaw(Stream &in, Channel *ch)
1774 const int readLen = 8192;
1776 pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
1777 in.read(pack.data,pack.len);
1778 ch->newPacket(pack);
1779 ch->checkReadDelay(pack.len);
1781 ch->streamPos+=pack.len;
1784 // ------------------------------------------
1785 void RawStream::readHeader(Stream &,Channel *)
1789 // ------------------------------------------
1790 int RawStream::readPacket(Stream &in,Channel *ch)
1796 // ------------------------------------------
1797 void RawStream::readEnd(Stream &,Channel *)
1803 // -----------------------------------
1804 void ChanPacket::init(ChanPacketv &p)
1808 if (len > MAX_DATALEN)
1809 throw StreamException("Packet data too large");
1813 priority = p.priority;
1814 memcpy(data, p.data, len);
1816 // -----------------------------------
1817 void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
1820 if (l > MAX_DATALEN)
1821 throw StreamException("Packet data too large");
1828 // -----------------------------------
1829 void ChanPacket::writeRaw(Stream &out)
1831 out.write(data,len);
1833 // -----------------------------------
1834 void ChanPacket::writePeercast(Stream &out)
1836 unsigned int tp = 0;
1839 case T_HEAD: tp = 'HEAD'; break;
1840 case T_META: tp = 'META'; break;
1841 case T_DATA: tp = 'DATA'; break;
1844 if (type != T_UNKNOWN)
1847 out.writeShort(len);
1849 out.write(data,len);
1852 // -----------------------------------
1853 void ChanPacket::readPeercast(Stream &in)
1855 unsigned int tp = in.readTag();
1859 case 'HEAD': type = T_HEAD; break;
1860 case 'DATA': type = T_DATA; break;
1861 case 'META': type = T_META; break;
1862 default: type = T_UNKNOWN;
1864 len = in.readShort();
1866 if (len > MAX_DATALEN)
1867 throw StreamException("Bad ChanPacket");
1870 // -----------------------------------
1871 int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
1881 for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
1883 //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
1884 ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
1885 if (src->type & accept)
1887 if (src->pos >= reqPos)
1890 //packets[writePos++] = *src;
1891 packets[writePos++].init(*src);
1900 return lastPos-firstPos;
1903 // -----------------------------------
1904 bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
1911 unsigned int bound = packets[0].len * ChanPacketBuffer::MAX_PACKETS * 2; // max packets to wait
1912 unsigned int fpos = getFirstDataPos();
1913 unsigned int lpos = getLatestPos();
1914 if ((spos < fpos && fpos <= lpos && spos != getStreamPosEnd(lastPos)) // --s-----f---l--
1915 || (spos < fpos && lpos < fpos && spos > lpos + bound) // -l-------s--f--
1916 || (spos > lpos && lpos >= fpos && spos - lpos > bound)) // --f---l------s-
1920 for(unsigned int i=firstPos; i<=lastPos; i++)
1922 //ChanPacket &p = packets[i%MAX_PACKETS];
1923 ChanPacketv &p = packets[i%MAX_PACKETS];
1924 if (p.pos >= spos && p.pos - spos <= bound)
1935 // -----------------------------------
1936 unsigned int ChanPacketBuffer::getLatestPos()
1941 return getStreamPos(lastPos);
1944 // -----------------------------------
1945 unsigned int ChanPacketBuffer::getFirstDataPos()
1949 for(unsigned int i=firstPos; i<=lastPos; i++)
1951 if (packets[i%MAX_PACKETS].type == ChanPacket::T_DATA)
1952 return packets[i%MAX_PACKETS].pos;
1956 // -----------------------------------
1957 unsigned int ChanPacketBuffer::getOldestPos()
1962 return getStreamPos(firstPos);
1965 // -----------------------------------
1966 unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos)
1968 unsigned int min = getStreamPos(safePos);
1969 unsigned int max = getStreamPos(lastPos);
1980 // -----------------------------------
1981 unsigned int ChanPacketBuffer::getStreamPos(unsigned int index)
1983 return packets[index%MAX_PACKETS].pos;
1985 // -----------------------------------
1986 unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index)
1988 return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
1990 // -----------------------------------
1991 bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
1995 if (servMgr->keepDownstreams) {
1996 unsigned int lpos = getLatestPos();
1997 unsigned int diff = pack.pos - lpos;
1998 if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
1999 if (lpos && (diff == 0 || diff > 0xfff00000)) {
2000 LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
2001 lastSkipTime = sys->getTime();
2006 if (willSkip()) // too far behind
2008 lastSkipTime = sys->getTime();
2014 pack.sync = writePos;
2015 packets[writePos%MAX_PACKETS].init(pack);
2017 // LOG_DEBUG("packet.len = %d",pack.len);
2023 if (writePos >= MAX_PACKETS)
2024 firstPos = writePos-MAX_PACKETS;
2028 if (writePos >= NUM_SAFEPACKETS)
2029 safePos = writePos - NUM_SAFEPACKETS;
2036 lastWriteTime = sys->getTime();
2044 // -----------------------------------
2045 void ChanPacketBuffer::readPacket(ChanPacket &pack)
2048 unsigned int tim = sys->getTime();
2050 if (readPos < firstPos)
2051 throw StreamException("Read too far behind");
2053 while (readPos >= writePos)
2056 if ((sys->getTime() - tim) > 30)
2057 throw TimeoutException();
2060 pack.init(packets[readPos%MAX_PACKETS]);
2065 // -----------------------------------
2066 void ChanPacketBuffer::readPacketPri(ChanPacket &pack)
2068 unsigned int tim = sys->getTime();
2070 if (readPos < firstPos)
2071 throw StreamException("Read too far behind");
2073 while (readPos >= writePos)
2076 if ((sys->getTime() - tim) > 30)
2077 throw TimeoutException();
2080 ChanPacketv *best = &packets[readPos % MAX_PACKETS];
2081 for (unsigned int i = readPos + 1; i < writePos; i++) {
2082 if (packets[i % MAX_PACKETS].priority > best->priority)
2083 best = &packets[i % MAX_PACKETS];
2086 best->init(packets[readPos % MAX_PACKETS]);
2091 // -----------------------------------
2092 bool ChanPacketBuffer::willSkip()
2094 return ((writePos-readPos) >= MAX_PACKETS);
2097 // -----------------------------------
2098 void Channel::getStreamPath(char *str)
2104 sprintf(str,"/stream/%s%s",idStr,info.getTypeExt());
2109 // -----------------------------------
2110 void ChanMgr::startSearch(ChanInfo &info)
2117 searchActive = true;
2119 // -----------------------------------
2120 void ChanMgr::quit()
2122 LOG_DEBUG("ChanMgr is quitting..");
2125 // -----------------------------------
2126 int ChanMgr::numIdleChannels()
2129 Channel *ch = channel;
2133 if (ch->thread.active)
2134 if (ch->status == Channel::S_IDLE)
2140 // -----------------------------------
2141 void ChanMgr::closeOldestIdle()
2143 unsigned int idleTime = (unsigned int)-1;
2144 Channel *ch = channel,*oldest=NULL;
2148 if (ch->thread.active)
2149 if (ch->status == Channel::S_IDLE)
2150 if (ch->lastIdleTime < idleTime)
2153 idleTime = ch->lastIdleTime;
2159 oldest->thread.active = false;
2162 // -----------------------------------
2163 void ChanMgr::closeAll()
2165 Channel *ch = channel;
2168 if (ch->thread.active)
2169 ch->thread.shutdown();
2173 // -----------------------------------
2174 Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
2176 Channel *ch = channel;
2180 if (ch->info.matchNameID(info))
2187 // -----------------------------------
2188 Channel *ChanMgr::findChannelByName(const char *n)
2190 Channel *ch = channel;
2194 if (stricmp(ch->info.name,n)==0)
2201 // -----------------------------------
2202 Channel *ChanMgr::findChannelByIndex(int index)
2205 Channel *ch = channel;
2218 // -----------------------------------
2219 Channel *ChanMgr::findChannelByMount(const char *str)
2221 Channel *ch = channel;
2225 if (strcmp(ch->mount,str)==0)
2232 // -----------------------------------
2233 Channel *ChanMgr::findChannelByID(GnuID &id)
2235 Channel *ch = channel;
2239 if (ch->info.id.isSame(id))
2245 // -----------------------------------
2246 Channel *ChanMgr::findChannelByChannelID(int id)
2249 Channel *ch = channel;
2252 if (ch->isActive()){
2253 if (ch->channel_id == id){
2261 // -----------------------------------
2262 int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
2265 Channel *ch = channel;
2269 if (ch->info.match(info))
2279 // -----------------------------------
2280 int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
2283 Channel *ch = channel;
2287 if (ch->status == status)
2297 // -----------------------------------
2298 Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
2300 Channel *c = chanMgr->createChannel(info,NULL);
2303 c->stayConnected = stayConnected;
2309 // -----------------------------------
2310 Channel *ChanMgr::findAndRelay(ChanInfo &info)
2313 info.id.toStr(idStr);
2314 LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
2316 if(!isIndexTxt(&info)) // for PCRaw (popup)
2317 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
2322 WLockBlock wb(&(chanMgr->channellock));
2326 c = findChannelByNameID(info);
2330 c = chanMgr->createChannel(info,NULL);
2333 c->setStatus(Channel::S_SEARCHING);
2336 } else if (!(c->thread.active)){
2337 c->thread.active = true;
2338 c->thread.finish = false;
2339 c->info.lastPlayStart = 0; // reconnect
2340 c->info.lastPlayEnd = 0;
2342 c->finthread->finish = true;
2343 c->finthread = NULL;
2345 if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
2346 c->setStatus(Channel::S_SEARCHING);
2353 for(int i=0; i<600; i++) // search for 1 minute.
2358 c = findChannelByNameID(info);
2362 // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
2367 if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
2377 // -----------------------------------
2384 currFindAndPlayChannel.clear();
2386 broadcastMsg.clear();
2387 broadcastMsgInterval=10;
2389 broadcastID.generate(PCP_BROADCAST_FLAGS);
2394 icyMetaInterval = 8192;
2395 maxRelaysPerChannel = 1;
2399 minBroadcastTTL = 1;
2400 maxBroadcastTTL = 7;
2402 pushTimeout = 60; // 1 minute
2403 pushTries = 5; // 5 times
2404 maxPushHops = 8; // max 8 hops away
2405 maxUptime = 0; // 0 = none
2407 prefetchTime = 10; // n seconds
2409 hostUpdateInterval = 120; // 2 minutes
2421 // -----------------------------------
2422 bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
2425 if (var == "numHitLists")
2426 sprintf(buf,"%d",numHitLists());
2428 else if (var == "numChannels")
2429 sprintf(buf,"%d",numChannels());
2430 else if (var == "djMessage")
2432 String utf8 = broadcastMsg;
2433 utf8.convertTo(String::T_UNICODESAFE);
2434 strcpy(buf,utf8.cstr());
2436 else if (var == "icyMetaInterval")
2437 sprintf(buf,"%d",icyMetaInterval);
2438 else if (var == "maxRelaysPerChannel")
2439 sprintf(buf,"%d",maxRelaysPerChannel);
2440 else if (var == "hostUpdateInterval")
2441 sprintf(buf,"%d",hostUpdateInterval);
2442 else if (var == "broadcastID")
2443 broadcastID.toStr(buf);
2449 out.writeString(buf);
2453 // -----------------------------------
2454 bool Channel::writeVariable(Stream &out, const String &var, int index)
2465 utf8.convertTo(String::T_UNICODESAFE);
2466 strcpy(buf,utf8.cstr());
2468 }else if (var == "bitrate")
2470 sprintf(buf,"%d",info.bitrate);
2472 }else if (var == "srcrate")
2476 unsigned int tot = sourceData->getSourceRate();
2477 sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
2481 }else if (var == "genre")
2484 utf8.convertTo(String::T_UNICODESAFE);
2485 strcpy(buf,utf8.cstr());
2486 }else if (var == "desc")
2489 utf8.convertTo(String::T_UNICODESAFE);
2490 strcpy(buf,utf8.cstr());
2491 }else if (var == "comment")
2493 utf8 = info.comment;
2494 utf8.convertTo(String::T_UNICODESAFE);
2495 strcpy(buf,utf8.cstr());
2496 }else if (var == "bcstClap") //JP-MOD
2498 strcpy(buf,info.ppFlags & ServMgr::bcstClap ? "1":"0");
2499 }else if (var == "uptime")
2502 if (info.lastPlayStart)
2503 uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
2506 strcpy(buf,uptime.cstr());
2508 else if (var == "type")
2509 sprintf(buf,"%s",info.getTypeStr());
2510 else if (var == "ext")
2511 sprintf(buf,"%s",info.getTypeExt());
2512 else if (var == "proto") {
2513 switch(info.contentType) {
2514 case ChanInfo::T_WMA:
2515 case ChanInfo::T_WMV:
2516 sprintf(buf, "mms://");
2519 sprintf(buf, "http://");
2522 else if (var == "localRelays")
2523 sprintf(buf,"%d",localRelays());
2524 else if (var == "localListeners")
2525 sprintf(buf,"%d",localListeners());
2527 else if (var == "totalRelays")
2528 sprintf(buf,"%d",totalRelays());
2529 else if (var == "totalListeners")
2530 sprintf(buf,"%d",totalListeners());
2531 else if (var == "totalClaps") //JP-MOD
2532 sprintf(buf,"%d",totalClaps());
2533 else if (var == "status")
2534 sprintf(buf,"%s",getStatusStr());
2535 else if (var == "keep")
2536 sprintf(buf,"%s",stayConnected?"Yes":"No");
2537 else if (var == "id")
2539 else if (var.startsWith("track."))
2542 if (var == "track.title")
2543 utf8 = info.track.title;
2544 else if (var == "track.artist")
2545 utf8 = info.track.artist;
2546 else if (var == "track.album")
2547 utf8 = info.track.album;
2548 else if (var == "track.genre")
2549 utf8 = info.track.genre;
2550 else if (var == "track.contactURL")
2551 utf8 = info.track.contact;
2553 utf8.convertTo(String::T_UNICODESAFE);
2554 strcpy(buf,utf8.cstr());
2556 }else if (var == "contactURL")
2557 sprintf(buf,"%s",info.url.cstr());
2558 else if (var == "streamPos")
2559 sprintf(buf,"%d",streamPos);
2560 else if (var == "sourceType")
2561 strcpy(buf,getSrcTypeStr());
2562 else if (var == "sourceProtocol")
2563 strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
2564 else if (var == "sourceURL")
2566 if (sourceURL.isEmpty())
2567 sourceHost.host.toStr(buf);
2569 strcpy(buf,sourceURL.cstr());
2571 else if (var == "headPos")
2572 sprintf(buf,"%d",headPack.pos);
2573 else if (var == "headLen")
2574 sprintf(buf,"%d",headPack.len);
2575 else if (var == "numHits")
2577 ChanHitList *chl = chanMgr->findHitListByID(info.id);
2580 // numHits = chl->numHits();
2588 sprintf(buf,"%d",numHits);
2589 } else if (var == "isBroadcast")
2590 strcpy(buf, (type == T_BROADCAST) ? "1":"0");
2594 out.writeString(buf);
2598 // -----------------------------------
2599 void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
2601 Channel *c = channel;
2604 if ( c->isActive() && c->isBroadcasting() )
2605 c->broadcastTrackerUpdate(svID,force);
2611 // -----------------------------------
2612 int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
2616 Channel *c = channel;
2619 if (c->sendPacketUp(pack,chanID,srcID,destID))
2627 // -----------------------------------
2628 void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
2630 //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
2633 Host sh = servMgr->serverHost;
2634 bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
2635 bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
2636 bool stable = servMgr->totalStreams>0;
2643 Channel *c = channel;
2649 bool tracker = c->isBroadcasting();
2651 int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds
2659 if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
2665 serv->outputPacket(hit,false);
2669 LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);
2676 // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);
2679 // -----------------------------------
2680 void ChanMgr::setUpdateInterval(unsigned int v)
2682 hostUpdateInterval = v;
2686 // -----------------------------------
2690 MemoryStream mem(pack.data,sizeof(pack.data));
2691 AtomStream atom(mem);
2692 atom.writeParent(PCP_BCST,3);
2693 atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
2694 atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
2695 atom.writeParent(PCP_MESG,1);
2696 atom.writeString(PCP_MESG_DATA,msg.cstr());
2706 PCPStream::readAtom(atom,bcs);
2707 //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2708 //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
2709 //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
2710 //LOG_DEBUG("Sent message to %d clients",cnt);
2712 // -----------------------------------
2713 void ChanMgr::setBroadcastMsg(String &msg)
2715 if (!msg.isSame(broadcastMsg))
2719 Channel *c = channel;
2722 if (c->isActive() && c->isBroadcasting())
2724 ChanInfo newInfo = c->info;
2725 newInfo.comment = broadcastMsg;
2726 c->updateInfo(newInfo);
2735 // -----------------------------------
2736 void ChanMgr::clearHitLists()
2739 // LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
2740 chanMgr->hitlistlock.on();
2743 peercastApp->delChannel(&hitlist->info);
2745 ChanHitList *next = hitlist->next;
2751 // LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
2752 chanMgr->hitlistlock.off();
2754 // -----------------------------------
2755 Channel *ChanMgr::deleteChannel(Channel *delchan)
2759 Channel *ch = channel,*prev=NULL,*next=NULL;
2765 Channel *next = ch->next;
2771 if (delchan->sourceStream){
2772 delchan->sourceStream->parent = NULL;
2788 // -----------------------------------
2789 Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
2802 nc->info.lastPlayStart = 0;
2803 nc->info.lastPlayEnd = 0;
2804 nc->info.status = ChanInfo::S_UNKNOWN;
2806 nc->mount.set(mount);
2807 nc->setStatus(Channel::S_WAIT);
2808 nc->type = Channel::T_ALLOCATED;
2809 nc->info.createdTime = sys->getTime();
2811 LOG_CHANNEL("New channel created");
2816 // -----------------------------------
2817 int ChanMgr::pickHits(ChanHitSearch &chs)
2819 ChanHitList *chl = hitlist;
2823 if (chl->pickHits(chs))
2833 // -----------------------------------
2834 ChanHitList *ChanMgr::findHitList(ChanInfo &info)
2836 ChanHitList *chl = hitlist;
2840 if (chl->info.matchNameID(info))
2847 // -----------------------------------
2848 ChanHitList *ChanMgr::findHitListByID(GnuID &id)
2850 ChanHitList *chl = hitlist;
2854 if (chl->info.id.isSame(id))
2860 // -----------------------------------
2861 int ChanMgr::numHitLists()
2864 ChanHitList *chl = hitlist;
2873 // -----------------------------------
2874 ChanHitList *ChanMgr::addHitList(ChanInfo &info)
2876 ChanHitList *chl = new ChanHitList();
2879 chl->next = hitlist;
2884 chl->info.createdTime = sys->getTime();
2885 peercastApp->addChannel(&chl->info);
2890 // -----------------------------------
2891 void ChanMgr::clearDeadHits(bool clearTrackers)
2893 unsigned int interval;
2895 if (servMgr->isRoot)
2896 interval = 1200; // mainly for old 0.119 clients
2898 interval = hostUpdateInterval+120;
2900 chanMgr->hitlistlock.on();
2901 ChanHitList *chl = hitlist,*prev = NULL;
2906 if (chl->clearDeadHits(interval,clearTrackers) == 0)
2908 if (!isBroadcasting(chl->info.id))
2910 if (!chanMgr->findChannelByID(chl->info.id))
2912 peercastApp->delChannel(&chl->info);
2914 ChanHitList *next = chl->next;
2930 chanMgr->hitlistlock.off();
2932 // -----------------------------------
2933 bool ChanMgr::isBroadcasting(GnuID &id)
2935 Channel *ch = findChannelByID(id);
2937 return ch->isBroadcasting();
2941 // -----------------------------------
2942 bool ChanMgr::isBroadcasting()
2944 Channel *ch = channel;
2948 if (ch->isBroadcasting())
2956 // -----------------------------------
2957 int ChanMgr::numChannels()
2960 Channel *ch = channel;
2970 // -----------------------------------
2971 void ChanMgr::deadHit(ChanHit &hit)
2973 ChanHitList *chl = findHitListByID(hit.chanID);
2977 // -----------------------------------
2978 void ChanMgr::delHit(ChanHit &hit)
2980 ChanHitList *chl = findHitListByID(hit.chanID);
2985 // -----------------------------------
2986 void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
2992 hit.rhost[1].init();
2993 hit.tracker = tracker;
2998 // -----------------------------------
2999 ChanHit *ChanMgr::addHit(ChanHit &h)
3002 lastHit = sys->getTime();
3004 ChanHitList *hl=NULL;
3006 hl = findHitListByID(h.chanID);
3012 hl = addHitList(info);
3017 return hl->addHit(h);
3022 // -----------------------------------
3023 bool ChanMgr::findParentHit(ChanHit &p)
3025 ChanHitList *hl=NULL;
3027 chanMgr->hitlistlock.on();
3029 hl = findHitListByID(p.chanID);
3033 ChanHit *ch = hl->hit;
3036 if (!ch->dead && (ch->rhost[0].ip == p.uphost.ip)
3037 && (ch->rhost[0].port == p.uphost.port))
3039 chanMgr->hitlistlock.off();
3046 chanMgr->hitlistlock.off();
3051 // -----------------------------------
3052 class ChanFindInfo : public ThreadInfo
3058 // -----------------------------------
3059 THREAD_PROC findAndPlayChannelProcMain(ThreadInfo *th)
3061 ChanFindInfo *cfi = (ChanFindInfo *)th;
3067 Channel *ch = chanMgr->findChannelByNameID(info);
3069 chanMgr->currFindAndPlayChannel = info.id;
3072 ch = chanMgr->findAndRelay(info);
3076 // check that a different channel hasn`t be selected already.
3077 if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
3078 chanMgr->playChannel(ch->info);
3081 ch->stayConnected = cfi->keep;
3088 // -----------------------------------
3089 THREAD_PROC findAndPlayChannelProc(ThreadInfo *thread)
3091 SEH_THREAD(findAndPlayChannelProcMain, findAndPlayChannel);
3094 // -----------------------------------
3095 void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
3097 ChanFindInfo *cfi = new ChanFindInfo;
3100 cfi->func = findAndPlayChannelProc;
3103 sys->startThread(cfi);
3105 // -----------------------------------
3106 void ChanMgr::playChannel(ChanInfo &info)
3109 char str[128],fname[256],idStr[128];
3111 sprintf(str,"http://127.0.0.1:%d",servMgr->serverHost.port);
3112 info.id.toStr(idStr);
3114 PlayList::TYPE type;
3117 if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
3119 type = PlayList::T_ASX;
3120 // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
3121 // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
3122 if (servMgr->getModulePath) //JP-EX
3124 peercastApp->getDirectory();
3125 sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);
3127 sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
3128 }else if (info.contentType == ChanInfo::T_OGM)
3130 type = PlayList::T_RAM;
3131 if (servMgr->getModulePath) //JP-EX
3133 peercastApp->getDirectory();
3134 sprintf(fname,"%s/play.ram",servMgr->modulePath);
3136 sprintf(fname,"%s/play.ram",peercastApp->getPath());
3140 type = PlayList::T_SCPLS;
3141 if (servMgr->getModulePath) //JP-EX
3143 peercastApp->getDirectory();
3144 sprintf(fname,"%s/play.pls",servMgr->modulePath);
3146 sprintf(fname,"%s/play.pls",peercastApp->getPath());
3150 PlayList *pls = new PlayList(type,1);
3151 pls->addChannel(str,info);
3154 LOG_DEBUG("Writing %s",fname);
3156 file.openWriteReplace(fname);
3161 LOG_DEBUG("Executing: %s",fname);
3162 sys->executeFile(fname);
3167 // -----------------------------------
3168 ChanHitList::ChanHitList()
3175 // -----------------------------------
3176 ChanHitList::~ChanHitList()
3178 chanMgr->hitlistlock.on();
3180 hit = deleteHit(hit);
3181 chanMgr->hitlistlock.off();
3183 // -----------------------------------
3184 void ChanHit::pickNearestIP(Host &h)
3186 for(int i=0; i<2; i++)
3188 if (h.classType() == rhost[i].classType())
3196 // -----------------------------------
3197 void ChanHit::init()
3208 clap_pp = 0; //JP-MOD
3210 dead = tracker = firewalled = stable = yp = false;
3211 recv = cin = direct = relay = true;
3212 relayfull = chfull = ratefull = false;
3221 version_ex_prefix[0] = ' ';
3222 version_ex_prefix[1] = ' ';
3223 version_ex_number = 0;
3232 oldestPos = newestPos = 0;
3237 // -----------------------------------
3238 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)
3241 firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
3242 numListeners = numl;
3245 stable = servMgr->totalStreams>0;
3246 sessionID = servMgr->sessionID;
3249 direct = !servMgr->directFull();
3250 // relay = !servMgr->relaysFull();
3251 cin = !servMgr->controlInFull();
3253 relayfull = servMgr->relaysFull();
3256 Channel *c = chanMgr->channel;
3258 unsigned int needRate = 0;
3259 unsigned int allRate = 0;
3261 if (c->isPlaying()){
3262 allRate += c->info.bitrate * c->localRelays();
3263 if ((c != ch) && (c->localRelays() == 0)){
3264 if(!isIndexTxt(c)) // for PCRaw (relay)
3266 needRate+=c->info.bitrate;
3271 unsigned int numRelay = servMgr->numStreams(Servent::T_RELAY,false);
3272 int diff = servMgr->maxRelays - numRelay;
3273 if (ch->localRelays()){
3274 if (noRelay > diff){
3282 // ratefull = servMgr->bitrateFull(needRate+bitrate);
3283 ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
3285 if (!isIndexTxt(ch))
3286 relay = (!relayfull) && (!chfull) && (!ratefull) && (numRelay + noRelay < servMgr->maxRelays);
3288 relay = (!chfull) && (!ratefull); // for PCRaw (relay)
3291 LOG_DEBUG("Reject by relay full");
3294 LOG_DEBUG("Reject by channel full");
3297 LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
3300 host = servMgr->serverHost;
3302 version = PCP_CLIENT_VERSION;
3303 version_vp = PCP_CLIENT_VERSION_VP;
3306 strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
3307 version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
3310 version_ex_prefix[0] = ' ';
3311 version_ex_prefix[1] = ' ';
3312 version_ex_number = 0;
3315 status = ch->status;
3317 rhost[0] = Host(host.ip,host.port);
3318 rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
3326 uphost.ip = ch->sourceHost.host.ip;
3327 uphost.port = ch->sourceHost.host.port;
3331 // -----------------------------------
3332 void ChanHit::initLocal_pp(bool isStealth, int numClaps) //JP-MOD
3334 numListeners = numListeners && !isStealth ? 1 : 0;
3338 // -----------------------------------
3339 void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
3341 bool addChan=chanID.isSet();
3342 bool uphostdata=(uphost.ip != 0);
3345 if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
3346 if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
3347 if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
3348 if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
3349 if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
3350 if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
3352 atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0) + (clap_pp?1:0/*JP-MOD*/));
3355 atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
3356 atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
3357 atom.writeInt(PCP_HOST_IP,rhost[0].ip);
3358 atom.writeShort(PCP_HOST_PORT,rhost[0].port);
3359 atom.writeInt(PCP_HOST_IP,rhost[1].ip);
3360 atom.writeShort(PCP_HOST_PORT,rhost[1].port);
3361 atom.writeInt(PCP_HOST_NUML,numListeners);
3362 atom.writeInt(PCP_HOST_NUMR,numRelays);
3363 atom.writeInt(PCP_HOST_UPTIME,upTime);
3364 atom.writeInt(PCP_HOST_VERSION,version);
3365 atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
3366 if (version_ex_number){
3367 atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
3368 atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
3370 atom.writeChar(PCP_HOST_FLAGS1,fl1);
3371 atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
3372 atom.writeInt(PCP_HOST_NEWPOS,newestPos);
3374 atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
3375 atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
3376 atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
3378 if (clap_pp){ //JP-MOD
3379 atom.writeInt(PCP_HOST_CLAP_PP,clap_pp);
3382 // -----------------------------------
3383 bool ChanHit::writeVariable(Stream &out, const String &var)
3387 if (var == "rhost0")
3389 if (servMgr->enableGetName) //JP-EX s
3395 strcpy(buf,"<font color=red>");
3397 strcpy(buf,"<font color=orange>");
3402 strcpy(buf,"<font color=purple>");
3404 strcpy(buf,"<font color=blue>");
3407 strcpy(buf,"<font color=green>");
3411 rhost[0].toStr(buf2);
3415 if (ClientSocket::getHostname(h_name,sizeof(h_name),rhost[0].ip)) // BOF
\91Î
\8dô
\82Á
\82Û
\82¢
3421 strcat(buf,"</font>");
3424 rhost[0].toStr(buf);
3426 else if (var == "rhost1")
3427 rhost[1].toStr(buf);
3428 else if (var == "numHops")
3429 sprintf(buf,"%d",numHops);
3430 else if (var == "numListeners")
3431 sprintf(buf,"%d",numListeners);
3432 else if (var == "numRelays")
3433 sprintf(buf,"%d",numRelays);
3434 else if (var == "uptime")
3437 timeStr.setFromStopwatch(upTime);
3438 strcpy(buf,timeStr.cstr());
3439 }else if (var == "update")
3443 timeStr.setFromStopwatch(sys->getTime()-time);
3446 strcpy(buf,timeStr.cstr());
3447 }else if (var == "isFirewalled"){
3448 sprintf(buf,"%d",firewalled?1:0);
3449 }else if (var == "version"){
3450 sprintf(buf,"%d",version);
3451 }else if (var == "agent"){
3453 if (version_ex_number){
3454 sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
3455 } else if (version_vp){
3456 sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
3458 sprintf(buf,"v0.%d", version);
3464 else if (var == "check")
3467 strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
3468 rhost[0].IPtoStr(buf2);
3470 strcat(buf, "')\">_</a>");
3472 else if (var == "uphost") // tree
3474 else if (var == "uphostHops") // tree
3475 sprintf(buf,"%d",uphostHops);
3476 else if (var == "canRelay") // tree
3477 sprintf(buf, "%d",relay);
3481 out.writeString(buf);
3485 // -----------------------------------
3486 int ChanHitList::getTotalListeners()
3493 cnt+=h->numListeners;
3498 // -----------------------------------
3499 int ChanHitList::getTotalRelays()
3511 // -----------------------------------
3512 int ChanHitList::getTotalFirewalled()
3526 // -----------------------------------
3527 int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
3532 void ChanHitList::clearHits(bool flg)
3534 ChanHit *c = hit, *prev = NULL;
3537 if (flg || (c->numHops != 0)){
3538 ChanHit *next = c->next;
3553 // -----------------------------------
3554 ChanHit *ChanHitList::deleteHit(ChanHit *ch)
3556 ChanHit *c = hit,*prev=NULL;
3561 ChanHit *next = c->next;
3577 // -----------------------------------
3578 ChanHit *ChanHitList::addHit(ChanHit &h)
3580 char ip0str[64],ip1str[64];
3581 h.rhost[0].toStr(ip0str);
3582 h.rhost[1].toStr(ip1str);
3584 h.uphost.toStr(uphostStr);
3586 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
3588 LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
3591 // dont add our own hits
3592 if (servMgr->sessionID.isSame(h.sessionID))
3596 lastHitTime = sys->getTime();
3597 h.time = lastHitTime;
3602 if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
3603 if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
3607 if (ch->numHops > 0 && h.numHops == 0)
3608 // downstream hit recieved as RelayHost
3610 ChanHit *next = ch->next;
3619 // clear hits with same session ID (IP may have changed)
3620 if (h.sessionID.isSet())
3626 if (ch->sessionID.isSame(h.sessionID))
3638 ChanHit *ch = new ChanHit();
3640 ch->chanID = info.id;
3650 // -----------------------------------
3651 int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
3654 unsigned int ctime = sys->getTime();
3656 // LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
3657 chanMgr->hitlistlock.on();
3663 if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
3665 // ch = deleteHit(ch);
3667 if (ch->firewalled){
3668 // LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
3669 if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
3673 ch->numListeners = 0;
3686 // LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
3687 chanMgr->hitlistlock.off();
3692 // -----------------------------------
3693 void ChanHitList::deadHit(ChanHit &h)
3695 char ip0str[64],ip1str[64];
3696 h.rhost[0].toStr(ip0str);
3697 h.rhost[1].toStr(ip1str);
3698 LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
3704 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3711 // -----------------------------------
3712 void ChanHitList::delHit(ChanHit &h)
3714 char ip0str[64],ip1str[64];
3715 h.rhost[0].toStr(ip0str);
3716 h.rhost[1].toStr(ip1str);
3717 LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
3723 if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
3731 // -----------------------------------
3732 int ChanHitList::numHits()
3738 if (ch->host.ip && !ch->dead && ch->numHops)
3745 // -----------------------------------
3746 int ChanHitList::numListeners()
3752 if (ch->host.ip && !ch->dead && ch->numHops)
3753 cnt += (unsigned int)ch->numListeners > 3 ? 3 : ch->numListeners;
3760 // -----------------------------------
3761 int ChanHitList::numClaps() //JP-MOD
3767 if (ch->host.ip && !ch->dead && ch->numHops && (ch->clap_pp & 1)){
3775 // -----------------------------------
3776 int ChanHitList::numRelays()
3782 if (ch->host.ip && !ch->dead)
3783 cnt += ch->numRelays;
3790 // -----------------------------------
3791 int ChanHitList::numTrackers()
3797 if ((ch->host.ip && !ch->dead) && (ch->tracker))
3803 // -----------------------------------
3804 int ChanHitList::numFirewalled()
3810 if (ch->host.ip && !ch->dead)
3811 cnt += ch->firewalled?1:0;
3816 // -----------------------------------
3817 int ChanHitList::closestHit()
3819 unsigned int hop=10000;
3823 if (ch->host.ip && !ch->dead)
3824 if (ch->numHops < hop)
3831 // -----------------------------------
3832 int ChanHitList::furthestHit()
3838 if (ch->host.ip && !ch->dead)
3839 if (ch->numHops > hop)
3846 // -----------------------------------
3847 unsigned int ChanHitList::newestHit()
3849 unsigned int time=0;
3853 if (ch->host.ip && !ch->dead)
3854 if (ch->time > time)
3861 // -----------------------------------
3862 int ChanHitList::pickHits(ChanHitSearch &chs)
3864 ChanHit best,*bestP=NULL;
3869 unsigned int ctime = sys->getTime();
3874 if (c->host.ip && !c->dead)
3876 if (!chs.excludeID.isSame(c->sessionID))
3877 if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
3878 if ((c->numHops<=best.numHops)) // (c->time>=best.time))
3879 if (c->relay || (!c->relay && chs.useBusyRelays))
3880 if (c->cin || (!c->cin && chs.useBusyControls))
3883 if (chs.trackersOnly && c->tracker)
3885 if (chs.matchHost.ip)
3887 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3891 best.host = best.rhost[1]; // use lan ip
3893 }else if (c->firewalled == chs.useFirewalled)
3897 best.host = best.rhost[0]; // use wan ip
3899 }else if (!chs.trackersOnly && !c->tracker)
3901 if (chs.matchHost.ip)
3903 if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
3907 best.host = best.rhost[1]; // use lan ip
3909 }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
3913 best.host = best.rhost[0]; // use wan ip
3923 if (chs.numResults < ChanHitSearch::MAX_RESULTS)
3926 bestP->lastContact = ctime;
3927 chs.best[chs.numResults++] = best;
3937 // -----------------------------------
3938 int ChanHitList::pickSourceHits(ChanHitSearch &chs)
3940 if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
3944 // -----------------------------------
3945 unsigned int ChanHitList::getSeq()
3949 seq = riSequence = (riSequence + 1) & 0xffffff;
3954 // -----------------------------------
3955 const char *ChanInfo::getTypeStr()
3957 if (contentTypeStr.isEmpty()) {
3958 return getTypeStr(contentType);
3961 return contentTypeStr.cstr();
3964 // -----------------------------------
3965 const char *ChanInfo::getTypeExt()
3967 if (streamExt.isEmpty()) {
3968 return getTypeExt(contentType);
3971 return streamExt.cstr();
3974 // -----------------------------------
3975 const char *ChanInfo::getMIMEType()
3977 if (streamType.isEmpty()) {
3978 return getMIMEType(contentType);
3981 return streamType.cstr();
3984 // -----------------------------------
3985 const char *ChanInfo::getTypeStr(TYPE t)
3989 case T_RAW: return "RAW";
3991 case T_MP3: return "MP3";
3992 case T_OGG: return "OGG";
3993 case T_OGM: return "OGM";
3994 case T_WMA: return "WMA";
3996 case T_MOV: return "MOV";
3997 case T_MPG: return "MPG";
3998 case T_NSV: return "NSV";
3999 case T_WMV: return "WMV";
4001 case T_PLS: return "PLS";
4002 case T_ASX: return "ASX";
4004 default: return "UNKNOWN";
4007 // -----------------------------------
4008 const char *ChanInfo::getProtocolStr(PROTOCOL t)
4012 case SP_PEERCAST: return "PEERCAST";
4013 case SP_HTTP: return "HTTP";
4014 case SP_FILE: return "FILE";
4015 case SP_MMS: return "MMS";
4016 case SP_PCP: return "PCP";
4017 default: return "UNKNOWN";
4020 // -----------------------------------
4021 ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
4023 if (stricmp(str,"PEERCAST")==0)
4025 else if (stricmp(str,"HTTP")==0)
4027 else if (stricmp(str,"FILE")==0)
4029 else if (stricmp(str,"MMS")==0)
4031 else if (stricmp(str,"PCP")==0)
4037 // -----------------------------------
4038 const char *ChanInfo::getTypeExt(TYPE t)
4042 case ChanInfo::T_OGM:
4043 case ChanInfo::T_OGG:
4045 case ChanInfo::T_MP3:
4047 case ChanInfo::T_MOV:
4049 case ChanInfo::T_NSV:
4051 case ChanInfo::T_WMV:
4053 case ChanInfo::T_WMA:
4059 // -----------------------------------
4060 const char *ChanInfo::getMIMEType(TYPE t)
4064 case ChanInfo::T_OGG:
4066 case ChanInfo::T_OGM:
4068 case ChanInfo::T_MP3:
4070 case ChanInfo::T_MOV:
4072 case ChanInfo::T_MPG:
4074 case ChanInfo::T_NSV:
4076 case ChanInfo::T_ASX:
4078 case ChanInfo::T_WMA:
4080 case ChanInfo::T_WMV:
4083 return "application/octet-stream";
4086 // -----------------------------------
4087 ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
4089 if (stricmp(str,"MP3")==0)
4091 else if (stricmp(str,"OGG")==0)
4093 else if (stricmp(str,"OGM")==0)
4095 else if (stricmp(str,"RAW")==0)
4097 else if (stricmp(str,"NSV")==0)
4099 else if (stricmp(str,"WMA")==0)
4101 else if (stricmp(str,"WMV")==0)
4103 else if (stricmp(str,"PLS")==0)
4105 else if (stricmp(str,"M3U")==0)
4107 else if (stricmp(str,"ASX")==0)
4112 // -----------------------------------
4113 bool ChanInfo::matchNameID(ChanInfo &inf)
4116 if (id.isSame(inf.id))
4119 if (!inf.name.isEmpty())
4120 if (name.contains(inf.name))
4125 // -----------------------------------
4126 bool ChanInfo::match(ChanInfo &inf)
4130 if (inf.status != S_UNKNOWN)
4132 if (status != inf.status)
4136 if (inf.bitrate != 0)
4138 if (bitrate == inf.bitrate)
4145 if (id.isSame(inf.id))
4150 if (inf.contentType != T_UNKNOWN)
4152 if (contentType == inf.contentType)
4157 if (!inf.name.isEmpty())
4159 if (name.contains(inf.name))
4164 if (!inf.genre.isEmpty())
4166 if (genre.contains(inf.genre))
4173 // -----------------------------------
4174 bool TrackInfo::update(TrackInfo &inf)
4176 bool changed = false;
4178 if (!contact.isSame(inf.contact))
4180 contact = inf.contact;
4184 if (!title.isSame(inf.title))
4190 if (!artist.isSame(inf.artist))
4192 artist = inf.artist;
4196 if (!album.isSame(inf.album))
4202 if (!genre.isSame(inf.genre))
4213 // -----------------------------------
4214 bool ChanInfo::update(ChanInfo &info)
4216 bool changed = false;
4221 if (!info.id.isSet())
4224 // only update from chaninfo that has full name etc..
4225 if (info.name.isEmpty())
4228 // check valid broadcaster key
4231 if (!bcID.isSame(info.bcID))
4233 LOG_ERROR("ChanInfo BC key not valid");
4243 if (bitrate != info.bitrate)
4245 bitrate = info.bitrate;
4249 if (contentType != info.contentType)
4251 contentType = info.contentType;
4255 if (!contentTypeStr.isSame(info.contentTypeStr))
4257 contentTypeStr = info.contentTypeStr;
4261 if (!streamType.isSame(info.streamType))
4263 streamType = info.streamType;
4267 if (!streamExt.isSame(info.streamExt))
4269 streamExt = info.streamExt;
4273 if(ppFlags != info.ppFlags) //JP-MOD
4275 ppFlags = info.ppFlags;
4279 if (!desc.isSame(info.desc)) //JP-EX
4285 if (!name.isSame(info.name))
4291 if (!comment.isSame(info.comment))
4293 comment = info.comment;
4297 if (!genre.isSame(info.genre))
4303 if (!url.isSame(info.url))
4309 if (track.update(info.track))
4315 // -----------------------------------
4316 void ChanInfo::initNameID(const char *n)
4324 // -----------------------------------
4325 void ChanInfo::init()
4330 contentType = T_UNKNOWN;
4331 contentTypeStr.clear();
4334 srcProtocol = SP_UNKNOWN;
4345 ppFlags = 0; //JP-MOD
4347 // -----------------------------------
4348 void ChanInfo::readTrackXML(XML::Node *n)
4351 readXMLString(track.title,n,"title");
4352 readXMLString(track.contact,n,"contact");
4353 readXMLString(track.artist,n,"artist");
4354 readXMLString(track.album,n,"album");
4355 readXMLString(track.genre,n,"genre");
4357 // -----------------------------------
4358 unsigned int ChanInfo::getUptime()
4360 // calculate uptime and cap if requested by settings.
4362 upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
4363 if (chanMgr->maxUptime)
4364 if (upt > chanMgr->maxUptime)
4365 upt = chanMgr->maxUptime;
4368 // -----------------------------------
4369 unsigned int ChanInfo::getAge()
4371 return sys->getTime()-createdTime;
4374 // ------------------------------------------
4375 void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
4377 for(int i=0; i<numc; i++)
4380 ID4 id = atom.read(c,d);
4381 if (id == PCP_CHAN_TRACK_TITLE)
4383 atom.readString(track.title.data,sizeof(track.title.data),d);
4384 }else if (id == PCP_CHAN_TRACK_CREATOR)
4386 atom.readString(track.artist.data,sizeof(track.artist.data),d);
4387 }else if (id == PCP_CHAN_TRACK_URL)
4389 atom.readString(track.contact.data,sizeof(track.contact.data),d);
4390 }else if (id == PCP_CHAN_TRACK_ALBUM)
4392 atom.readString(track.album.data,sizeof(track.album.data),d);
4397 // ------------------------------------------
4398 void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
4400 for(int i=0; i<numc; i++)
4403 ID4 id = atom.read(c,d);
4404 if (id == PCP_CHAN_INFO_NAME)
4406 atom.readString(name.data,sizeof(name.data),d);
4407 }else if (id == PCP_CHAN_INFO_BITRATE)
4409 bitrate = atom.readInt();
4410 }else if (id == PCP_CHAN_INFO_GENRE)
4412 atom.readString(genre.data,sizeof(genre.data),d);
4413 }else if (id == PCP_CHAN_INFO_URL)
4415 atom.readString(url.data,sizeof(url.data),d);
4416 }else if (id == PCP_CHAN_INFO_DESC)
4418 atom.readString(desc.data,sizeof(desc.data),d);
4419 }else if (id == PCP_CHAN_INFO_COMMENT)
4421 atom.readString(comment.data,sizeof(comment.data),d);
4422 }else if (id == PCP_CHAN_INFO_TYPE)
4425 atom.readString(type,sizeof(type),d);
4426 contentType = ChanInfo::getTypeFromStr(type);
4427 contentTypeStr = type;
4428 }else if (id == PCP_CHAN_INFO_STREAMTYPE)
4430 atom.readString(streamType.data,sizeof(streamType.data),d);
4431 }else if (id == PCP_CHAN_INFO_STREAMEXT)
4433 atom.readString(streamExt.data,sizeof(streamExt.data),d);
4434 }else if (id == PCP_CHAN_INFO_PPFLAGS) //JP-MOD
4436 ppFlags = (unsigned int)atom.readInt();
4442 // -----------------------------------
4443 void ChanInfo::writeInfoAtoms(AtomStream &atom)
4445 atom.writeParent(PCP_CHAN_INFO,7 + (ppFlags ? 1:0/*JP-MOD*/));
4446 atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
4447 atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
4448 atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
4449 atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
4450 atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
4451 atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
4452 atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr());
4453 if (!streamType.isEmpty())
4454 atom.writeString(PCP_CHAN_INFO_STREAMTYPE,streamType.cstr());
4455 if (!streamExt.isEmpty())
4456 atom.writeString(PCP_CHAN_INFO_STREAMEXT,streamExt.cstr());
4458 atom.writeInt(PCP_CHAN_INFO_PPFLAGS,ppFlags); //JP-MOD
4461 // -----------------------------------
4462 void ChanInfo::writeTrackAtoms(AtomStream &atom)
4464 atom.writeParent(PCP_CHAN_TRACK,4);
4465 atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
4466 atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
4467 atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
4468 atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
4472 // -----------------------------------
4473 XML::Node *ChanInfo::createChannelXML()
4477 String nameUNI = name;
4478 nameUNI.convertTo(String::T_UNICODESAFE);
4480 String urlUNI = url;
4481 urlUNI.convertTo(String::T_UNICODESAFE);
4483 String genreUNI = genre;
4484 genreUNI.convertTo(String::T_UNICODESAFE);
4486 String descUNI = desc;
4487 descUNI.convertTo(String::T_UNICODESAFE);
4490 commentUNI = comment;
4491 commentUNI.convertTo(String::T_UNICODESAFE);
4497 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\"",
4513 // -----------------------------------
4514 XML::Node *ChanInfo::createQueryXML()
4520 String nameHTML = name;
4521 nameHTML.convertTo(String::T_HTML);
4522 String genreHTML = genre;
4523 genreHTML.convertTo(String::T_HTML);
4526 if (!nameHTML.isEmpty())
4528 strcat(buf," name=\"");
4529 strcat(buf,nameHTML.cstr());
4533 if (!genreHTML.isEmpty())
4535 strcat(buf," genre=\"");
4536 strcat(buf,genreHTML.cstr());
4543 strcat(buf," id=\"");
4549 return new XML::Node("channel %s",buf);
4552 // -----------------------------------
4553 XML::Node *ChanInfo::createRelayChannelXML()
4560 return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
4566 }// -----------------------------------
4567 XML::Node *ChanInfo::createTrackXML()
4569 String titleUNI = track.title;
4570 titleUNI.convertTo(String::T_UNICODESAFE);
4572 String artistUNI = track.artist;
4573 artistUNI.convertTo(String::T_UNICODESAFE);
4575 String albumUNI = track.album;
4576 albumUNI.convertTo(String::T_UNICODESAFE);
4578 String genreUNI = track.genre;
4579 genreUNI.convertTo(String::T_UNICODESAFE);
4581 String contactUNI = track.contact;
4582 contactUNI.convertTo(String::T_UNICODESAFE);
4586 return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
4595 // -----------------------------------
4596 void ChanInfo::init(XML::Node *n)
4602 // -----------------------------------
4603 void ChanInfo::updateFromXML(XML::Node *n)
4605 String typeStr,idStr;
4607 readXMLString(name,n,"name");
4608 readXMLString(genre,n,"genre");
4609 readXMLString(url,n,"url");
4610 readXMLString(desc,n,"desc");
4613 int br = n->findAttrInt("bitrate");
4618 ppFlags = ServMgr::bcstNone;
4620 if (n->findAttrInt("bcstClap"))
4621 ppFlags |= ServMgr::bcstClap;
4624 readXMLString(typeStr,n,"type");
4625 if (!typeStr.isEmpty()) {
4626 contentType = getTypeFromStr(typeStr.cstr());
4627 contentTypeStr = typeStr;
4630 readXMLString(idStr,n,"id");
4631 if (!idStr.isEmpty())
4632 id.fromStr(idStr.cstr());
4634 readXMLString(comment,n,"comment");
4636 XML::Node *tn = n->findNode("track");
4642 // -----------------------------------
4643 void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
4653 // -----------------------------------
4654 void ChanInfo::init(const char *fn)
4661 // -----------------------------------
4662 void PlayList::readASX(Stream &in)
4664 LOG_DEBUG("Reading ASX");
4670 }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
4674 XML::Node *n = xml.root->child;
4677 if (stricmp("entry",n->getName())==0)
4679 XML::Node *rf = n->findNode("ref");
4682 char *hr = rf->findAttr("href");
4686 //LOG("asx url %s",hr);
4695 // -----------------------------------
4696 void PlayList::readSCPLS(Stream &in)
4699 while (in.readLine(tmp,sizeof(tmp)))
4701 if (strnicmp(tmp,"file",4)==0)
4703 char *p = strstr(tmp,"=");
4709 // -----------------------------------
4710 void PlayList::readPLS(Stream &in)
4713 while (in.readLine(tmp,sizeof(tmp)))
4719 // -----------------------------------
4720 void PlayList::writeSCPLS(Stream &out)
4722 out.writeLine("[playlist]");
4724 out.writeLineF("NumberOfEntries=%d",numURLs);
4726 for(int i=0; i<numURLs; i++)
4728 out.writeLineF("File%d=%s",i+1,urls[i].cstr());
4729 out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
4730 out.writeLineF("Length%d=-1",i+1);
4732 out.writeLine("Version=2");
4734 // -----------------------------------
4735 void PlayList::writePLS(Stream &out)
4737 for(int i=0; i<numURLs; i++)
4738 out.writeLineF("%s",urls[i].cstr());
4740 // -----------------------------------
4741 void PlayList::writeRAM(Stream &out)
4743 for(int i=0; i<numURLs; i++)
4744 out.writeLineF("%s",urls[i].cstr());
4747 // -----------------------------------
4748 #define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
4749 static void SJIStoSJISSAFE(char *string, size_t size)
4753 (string[pos] != '\0') && (pos < size);
4756 if(isHTMLSPECIAL(string[pos]))
4761 // -----------------------------------
4762 static void WriteASXInfo(Stream &out, String &title, String &contacturl, String::TYPE tEncoding = String::T_UNICODESAFE) //JP-MOD
4764 if(!title.isEmpty())
4767 titleEncode = title;
4768 titleEncode.convertTo(tEncoding);
4769 if(tEncoding == String::T_SJIS)
4770 SJIStoSJISSAFE(titleEncode.cstr(), String::MAX_LEN);
4771 out.writeLineF("<TITLE>%s</TITLE>", titleEncode.cstr());
4774 if(!contacturl.isEmpty())
4776 String contacturlEncode;
4777 contacturlEncode = contacturl;
4778 contacturlEncode.convertTo(tEncoding);
4779 if(tEncoding == String::T_SJIS)
4780 SJIStoSJISSAFE(contacturlEncode.cstr(), String::MAX_LEN);
4781 out.writeLineF("<MOREINFO HREF = \"%s\" />", contacturlEncode.cstr());
4785 // -----------------------------------
4786 void PlayList::writeASX(Stream &out)
4788 out.writeLine("<ASX Version=\"3.0\">");
4790 String::TYPE tEncoding = String::T_SJIS;
4791 if(servMgr->asxDetailedMode == 2)
4793 out.writeLine("<PARAM NAME = \"Encoding\" VALUE = \"utf-8\" />"); //JP-MOD Memo: UTF-8 cannot be used in some recording software.
4794 tEncoding = String::T_UNICODESAFE;
4797 if(servMgr->asxDetailedMode)
4798 WriteASXInfo(out, titles[0], contacturls[0], tEncoding); //JP-MOD
4800 for(int i=0; i<numURLs; i++)
4802 out.writeLine("<ENTRY>");
4803 if(servMgr->asxDetailedMode)
4804 WriteASXInfo(out, titles[i], contacturls[i], tEncoding); //JP-MOD
4805 out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
4806 out.writeLine("</ENTRY>");
4808 out.writeLine("</ASX>");
4812 // -----------------------------------
4813 void PlayList::addChannel(const char *path, ChanInfo &info)
4819 info.id.toStr(idStr);
4820 char *nid = info.id.isSet()?idStr:info.name.cstr();
4822 sprintf(url.cstr(),"%s/stream/%s%s",path,nid,info.getTypeExt());
4823 addURL(url.cstr(),info.name,info.url);
4826 // -----------------------------------
4827 void ChanHitSearch::init()
4831 useFirewalled = false;
4832 trackersOnly = false;
4833 useBusyRelays = true;
4834 useBusyControls = true;
4838 //seed = sys->getTime();
4842 int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
4850 ChanHit tmpHit[MAX_RESULTS];
4855 unsigned int seq = chl->getSeq();
4857 ChanHit *hit = chl->hit;
4860 if (hit->rhost[0].ip && !hit->dead) {
4862 (!exID.isSame(hit->sessionID))
4865 && (!hit->firewalled)
4866 && (hit->numHops != 0)
4868 if ( (hit->rhost[0].ip == host1.ip)
4869 && hit->rhost[1].isValid()
4870 && (host2.ip != hit->rhost[1].ip)
4873 best[0].host = hit->rhost[1];
4876 if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
4878 best[0].host = hit->rhost[1];
4882 loop = (index / MAX_RESULTS) + 1;
4883 //prob = (float)1 / (float)loop;
4885 //rnd = (float)rand() / (float)RAND_MAX;
4886 rnd = rand() % base;
4887 if (hit->numHops == 1){
4888 if (tmpHit[index % MAX_RESULTS].numHops == 1){
4890 tmpHit[index % MAX_RESULTS] = *hit;
4891 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4895 tmpHit[index % MAX_RESULTS] = *hit;
4896 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4900 if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
4901 tmpHit[index % MAX_RESULTS] = *hit;
4902 tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
4908 // hit->host.toStr(tmp);
4909 // LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
4915 if (index > MAX_RESULTS){
4921 /* int use[MAX_RESULTS];
4922 memset(use, 0, sizeof(use));
4924 for (i = 0; i < cnt; i++){
4928 for (i = 0; i < cnt; i++){
4931 // LOG_DEBUG("%d",r);
4939 for (i = 0; i < cnt; i++){
4940 // LOG_DEBUG("%d", use[i]);
4941 best[use[i]] = tmpHit[i];
4944 for (int i = 0; i < cnt; i++){
4945 // LOG_DEBUG("%d", use[i]);
4946 best[(i + seq) % cnt] = tmpHit[i];
4948 // for (i = 0; i < cnt; i++){
4950 // best[i].host.toStr(tmp);
4951 // LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);