1 // ------------------------------------------------
6 // (c) 2002-4 peercast.org
7 // ------------------------------------------------
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 // ------------------------------------------------
24 #include "chkMemoryLeak.h"
25 #define DEBUG_NEW new(__FILE__, __LINE__)
29 // ------------------------------------------
30 void PCPStream::init(GnuID &rid)
36 nextRootPacket = 0; // 0 seconds (never)
39 inData.accept = ChanPacket::T_PCP;
42 outData.accept = ChanPacket::T_PCP;
44 // ------------------------------------------
45 void PCPStream::readVersion(Stream &in)
47 int len = in.readInt();
50 throw StreamException("Invalid PCP");
52 int ver = in.readInt();
54 LOG_DEBUG("PCP ver: %d",ver);
56 // ------------------------------------------
57 void PCPStream::readHeader(Stream &in,Channel *)
59 // AtomStream atom(in);
61 // if (in.readInt() != PCP_CONNECT)
62 // throw StreamException("Not PCP");
66 // ------------------------------------------
67 bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID)
70 if (!destID.isSame(remoteID))
71 if (!routeList.contains(destID))
74 return outData.writePacket(pack);
76 // ------------------------------------------
77 void PCPStream::flush(Stream &in)
80 // send outward packets
81 while (outData.numPending())
83 outData.readPacket(pack);
87 // ------------------------------------------
88 int PCPStream::readPacket(Stream &in,Channel *)
91 return readPacket(in,bcs);
93 // ------------------------------------------
94 int PCPStream::readPacket(Stream &in,BroadcastState &bcs)
96 int error = PCP_ERROR_GENERAL;
102 MemoryStream mem(pack.data,sizeof(pack.data));
103 AtomStream patom(mem);
106 // send outward packets
107 error = PCP_ERROR_WRITE;
108 if (outData.numPending())
110 outData.readPacket(pack);
113 error = PCP_ERROR_GENERAL;
115 if (outData.willSkip())
117 error = PCP_ERROR_WRITE+PCP_ERROR_SKIP;
118 throw StreamException("Send too slow");
122 error = PCP_ERROR_READ;
123 // poll for new downward packet
129 id = atom.read(numc,numd);
132 pack.len = patom.writeAtoms(id, in, numc, numd);
133 pack.type = ChanPacket::T_PCP;
135 //inData.writePacket(pack);
137 error = PCP_ERROR_GENERAL;
139 // process downward packets
140 //if (inData.numPending())
142 //inData.readPacket(pack);
147 id = patom.read(numc,numd);
149 error = PCPStream::procAtom(patom,id,numc,numd,bcs);
152 throw StreamException("PCP exception");
157 }catch(StreamException &e)
159 LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error);
165 // ------------------------------------------
166 void PCPStream::readEnd(Stream &,Channel *)
171 // ------------------------------------------
172 void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
179 for(int i=0; i<numc; i++)
182 ID4 id = atom.read(c,d);
184 if (id == PCP_PUSH_IP)
185 host.ip = atom.readInt();
186 else if (id == PCP_PUSH_PORT)
187 host.port = atom.readShort();
188 else if (id == PCP_PUSH_CHANID)
189 atom.readBytes(chanID.id,16);
192 LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
207 Channel *ch = chanMgr->findChannelByID(chanID);
209 if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID))
210 s = servMgr->allocServent();
212 s = servMgr->allocServent();
217 LOG_DEBUG("GIVing to %s",ipstr);
218 s->initGIV(host,chanID);
223 // ------------------------------------------
224 void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
228 for(int i=0; i<numc; i++)
231 ID4 id = atom.read(c,d);
233 if (id == PCP_ROOT_UPDINT)
235 int si = atom.readInt();
237 chanMgr->setUpdateInterval(si);
238 LOG_DEBUG("PCP got new host update interval: %ds",si);
239 }else if (id == PCP_ROOT_URL)
241 url = "http://www.peercast.org/";
243 atom.readString(loc.data,sizeof(loc.data),d);
246 }else if (id == PCP_ROOT_CHECKVER)
248 unsigned int newVer = atom.readInt();
249 if (newVer > PCP_CLIENT_VERSION)
251 strcpy(servMgr->downloadURL,url.cstr());
252 peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client.");
254 LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION);
256 }else if (id == PCP_ROOT_NEXT)
258 unsigned int time = atom.readInt();
262 unsigned int ctime = sys->getTime();
263 nextRootPacket = ctime+time;
264 LOG_DEBUG("PCP expecting next root packet in %ds",time);
270 }else if (id == PCP_ROOT_UPDATE)
274 chanMgr->broadcastTrackerUpdate(remoteID,true);
276 }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
280 atom.readString(newMsg.data,sizeof(newMsg.data),d);
281 if (!newMsg.isSame(servMgr->rootMsg.cstr()))
283 servMgr->rootMsg = newMsg;
284 LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr());
285 peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr());
289 LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
295 // ------------------------------------------
296 void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs)
302 for(int i=0; i<numc; i++)
305 ID4 id = atom.read(c,d);
307 if (id == PCP_CHAN_PKT_TYPE)
309 type = atom.readID4();
311 if (type == PCP_CHAN_PKT_HEAD)
312 pack.type = ChanPacket::T_HEAD;
313 else if (type == PCP_CHAN_PKT_DATA)
314 pack.type = ChanPacket::T_DATA;
316 pack.type = ChanPacket::T_UNKNOWN;
318 }else if (id == PCP_CHAN_PKT_POS)
320 pack.pos = atom.readInt();
323 }else if (id == PCP_CHAN_PKT_DATA)
326 atom.readBytes(pack.data,pack.len);
330 LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
338 int diff = pack.pos - ch->streamPos;
341 LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount);
342 if (ch->lastSkipTime + 120 < sys->getTime()){
345 ch->lastSkipTime = sys->getTime();
346 ch->skipCount++; //JP-EX
350 if (servMgr->autoBumpSkipCount) //JP-EX
352 if (ch->skipCount > servMgr->autoBumpSkipCount)
354 LOG_DEBUG("Auto bump");
359 if (pack.type == ChanPacket::T_HEAD)
361 LOG_DEBUG("New head packet at %d",pack.pos);
363 if (servMgr->keepDownstreams)
364 renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0);
369 // check for stream restart
372 LOG_CHANNEL("PCP resetting stream");
377 if (renewhead || ch->lastStopTime + 30 < sys->getTime()) {
378 // check for stream restart
381 LOG_CHANNEL("PCP resetting stream");
388 ch->rawData.writePacket(pack,true);
389 ch->streamPos = pack.pos+pack.len;
392 }else if (pack.type == ChanPacket::T_DATA)
394 ch->rawData.writePacket(pack,true);
395 ch->streamPos = pack.pos+pack.len;
400 // update this parent packet stream position
401 if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos)))
402 bcs.streamPos = pack.pos;
405 // -----------------------------------
406 void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg)
410 GnuID chanID = bcs.chanID; //use default
414 unsigned int ipNum=0;
416 for(int i=0; i<numc; i++)
419 ID4 id = atom.read(c,d);
421 if (id == PCP_HOST_IP)
423 unsigned int ip = atom.readInt();
424 hit.rhost[ipNum].ip = ip;
425 }else if (id == PCP_HOST_PORT)
427 int port = atom.readShort();
428 hit.rhost[ipNum++].port = port;
433 else if (id == PCP_HOST_NUML)
434 hit.numListeners = atom.readInt();
435 else if (id == PCP_HOST_NUMR)
436 hit.numRelays = atom.readInt();
437 else if (id == PCP_HOST_UPTIME)
438 hit.upTime = atom.readInt();
439 else if (id == PCP_HOST_OLDPOS)
440 hit.oldestPos = atom.readInt();
441 else if (id == PCP_HOST_NEWPOS)
442 hit.newestPos = atom.readInt();
443 else if (id == PCP_HOST_VERSION)
444 hit.version = atom.readInt();
445 else if (id == PCP_HOST_VERSION_VP)
446 hit.version_vp = atom.readInt();
447 else if (id == PCP_HOST_VERSION_EX_PREFIX)
448 atom.readBytes(hit.version_ex_prefix,2);
449 else if (id == PCP_HOST_VERSION_EX_NUMBER){
450 hit.version_ex_number = atom.readShort();
452 else if (id == PCP_HOST_FLAGS1)
454 int fl1 = atom.readChar();
456 hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0;
457 hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0;
458 hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0;
459 hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0;
460 hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0;
461 hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0;
464 }else if (id == PCP_HOST_ID)
465 atom.readBytes(hit.sessionID.id,16);
466 else if (id == PCP_HOST_CHANID)
467 atom.readBytes(chanID.id,16);
468 else if (id == PCP_HOST_UPHOST_IP)
469 hit.uphost.ip = atom.readInt();
470 else if (id == PCP_HOST_UPHOST_PORT)
471 hit.uphost.port = atom.readInt();
472 else if (id == PCP_HOST_UPHOST_HOPS)
473 hit.uphostHops = atom.readInt();
476 LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
481 hit.host = hit.rhost[0];
484 hit.numHops = bcs.numHops;
486 hit.servent_id = bcs.servent_id;
489 // LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------");
490 chanMgr->hitlistlock.on();
492 chanMgr->addHit(hit);
494 chanMgr->delHit(hit);
495 // LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------");
496 chanMgr->hitlistlock.off();
499 if (hit.numHops == 1){
500 Servent *sv = servMgr->findServentByServentID(hit.servent_id);
502 // LOG_DEBUG("set servent's waitPort = %d", hit.host.port);
503 sv->waitPort = hit.host.port;
508 // ------------------------------------------
509 void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
512 ChanHitList *chl=NULL;
515 ch = chanMgr->findChannelByID(bcs.chanID);
516 chl = chanMgr->findHitListByID(bcs.chanID);
521 newInfo = chl->info;*/
524 ChanHitList *chl=NULL;
525 ChanInfo newInfo, chaInfo;
533 for(int i=0; i<numc; i++)
537 ID4 id = atom.read(c,d);
539 if ((id == PCP_CHAN_PKT) && (ch))
541 readPktAtoms(ch,atom,c,bcs);
542 }else if (id == PCP_CHAN_INFO)
544 newInfo.readInfoAtoms(atom,c);
546 }else if (id == PCP_CHAN_TRACK)
548 newInfo.readTrackAtoms(atom,c);
550 }else if (id == PCP_CHAN_BCID)
552 atom.readBytes(newInfo.bcID.id,16);
554 }else if (id == PCP_CHAN_KEY) // depreciated
556 atom.readBytes(newInfo.bcID.id,16);
557 newInfo.bcID.id[0] = 0; // clear flags
559 }else if (id == PCP_CHAN_ID)
561 atom.readBytes(newInfo.id.id,16);
563 ch = chanMgr->findChannelByID(newInfo.id);
564 chl = chanMgr->findHitListByID(newInfo.id);
568 LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
573 chl = chanMgr->findHitList(newInfo);
576 chl = chanMgr->addHitList(newInfo);
580 chl->info.update(newInfo);
582 if (!servMgr->chanLog.isEmpty())
584 //if (chl->numListeners())
589 file.openWriteAppend(servMgr->chanLog.cstr());
591 XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime());
592 XML::Node *n = chl->info.createChannelXML();
593 n->add(chl->createXML(false));
594 n->add(chl->info.createTrackXML());
600 }catch(StreamException &e)
602 LOG_ERROR("Unable to update channel log: %s",e.msg);
609 if (ch && !ch->isBroadcasting())
610 ch->updateInfo(newInfo);
614 // ------------------------------------------
615 int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
623 char ver_ex_prefix[2];
624 int ver_ex_number = 0;
629 bcs.initPacketSettings();
631 MemoryStream pmem(pack.data,sizeof(pack.data));
632 AtomStream patom(pmem);
634 patom.writeParent(PCP_BCST,numc);
636 for(int i=0; i<numc; i++)
639 ID4 id = atom.read(c,d);
641 if (id == PCP_BCST_TTL)
643 ttl = atom.readChar()-1;
644 patom.writeChar(id,ttl);
646 }else if (id == PCP_BCST_HOPS)
648 bcs.numHops = atom.readChar()+1;
649 patom.writeChar(id,bcs.numHops);
651 }else if (id == PCP_BCST_FROM)
653 atom.readBytes(fromID.id,16);
654 patom.writeBytes(id,fromID.id,16);
656 routeList.add(fromID);
657 }else if (id == PCP_BCST_GROUP)
659 bcs.group = atom.readChar();
660 patom.writeChar(id,bcs.group);
661 }else if (id == PCP_BCST_DEST)
663 atom.readBytes(destID.id,16);
664 patom.writeBytes(id,destID.id,16);
665 bcs.forMe = destID.isSame(servMgr->sessionID);
670 destID.toStr(idstr1);
671 servMgr->sessionID.toStr(idstr2);
673 }else if (id == PCP_BCST_CHANID)
675 atom.readBytes(bcs.chanID.id,16);
676 patom.writeBytes(id,bcs.chanID.id,16);
677 }else if (id == PCP_BCST_VERSION)
679 ver = atom.readInt();
680 patom.writeInt(id,ver);
681 }else if (id == PCP_BCST_VERSION_VP)
683 ver_vp = atom.readInt();
684 patom.writeInt(id,ver_vp);
685 }else if (id == PCP_BCST_VERSION_EX_PREFIX)
687 atom.readBytes(ver_ex_prefix,2);
688 patom.writeBytes(id,ver_ex_prefix,2);
689 }else if (id == PCP_BCST_VERSION_EX_NUMBER)
691 ver_ex_number = atom.readShort();
692 patom.writeShort(id,ver_ex_number);
693 }else if (id == PCP_HOST)
696 readHostAtoms(atom,c,bcs,hit,false);
697 if (hit.uphost.ip == 0){
698 // LOG_DEBUG("bcs servent_id = %d", bcs.servent_id);
699 if (bcs.numHops == 1){
700 hit.uphost.ip = servMgr->serverHost.ip;
701 hit.uphost.port = servMgr->serverHost.port;
704 Servent *sv = servMgr->findServentByServentID(bcs.servent_id);
706 hit.uphost.ip = sv->getHost().ip;
707 hit.uphost.port = sv->waitPort;
708 hit.uphostHops = bcs.numHops - 1;
712 int oldPos = pmem.pos;
713 hit.writeAtoms(patom, hit.chanID);
715 r = readAtom(patom,bcs);
717 // copy and process atoms
718 int oldPos = pmem.pos;
719 patom.writeAtoms(id,atom.io,c,d);
721 r = readAtom(patom,bcs);
728 fromID.toStr(fromStr);
732 destID.toStr(destStr);
734 bcs.chanID.toStr(tmp);
739 LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d",
740 bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl);
742 LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(VP%04d), from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,ver_vp,fromStr,destStr,ttl);
744 LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl);
748 if (fromID.isSame(servMgr->sessionID))
750 LOG_ERROR("BCST loopback");
751 return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK;
754 // broadcast back out if ttl > 0
755 if ((ttl>0) && (!bcs.forMe))
758 pack.type = ChanPacket::T_PCP;
760 if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
762 chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID);
765 if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
767 servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT);
770 if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS))
772 servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN);
775 if (bcs.group & (PCP_BCST_GROUP_RELAYS))
777 servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY);
781 // LOG_DEBUG("ttl=%d",ttl);
784 // LOG_DEBUG("ttl=%d",ttl);
790 // ------------------------------------------
791 int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs)
799 readChanAtoms(atom,numc,bcs);
800 }else if (id == PCP_ROOT)
803 throw StreamException("Unauthorized root message");
805 readRootAtoms(atom,numc,bcs);
807 }else if (id == PCP_HOST)
809 readHostAtoms(atom,numc,bcs,hit);
810 Channel *ch = chanMgr->findChannelByID(hit.chanID);
811 if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){
812 if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){
814 hit.host.IPtoStr(tmp);
815 LOG_DEBUG("host that can't relay is disconnect: %s", tmp);
816 rBan = PCP_ERROR_BANNED;
818 if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){
820 hit.host.IPtoStr(tmp);
821 LOG_DEBUG("host that is not VP is disconnect: %s", tmp);
822 rBan = PCP_ERROR_BANNED;
826 }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
829 atom.readString(msg.data,sizeof(msg.data),dlen);
830 LOG_DEBUG("PCP got text: %s",msg.cstr());
831 }else if (id == PCP_BCST)
833 r = readBroadcastAtoms(atom,numc,bcs);
834 }else if (id == PCP_HELO)
836 atom.skip(numc,dlen);
837 atom.writeParent(PCP_OLEH,1);
838 atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
839 }else if (id == PCP_PUSH)
842 readPushAtoms(atom,numc,bcs);
843 }else if (id == PCP_OK)
847 }else if (id == PCP_QUIT)
853 }else if (id == PCP_ATOM)
855 for(int i=0; i<numc; i++)
858 ID4 aid = atom.read(nc,nd);
859 int ar = procAtom(atom,aid,nc,nd,bcs);
866 LOG_CHANNEL("PCP skip: %s",id.getString().str());
867 atom.skip(numc,dlen);
877 // ------------------------------------------
878 int PCPStream::readAtom(AtomStream &atom,BroadcastState &bcs)
881 ID4 id = atom.read(numc,dlen);
883 return procAtom(atom,id,numc,dlen,bcs);