--- /dev/null
+// ------------------------------------------------
+// File : asf.h
+// Date: 10-apr-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ASF_H
+#define _ASF_H
+
+
+#include "stream.h"
+
+// -----------------------------------
+class MSID
+{
+public:
+
+ void read(Stream &in)
+ {
+ data1 = in.readLong();
+ data2 = in.readShort();
+ data3 = in.readShort();
+ in.read(data4,8);
+ }
+
+ void write(Stream &out)
+ {
+ out.writeLong(data1);
+ out.writeShort(data2);
+ out.writeShort(data3);
+ out.write(data4,8);
+ }
+
+
+ void toString(String &s)
+ {
+ sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X",
+ data1,data2,data3,
+ data4[0],data4[1],data4[2],data4[3],
+ data4[4],data4[5],data4[6],data4[7]);
+ }
+
+ int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));}
+
+ unsigned int data1;
+ unsigned short data2,data3;
+ unsigned char data4[8];
+
+};
+
+
+
+
+// -----------------------------------
+const MSID headObjID=
+ {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID dataObjID=
+ {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID filePropObjID=
+ {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65};
+const MSID streamPropObjID=
+ {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65};
+
+const MSID audioStreamObjID=
+ {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+const MSID videoStreamObjID=
+ {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+
+const MSID streamBitrateObjID=
+ {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2};
+
+
+// -----------------------------------
+class ASFObject
+{
+public:
+
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_HEAD_OBJECT,
+ T_DATA_OBJECT,
+ T_FILE_PROP,
+ T_STREAM_PROP,
+ T_STREAM_BITRATE
+ };
+
+ int getTotalLen()
+ {
+ return 24+dataLen;
+ }
+
+ unsigned int readHead(Stream &in)
+ {
+ id.read(in);
+
+ lenLo = in.readLong();
+ lenHi = in.readLong();
+
+ type = T_UNKNOWN;
+ if (id == headObjID)
+ type = T_HEAD_OBJECT;
+ else if (id == dataObjID)
+ type = T_DATA_OBJECT;
+ else if (id == filePropObjID)
+ type = T_FILE_PROP;
+ else if (id == streamPropObjID)
+ type = T_STREAM_PROP;
+ else if (id == streamBitrateObjID)
+ type = T_STREAM_BITRATE;
+
+ String str;
+ id.toString(str);
+ LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi);
+
+
+ dataLen = 0;
+
+ return lenLo-24;
+ }
+
+ void readData(Stream &in,int len)
+ {
+ dataLen = len;
+
+ if ((dataLen > sizeof(data)) || (lenHi))
+ throw StreamException("ASF object too big");
+
+ in.read(data,dataLen);
+ }
+
+
+ void write(Stream &out)
+ {
+ id.write(out);
+ out.writeLong(lenLo);
+ out.writeLong(lenHi);
+ if (dataLen)
+ out.write(data,dataLen);
+ }
+
+ const char *getTypeName()
+ {
+ switch(type)
+ {
+ case T_HEAD_OBJECT:
+ return "ASF_Header_Object";
+ case T_DATA_OBJECT:
+ return "ASF_Data_Object";
+ case T_FILE_PROP:
+ return "ASF_File_Properties_Object";
+ case T_STREAM_PROP:
+ return "ASF_Stream_Properties_Object";
+ case T_STREAM_BITRATE:
+ return "ASF_Stream_Bitrate_Properties_Object";
+ default:
+ return "Unknown_Object";
+ }
+ }
+
+ char data[8192];
+ MSID id;
+ unsigned int lenLo,lenHi,dataLen;
+ TYPE type;
+};
+// -----------------------------------
+class ASFStream
+{
+public:
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_AUDIO,
+ T_VIDEO
+ };
+
+ void read(Stream &in)
+ {
+ MSID sid;
+ sid.read(in);
+
+ if (sid == videoStreamObjID)
+ type = T_VIDEO;
+ else if (sid == audioStreamObjID)
+ type = T_AUDIO;
+ else
+ type = T_UNKNOWN;
+
+ in.skip(32);
+ id = in.readShort()&0x7f;
+ }
+
+
+ const char *getTypeName()
+ {
+ switch(type)
+ {
+ case T_VIDEO:
+ return "Video";
+ case T_AUDIO:
+ return "Audio";
+ }
+ return "Unknown";
+ }
+
+ void reset()
+ {
+ id = 0;
+ bitrate = 0;
+ type = T_UNKNOWN;
+ }
+
+ unsigned int id;
+ int bitrate;
+ TYPE type;
+};
+
+// -----------------------------------
+class ASFInfo
+{
+public:
+ enum
+ {
+ MAX_STREAMS = 128
+ };
+
+ ASFInfo()
+ {
+ numPackets = 0;
+ packetSize = 0;
+ flags = 0;
+ bitrate=0;
+ for(int i=0; i<MAX_STREAMS; i++)
+ streams[i].reset();
+ }
+
+ unsigned int packetSize,numPackets,flags,bitrate;
+
+ ASFStream streams[MAX_STREAMS];
+};
+
+// -----------------------------------
+class ASFChunk
+{
+public:
+
+ void read(Stream &in)
+ {
+ type = in.readShort();
+ len = in.readShort();
+ seq = in.readLong();
+ v1 = in.readShort();
+ v2 = in.readShort();
+
+ dataLen = len-8;
+ if (dataLen > sizeof(data))
+ throw StreamException("ASF chunk too big");
+ in.read(data,dataLen);
+ }
+
+ void write(Stream &out)
+ {
+ out.writeShort(type);
+ out.writeShort(len);
+ out.writeLong(seq);
+ out.writeShort(v1);
+ out.writeShort(v2);
+ out.write(data,dataLen);
+ }
+
+ unsigned int seq,dataLen;
+ unsigned short type,len,v1,v2;
+ unsigned char data[8192];
+};
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : atom.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ATOM_H
+#define _ATOM_H
+
+#include "stream.h"
+
+#include "id.h"
+
+// ------------------------------------------------
+class AtomStream
+{
+public:
+ AtomStream(Stream &s) : io(s),numChildren(0),numData(0)
+ {}
+
+ void checkData(int d)
+ {
+ if (numData != d)
+ throw StreamException("Bad atom data");
+ }
+
+ void writeParent(ID4 id,int nc)
+ {
+ io.writeID4(id);
+ io.writeInt(nc|0x80000000);
+ }
+
+ void writeInt(ID4 id,int d)
+ {
+ io.writeID4(id);
+ io.writeInt(4);
+ io.writeInt(d);
+ }
+
+ void writeID4(ID4 id,ID4 d)
+ {
+ io.writeID4(id);
+ io.writeInt(4);
+ io.writeID4(d);
+ }
+
+ void writeShort(ID4 id,short d)
+ {
+ io.writeID4(id);
+ io.writeInt(2);
+ io.writeShort(d);
+ }
+
+ void writeChar(ID4 id,char d)
+ {
+ io.writeID4(id);
+ io.writeInt(1);
+ io.writeChar(d);
+ }
+
+ void writeBytes(ID4 id,const void *p,int l)
+ {
+ io.writeID4(id);
+ io.writeInt(l);
+ io.write(p,l);
+ }
+
+
+ int writeStream(ID4 id,Stream &in,int l)
+ {
+ io.writeID4(id);
+ io.writeInt(l);
+ in.writeTo(io,l);
+ return (sizeof(int)*2)+l;
+
+ }
+
+ void writeString(ID4 id,const char *p)
+ {
+ writeBytes(id,p,strlen(p)+1);
+ }
+
+ ID4 read(int &numc,int &dlen)
+ {
+ ID4 id = io.readID4();
+
+ unsigned int v = io.readInt();
+ if (v & 0x80000000)
+ {
+ numc = v&0x7fffffff;
+ dlen = 0;
+ }else
+ {
+ numc = 0;
+ dlen = v;
+ }
+
+ numChildren = numc;
+ numData = dlen;
+
+ return id;
+ }
+
+ void skip(int c, int d)
+ {
+ if (d)
+ io.skip(d);
+
+ for(int i=0; i<c; i++)
+ {
+ int numc,data;
+ read(numc,data);
+ skip(numc,data);
+ }
+
+ }
+
+ int readInt()
+ {
+ checkData(4);
+ return io.readInt();
+ }
+ int readID4()
+ {
+ checkData(4);
+ return io.readID4();
+ }
+
+ int readShort()
+ {
+ checkData(2);
+ return io.readShort();
+ }
+ int readChar()
+ {
+ checkData(1);
+ return io.readChar();
+ }
+ int readBytes(void *p,int l)
+ {
+ checkData(l);
+ return io.read(p,l);
+ }
+
+ void readString(char *s,int max,int dlen)
+ {
+ checkData(dlen);
+ readBytes(s,max,dlen);
+ s[max-1] = 0;
+
+ }
+
+ void readBytes(void *s,int max,int dlen)
+ {
+ checkData(dlen);
+ if (max > dlen)
+ readBytes(s,dlen);
+ else
+ {
+ readBytes(s,max);
+ io.skip(dlen-max);
+ }
+ }
+
+ int writeAtoms(ID4 id, Stream &in, int cnt, int data)
+ {
+ int total=0;
+
+ if (cnt)
+ {
+ writeParent(id,cnt);
+ total+=sizeof(int)*2;
+
+ for(int i=0; i<cnt; i++)
+ {
+ AtomStream ain(in);
+ int c,d;
+ ID4 cid = ain.read(c,d);
+ total += writeAtoms(cid,in,c,d);
+ }
+ }else
+ {
+ total += writeStream(id,in,data);
+ }
+
+ return total;
+ }
+
+ bool eof() {return io.eof();}
+
+
+ int numChildren,numData;
+ Stream &io;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : channel.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Channel streaming classes. These do the actual
+// streaming of media between clients.
+//
+// (c) 2002 peercast.org
+//
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "socket.h"
+#include "channel.h"
+#include "gnutella.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "sys.h"
+#include "xml.h"
+#include "http.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+
+#include "mp3.h"
+#include "ogg.h"
+#include "mms.h"
+#include "nsv.h"
+
+#include "icy.h"
+#include "url.h"
+
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+char *Channel::srcTypes[]=
+{
+ "NONE",
+ "PEERCAST",
+ "SHOUTCAST",
+ "ICECAST",
+ "URL"
+};
+// -----------------------------------
+char *Channel::statusMsgs[]=
+{
+ "NONE",
+ "WAIT",
+ "CONNECT",
+ "REQUEST",
+ "CLOSE",
+ "RECEIVE",
+ "BROADCAST",
+ "ABORT",
+ "SEARCH",
+ "NOHOSTS",
+ "IDLE",
+ "ERROR",
+ "NOTFOUND"
+};
+
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info)
+{
+ int len;
+
+ if( info &&
+ info->contentType == ChanInfo::T_RAW &&
+ info->bitrate <= 32 &&
+ (len = strlen(info->name.cstr())) >= 9 &&
+ !memcmp(info->name.cstr(), "index", 5) &&
+ !memcmp(info->name.cstr()+len-4, ".txt", 4))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool isIndexTxt(Channel *ch)
+{
+ if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
+ return true;
+ else
+ return false;
+}
+
+int numMaxRelaysIndexTxt(Channel *ch)
+{
+ return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
+}
+
+int canStreamIndexTxt(Channel *ch)
+{
+ int ret;
+
+ // \8e©\95ª\82ª\94z\90M\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\8aÖ\8cW\82È\82¢
+ if(!ch || ch->isBroadcasting())
+ return -1;
+
+ ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
+ if(ret < 0)
+ ret = 0;
+
+ return ret;
+}
+// for PCRaw end.
+
+// -----------------------------------
+void readXMLString(String &str, XML::Node *n, const char *arg)
+{
+ char *p;
+ p = n->findAttr(arg);
+ if (p)
+ {
+ str.set(p,String::T_HTML);
+ str.convertTo(String::T_ASCII);
+ }
+}
+
+int channel_count=1;
+// -----------------------------------------------------------------------------
+// Initialise the channel to its default settings of unallocated and reset.
+// -----------------------------------------------------------------------------
+Channel::Channel()
+{
+ next = NULL;
+ reset();
+ channel_id = channel_count++;
+}
+// -----------------------------------------------------------------------------
+void Channel::endThread(bool flg)
+{
+ if (pushSock)
+ {
+ pushSock->close();
+ delete pushSock;
+ pushSock = NULL;
+ }
+
+ if (sock)
+ {
+ sock->close();
+ sock = NULL;
+ }
+
+ if (sourceData)
+ {
+ delete sourceData;
+ sourceData = NULL;
+ }
+
+ if (flg == true){
+ reset();
+
+ chanMgr->channellock.on();
+ chanMgr->deleteChannel(this);
+ chanMgr->channellock.off();
+
+ sys->endThread(&thread);
+ }
+}
+// -----------------------------------------------------------------------------
+void Channel::resetPlayTime()
+{
+ info.lastPlayStart = sys->getTime();
+}
+// -----------------------------------------------------------------------------
+void Channel::setStatus(STATUS s)
+{
+ if (s != status)
+ {
+ bool wasPlaying = isPlaying();
+
+ status = s;
+
+ if (isPlaying())
+ {
+ info.status = ChanInfo::S_PLAY;
+ resetPlayTime();
+ }else
+ {
+ if (wasPlaying)
+ info.lastPlayEnd = sys->getTime();
+ info.status = ChanInfo::S_UNKNOWN;
+ }
+
+ if (isBroadcasting())
+ {
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (!chl)
+ chanMgr->addHitList(info);
+ }
+
+ peercastApp->channelUpdate(&info);
+
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Reset channel and make it available
+// -----------------------------------------------------------------------------
+void Channel::reset()
+{
+ sourceHost.init();
+ remoteID.clear();
+
+ streamIndex = 0;
+
+ lastIdleTime = 0;
+
+ info.init();
+
+ mount.clear();
+ bump = false;
+ stayConnected = false;
+
+ icyMetaInterval = 0;
+ streamPos = 0;
+ skipCount = 0; //JP-EX
+ lastSkipTime = 0;
+
+ insertMeta.init();
+
+ headPack.init();
+
+ sourceStream = NULL;
+
+ rawData.init();
+ rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
+
+ setStatus(S_NONE);
+ type = T_NONE;
+
+ readDelay = false;
+ sock = NULL;
+ pushSock = NULL;
+
+ sourceURL.clear();
+ sourceData = NULL;
+
+ lastTrackerUpdate = 0;
+ lastMetaUpdate = 0;
+
+ srcType = SRC_NONE;
+
+
+ startTime = 0;
+ syncTime = 0;
+
+ channel_id = 0;
+ finthread = NULL;
+
+ trackerHit.init();
+}
+
+// -----------------------------------
+void Channel::newPacket(ChanPacket &pack)
+{
+ if (pack.type != ChanPacket::T_PCP)
+ {
+ rawData.writePacket(pack,true);
+ }
+}
+
+
+// -----------------------------------
+bool Channel::checkIdle()
+{
+ return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
+}
+
+// -----------------------------------
+bool Channel::isFull()
+{
+ // for PCRaw (relay) start.
+ if(isIndexTxt(this))
+ {
+ int ret = canStreamIndexTxt(this);
+
+ if(ret > 0)
+ return false;
+ else if(ret == 0)
+ return true;
+ }
+ // for PCRaw (relay) end.
+
+ return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
+}
+// -----------------------------------
+int Channel::localRelays()
+{
+ return servMgr->numStreams(info.id,Servent::T_RELAY,true);
+}
+// -----------------------------------
+int Channel::localListeners()
+{
+ return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
+}
+
+// -----------------------------------
+int Channel::totalRelays()
+{
+ int tot = 0;
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (chl)
+ tot += chl->numHits();
+ return tot;
+}
+// -----------------------------------
+int Channel::totalListeners()
+{
+ int tot = localListeners();
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (chl)
+ tot += chl->numListeners();
+ return tot;
+}
+
+
+
+
+// -----------------------------------
+void Channel::startGet()
+{
+ srcType = SRC_PEERCAST;
+ type = T_RELAY;
+ info.srcProtocol = ChanInfo::SP_PCP;
+
+
+ sourceData = new PeercastSource();
+
+ startStream();
+}
+// -----------------------------------
+void Channel::startURL(const char *u)
+{
+ sourceURL.set(u);
+
+ srcType = SRC_URL;
+ type = T_BROADCAST;
+ stayConnected = true;
+
+ resetPlayTime();
+
+ sourceData = new URLSource(u);
+
+ startStream();
+
+}
+// -----------------------------------
+void Channel::startStream()
+{
+ thread.data = this;
+ thread.func = stream;
+ if (!sys->startThread(&thread))
+ reset();
+}
+
+// -----------------------------------
+void Channel::sleepUntil(double time)
+{
+ double sleepTime = time - (sys->getDTime()-startTime);
+
+// LOG("sleep %g",sleepTime);
+ if (sleepTime > 0)
+ {
+ if (sleepTime > 60) sleepTime = 60;
+
+ double sleepMS = sleepTime*1000;
+
+ sys->sleep((int)sleepMS);
+ }
+}
+
+
+// -----------------------------------
+void Channel::checkReadDelay(unsigned int len)
+{
+ if (readDelay)
+ {
+ unsigned int time = (len*1000)/((info.bitrate*1024)/8);
+ sys->sleep(time);
+ }
+
+
+}
+
+
+// -----------------------------------
+THREAD_PROC Channel::stream(ThreadInfo *thread)
+{
+// thread->lock();
+
+ Channel *ch = (Channel *)thread->data;
+
+ LOG_CHANNEL("Channel started");
+
+ while (thread->active && !peercastInst->isQuitting && !thread->finish)
+ {
+ ChanHitList *chl = chanMgr->findHitList(ch->info);
+ if (!chl)
+ chanMgr->addHitList(ch->info);
+
+ ch->sourceData->stream(ch);
+
+ LOG_CHANNEL("Channel stopped");
+ ch->rawData.init();
+
+ if (!ch->stayConnected)
+ {
+ thread->active = false;
+ break;
+ }else
+ {
+ if (!ch->info.lastPlayEnd)
+ ch->info.lastPlayEnd = sys->getTime();
+
+ unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
+
+ LOG_DEBUG("Channel sleeping for %d seconds",diff);
+ for(unsigned int i=0; i<diff; i++)
+ {
+ if (!thread->active || peercastInst->isQuitting){
+ thread->active = false;
+ break;
+ }
+ sys->sleep(1000);
+ }
+ }
+ }
+
+ LOG_DEBUG("thread.active = %d, thread.finish = %d",
+ ch->thread.active, ch->thread.finish);
+
+ if (!thread->finish){
+ ch->endThread(false);
+
+ if (!ch->finthread){
+ ch->finthread = new ThreadInfo();
+ ch->finthread->func = waitFinish;
+ ch->finthread->data = ch;
+ sys->startThread(ch->finthread);
+ }
+ } else {
+ ch->endThread(true);
+ }
+ return 0;
+}
+
+// -----------------------------------
+THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
+{
+ Channel *ch = (Channel*)thread->data;
+ LOG_DEBUG("Wait channel finish");
+
+ while(!(ch->thread.finish) && !thread->finish){
+ sys->sleep(1000);
+ }
+
+ if (ch->thread.finish){
+ LOG_DEBUG("channel finish");
+ ch->endThread(true);
+ } else {
+ LOG_DEBUG("channel restart");
+ }
+
+ delete thread;
+ return 0;
+}
+
+// -----------------------------------
+bool Channel::acceptGIV(ClientSocket *givSock)
+{
+ if (!pushSock)
+ {
+ pushSock = givSock;
+ return true;
+ }else
+ return false;
+}
+// -----------------------------------
+void Channel::connectFetch()
+{
+ sock = sys->createSocket();
+
+ if (!sock)
+ throw StreamException("Can`t create socket");
+
+ if (sourceHost.tracker || sourceHost.yp)
+ {
+ sock->setReadTimeout(30000);
+ sock->setWriteTimeout(30000);
+ LOG_CHANNEL("Channel using longer timeouts");
+ } else {
+ sock->setReadTimeout(5000);
+ sock->setWriteTimeout(5000);
+ }
+
+ sock->open(sourceHost.host);
+
+ sock->connect();
+}
+
+// -----------------------------------
+int Channel::handshakeFetch()
+{
+ char idStr[64];
+ info.id.toStr(idStr);
+
+ char sidStr[64];
+ servMgr->sessionID.toStr(sidStr);
+
+ sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
+ sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+ sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+ sock->writeLine("");
+
+ HTTP http(*sock);
+
+ int r = http.readResponse();
+
+ LOG_CHANNEL("Got response: %d",r);
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(PCX_HS_POS))
+ streamPos = atoi(arg);
+ else
+ Servent::readICYHeader(http, info, NULL);
+
+ LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
+ }
+
+ if ((r != 200) && (r != 503))
+ return r;
+
+ if (!servMgr->keepDownstreams) {
+ if (rawData.getLatestPos() > streamPos)
+ rawData.init();
+ }
+
+ AtomStream atom(*sock);
+
+ String agent;
+
+ Host rhost = sock->host;
+
+ if (info.srcProtocol == ChanInfo::SP_PCP)
+ {
+ // don`t need PCP_CONNECT here
+ Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
+ }
+
+ if (r == 503) return 503;
+ return 0;
+
+}
+
+// -----------------------------------
+void PeercastSource::stream(Channel *ch)
+{
+ int numYPTries=0;
+ int numYPTries2=0;
+ bool next_yp = false;
+ bool tracker_check = (ch->trackerHit.host.ip != 0);
+ int connFailCnt = 0;
+
+ ch->lastStopTime = 0;
+ ch->bumped = false;
+
+ while (ch->thread.active)
+ {
+ ch->skipCount = 0; //JP-EX
+ ch->lastSkipTime = 0;
+
+ ChanHitList *chl = NULL;
+
+ ch->sourceHost.init();
+
+ if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
+ ch->lastIdleTime = sys->getTime();
+ ch->setStatus(Channel::S_IDLE);
+ ch->skipCount = 0;
+ ch->lastSkipTime = 0;
+ break;
+ }
+
+ if (!servMgr->keepDownstreams && !ch->bumped) {
+ ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
+ }
+
+ ch->setStatus(Channel::S_SEARCHING);
+ LOG_CHANNEL("Channel searching for hit..");
+ do
+ {
+
+ if (ch->pushSock)
+ {
+ ch->sock = ch->pushSock;
+ ch->pushSock = NULL;
+ ch->sourceHost.host = ch->sock->host;
+ break;
+ }
+
+ chanMgr->hitlistlock.on();
+
+ chl = chanMgr->findHitList(ch->info);
+ if (chl)
+ {
+ ChanHitSearch chs;
+
+ // find local hit
+ if (!ch->sourceHost.host.ip){
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_RELAY_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use local hit");
+ }
+ }
+
+ // else find global hit
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = MIN_RELAY_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use global hit");
+ }
+ }
+
+
+ // else find local tracker
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use local tracker");
+ }
+ }
+
+ // find tracker
+ unsigned int ctime = sys->getTime();
+ if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
+ if (ch->trackerHit.lastContact + 30 < ctime){
+ ch->sourceHost = ch->trackerHit;
+ ch->trackerHit.lastContact = ctime;
+ LOG_DEBUG("use saved tracker");
+ }
+ }
+
+ // else find global tracker
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ tracker_check = true;
+ ch->trackerHit = chs.best[0];
+ LOG_DEBUG("use global tracker");
+ }
+ }
+ }
+
+ chanMgr->hitlistlock.off();
+
+ if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
+ ch->lastStopTime = 0;
+ LOG_DEBUG("------------ disconnect all downstreams");
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+
+ // no trackers found so contact YP
+ if (!tracker_check && !ch->sourceHost.host.ip)
+ {
+ next_yp = false;
+ if (servMgr->rootHost.isEmpty())
+ goto yp2;
+
+ if (numYPTries >= 3)
+ goto yp2;
+
+ if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
+ goto yp2;
+
+ unsigned int ctime=sys->getTime();
+ if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
+ {
+ ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+ ch->sourceHost.yp = true;
+ chanMgr->lastYPConnect=ctime;
+ numYPTries++;
+ }
+ if (numYPTries < 3)
+ next_yp = true;
+ }
+
+yp2:
+ // no trackers found so contact YP2
+ if (!tracker_check && !ch->sourceHost.host.ip)
+ {
+// next_yp = false;
+ if (servMgr->rootHost2.isEmpty())
+ goto yp0;
+
+ if (numYPTries2 >= 3)
+ goto yp0;
+
+ unsigned int ctime=sys->getTime();
+ if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
+ {
+ ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
+ ch->sourceHost.yp = true;
+ chanMgr->lastYPConnect2=ctime;
+ numYPTries2++;
+ }
+ if (numYPTries2 < 3)
+ next_yp = true;
+ }
+yp0:
+ if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
+
+ sys->sleepIdle();
+
+ }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
+
+ if (!ch->sourceHost.host.ip)
+ {
+ LOG_ERROR("Channel giving up");
+ ch->setStatus(Channel::S_ERROR);
+ break;
+ }
+
+ if (ch->sourceHost.yp)
+ {
+ LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
+ }else
+ {
+ LOG_CHANNEL("Channel found hit");
+ numYPTries=0;
+ numYPTries2=0;
+ }
+
+ if (ch->sourceHost.host.ip)
+ {
+ bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
+
+
+ //if (ch->sourceHost.tracker)
+ // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
+
+ char ipstr[64];
+ ch->sourceHost.host.toStr(ipstr);
+
+ char *type = "";
+ if (ch->sourceHost.tracker)
+ type = "(tracker)";
+ else if (ch->sourceHost.yp)
+ type = "(YP)";
+
+ int error=-1;
+ int got503 = 0;
+ try
+ {
+ ch->setStatus(Channel::S_CONNECTING);
+ ch->sourceHost.lastContact = sys->getTime();
+
+ if (!ch->sock)
+ {
+ LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
+ ch->connectFetch();
+ }
+
+ error = ch->handshakeFetch();
+ if (error == 503) {
+ got503 = 1;
+ error = 0;
+ }
+ if (error)
+ throw StreamException("Handshake error");
+ if (ch->sourceHost.tracker) connFailCnt = 0;
+
+ if (servMgr->autoMaxRelaySetting) //JP-EX
+ {
+ double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
+ if ((unsigned int)setMaxRelays == 0)
+ servMgr->maxRelays = 1;
+ else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
+ servMgr->maxRelays = servMgr->autoMaxRelaySetting;
+ else
+ servMgr->maxRelays = (unsigned int)setMaxRelays;
+ }
+
+ ch->sourceStream = ch->createSource();
+
+ error = ch->readStream(*ch->sock,ch->sourceStream);
+ if (error)
+ throw StreamException("Stream error");
+
+ error = 0; // no errors, closing normally.
+// ch->setStatus(Channel::S_CLOSING);
+ ch->setStatus(Channel::S_IDLE);
+
+ LOG_CHANNEL("Channel closed normally");
+ }catch(StreamException &e)
+ {
+ ch->setStatus(Channel::S_ERROR);
+ LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
+ if (!servMgr->allowConnectPCST) //JP-EX
+ {
+ if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
+ ch->thread.active = false;
+ }
+ //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
+ if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
+ chanMgr->deadHit(ch->sourceHost);
+ if (ch->sourceHost.tracker && error == -1) {
+ LOG_ERROR("can't connect to tracker");
+ connFailCnt++;
+ }
+ }
+
+ unsigned int ctime = sys->getTime();
+ if (ch->rawData.lastWriteTime) {
+ ch->lastStopTime = ch->rawData.lastWriteTime;
+ if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
+ ch->lastStopTime = ctime;
+ }
+
+ if (tracker_check && ch->sourceHost.tracker)
+ ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
+
+ // broadcast source host
+ if (!error && ch->sourceHost.host.ip) { // if closed normally
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ ch->sourceHost.writeAtoms(atom, ch->info.id);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+ LOG_DEBUG("stream: broadcast sourceHost");
+ }
+
+ // broadcast quit to any connected downstream servents
+ if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+ LOG_DEBUG("------------ broadcast quit to all downstreams");
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+
+
+ if (ch->sourceStream)
+ {
+ try
+ {
+ if (!error)
+ {
+ ch->sourceStream->updateStatus(ch);
+ ch->sourceStream->flush(*ch->sock);
+ }
+ }catch(StreamException &)
+ {}
+ ChannelStream *cs = ch->sourceStream;
+ ch->sourceStream = NULL;
+ cs->kill();
+ delete cs;
+ }
+
+ if (ch->sock)
+ {
+ ch->sock->close();
+ delete ch->sock;
+ ch->sock = NULL;
+ }
+
+ if (error == 404)
+ {
+ LOG_ERROR("Channel not found");
+ //if (!next_yp){
+ if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(true);
+ }
+ chanMgr->hitlistlock.off();
+
+ if(!isIndexTxt(&ch->info)) // for PCRaw (popup)
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+ return;
+ }
+ }
+
+
+ }
+
+ ch->lastIdleTime = sys->getTime();
+ ch->setStatus(Channel::S_IDLE);
+ ch->skipCount = 0; //JP-EX
+ ch->lastSkipTime = 0;
+ while ((ch->checkIdle()) && (ch->thread.active))
+ {
+ sys->sleepIdle();
+ }
+
+ sys->sleepIdle();
+ }
+
+}
+// -----------------------------------
+void Channel::startICY(ClientSocket *cs, SRC_TYPE st)
+{
+ srcType = st;
+ type = T_BROADCAST;
+ cs->setReadTimeout(0); // stay connected even when theres no data coming through
+ sock = cs;
+ info.srcProtocol = ChanInfo::SP_HTTP;
+
+ streamIndex = ++chanMgr->icyIndex;
+
+ sourceData = new ICYSource();
+ startStream();
+}
+
+// -----------------------------------
+static char *nextMetaPart(char *str,char delim)
+{
+ while (*str)
+ {
+ if (*str == delim)
+ {
+ *str++ = 0;
+ return str;
+ }
+ str++;
+ }
+ return NULL;
+}
+// -----------------------------------
+static void copyStr(char *to,char *from,int max)
+{
+ char c;
+ while ((c=*from++) && (--max))
+ if (c != '\'')
+ *to++ = c;
+
+ *to = 0;
+}
+
+// -----------------------------------
+void Channel::processMp3Metadata(char *str)
+{
+ ChanInfo newInfo = info;
+
+ char *cmd=str;
+ while (cmd)
+ {
+ char *arg = nextMetaPart(cmd,'=');
+ if (!arg)
+ break;
+
+ char *next = nextMetaPart(arg,';');
+
+ if (strcmp(cmd,"StreamTitle")==0)
+ {
+ newInfo.track.title.setUnquote(arg,String::T_ASCII);
+ newInfo.track.title.convertTo(String::T_UNICODE);
+
+ }else if (strcmp(cmd,"StreamUrl")==0)
+ {
+ newInfo.track.contact.setUnquote(arg,String::T_ASCII);
+ newInfo.track.contact.convertTo(String::T_UNICODE);
+ }
+
+
+ cmd = next;
+ }
+
+ updateInfo(newInfo);
+}
+
+// -----------------------------------
+XML::Node *ChanHit::createXML()
+{
+ // IP
+ char ipStr[64];
+ host.toStr(ipStr);
+
+ 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\"",
+ ipStr,
+ numHops,
+ numListeners,
+ numRelays,
+ upTime,
+ firewalled?1:0,
+ relay?1:0,
+ direct?1:0,
+ cin?1:0,
+ stable?1:0,
+ version,
+ sys->getTime()-time,
+ tracker
+ );
+
+}
+
+// -----------------------------------
+XML::Node *ChanHitList::createXML(bool addHits)
+{
+ XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
+ numHits(),
+ numListeners(),
+ numRelays(),
+ numFirewalled(),
+ closestHit(),
+ furthestHit(),
+ sys->getTime()-newestHit()
+ );
+
+ if (addHits)
+ {
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ hn->add(h->createXML());
+ h = h->next;
+ }
+ }
+
+ return hn;
+}
+
+// -----------------------------------
+XML::Node *Channel::createRelayXML(bool showStat)
+{
+ const char *ststr;
+ ststr = getStatusStr();
+ if (!showStat)
+ if ((status == S_RECEIVING) || (status == S_BROADCASTING))
+ ststr = "OK";
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+
+ return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
+ localListeners(),
+ localRelays(),
+ (chl!=NULL)?chl->numHits():0,
+ ststr
+ );
+}
+
+// -----------------------------------
+void ChanMeta::fromXML(XML &xml)
+{
+ MemoryStream tout(data,MAX_DATALEN);
+ xml.write(tout);
+
+ len = tout.pos;
+}
+// -----------------------------------
+void ChanMeta::fromMem(void *p, int l)
+{
+ len = l;
+ memcpy(data,p,len);
+}
+// -----------------------------------
+void ChanMeta::addMem(void *p, int l)
+{
+ if ((len+l) <= MAX_DATALEN)
+ {
+ memcpy(data+len,p,l);
+ len += l;
+ }
+}
+// -----------------------------------
+void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+ unsigned int ctime = sys->getTime();
+
+ if (((ctime-lastTrackerUpdate) > 30) || (force))
+ {
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack));
+
+ AtomStream atom(mem);
+
+ ChanHit hit;
+
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (!chl)
+ throw StreamException("Broadcast channel has no hitlist");
+
+ int numListeners = totalListeners();
+ int numRelays = totalRelays();
+
+ unsigned int oldp = rawData.getOldestPos();
+ unsigned int newp = rawData.getLatestPos();
+
+ hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
+ hit.tracker = true;
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,11);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeParent(PCP_CHAN,4);
+ atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+ atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
+ info.writeInfoAtoms(atom);
+ info.writeTrackAtoms(atom);
+ hit.writeAtoms(atom,info.id);
+
+
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+ GnuID noID;
+ noID.clear();
+ int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
+
+ if (cnt)
+ {
+ LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
+ lastTrackerUpdate = ctime;
+ }
+ }
+}
+
+// -----------------------------------
+bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
+{
+ if ( isActive()
+ && (!cid.isSet() || info.id.isSame(cid))
+ && (!sid.isSet() || !remoteID.isSame(sid))
+ && sourceStream
+ )
+ return sourceStream->sendPacket(pack,did);
+
+ return false;
+}
+
+// -----------------------------------
+void Channel::updateInfo(ChanInfo &newInfo)
+{
+ if (info.update(newInfo))
+ {
+ if (isBroadcasting())
+ {
+ unsigned int ctime = sys->getTime();
+ if ((ctime-lastMetaUpdate) > 30)
+ {
+ lastMetaUpdate = ctime;
+
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack));
+
+ AtomStream atom(mem);
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
+ atom.writeParent(PCP_CHAN,3);
+ atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+ info.writeInfoAtoms(atom);
+ info.writeTrackAtoms(atom);
+
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
+
+ broadcastTrackerUpdate(noID);
+ }
+ }
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+ if (chl)
+ chl->info = info;
+
+ peercastApp->channelUpdate(&info);
+
+ }
+
+}
+// -----------------------------------
+ChannelStream *Channel::createSource()
+{
+// if (servMgr->relayBroadcast)
+// chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
+
+
+ ChannelStream *source=NULL;
+
+ if (info.srcProtocol == ChanInfo::SP_PEERCAST)
+ {
+ LOG_CHANNEL("Channel is Peercast");
+ if (servMgr->allowConnectPCST) //JP-EX
+ source = new PeercastStream();
+ else
+ throw StreamException("Channel is not allowed");
+ }
+ else if (info.srcProtocol == ChanInfo::SP_PCP)
+ {
+ LOG_CHANNEL("Channel is PCP");
+ PCPStream *pcp = new PCPStream(remoteID);
+ source = pcp;
+ }
+ else if (info.srcProtocol == ChanInfo::SP_MMS)
+ {
+ LOG_CHANNEL("Channel is MMS");
+ source = new MMSStream();
+ }else
+ {
+ switch(info.contentType)
+ {
+ case ChanInfo::T_MP3:
+ LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
+ source = new MP3Stream();
+ break;
+ case ChanInfo::T_NSV:
+ LOG_CHANNEL("Channel is NSV");
+ source = new NSVStream();
+ break;
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ throw StreamException("Channel is WMA/WMV - but not MMS");
+ break;
+ case ChanInfo::T_OGG:
+ case ChanInfo::T_OGM:
+ LOG_CHANNEL("Channel is OGG");
+ source = new OGGStream();
+ break;
+ default:
+ LOG_CHANNEL("Channel is Raw");
+ source = new RawStream();
+ break;
+ }
+ }
+
+ source->parent = this;
+
+ return source;
+}
+// ------------------------------------------
+void ChannelStream::updateStatus(Channel *ch)
+{
+ ChanPacket pack;
+ if (getStatus(ch,pack))
+ {
+ if (!ch->isBroadcasting())
+ {
+ GnuID noID;
+ noID.clear();
+ int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
+ LOG_CHANNEL("Sent channel status update to %d clients",cnt);
+ }
+ }
+}
+
+// ------------------------------------------
+bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
+{
+ unsigned int ctime = sys->getTime();
+
+ ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
+
+ if (!chl)
+ return false;
+
+/* int newLocalListeners = ch->localListeners();
+ int newLocalRelays = ch->localRelays();
+
+ if (
+ (
+ (numListeners != newLocalListeners)
+ || (numRelays != newLocalRelays)
+ || (ch->isPlaying() != isPlaying)
+ || (servMgr->getFirewall() != fwState)
+ || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+ )
+ && ((ctime-lastUpdate) > 10)
+ )
+ {
+
+ numListeners = newLocalListeners;
+ numRelays = newLocalRelays;
+ isPlaying = ch->isPlaying();
+ fwState = servMgr->getFirewall();
+ lastUpdate = ctime;
+
+ ChanHit hit;
+
+ hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
+ hit.tracker = ch->isBroadcasting();*/
+
+ int newLocalListeners = ch->localListeners();
+ int newLocalRelays = ch->localRelays();
+
+ if ((ch->isPlaying() == isPlaying)){
+ if ((ctime-lastUpdate) < 10){
+ return false;
+ }
+
+ if ((ctime-lastCheckTime) < 10){
+ return false;
+ }
+ lastCheckTime = ctime;
+ }
+
+ unsigned int oldp = ch->rawData.getOldestPos();
+ unsigned int newp = ch->rawData.getLatestPos();
+
+ ChanHit hit;
+
+// LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
+
+ hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
+ hit.tracker = ch->isBroadcasting();
+
+ if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+ || (newLocalListeners != numListeners)
+ || (newLocalRelays != numRelays)
+ || (ch->isPlaying() != isPlaying)
+ || (servMgr->getFirewall() != fwState)
+ || (ch->chDisp.relay != hit.relay)
+ || (ch->chDisp.relayfull != hit.relayfull)
+ || (ch->chDisp.chfull != hit.chfull)
+ || (ch->chDisp.ratefull != hit.ratefull)
+ ){
+ numListeners = newLocalListeners;
+ numRelays = newLocalRelays;
+ isPlaying = ch->isPlaying();
+ fwState = servMgr->getFirewall();
+ lastUpdate = ctime;
+
+ ch->chDisp = hit;
+
+ if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
+ ch->stayConnected = true;
+
+ if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
+ ch->stayConnected = false;
+
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream atom(pmem);
+
+ GnuID noID;
+ noID.clear();
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,11);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
+ hit.writeAtoms(atom,noID);
+
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+ return true;
+ }else
+ return false;
+}
+// -----------------------------------
+bool Channel::checkBump()
+{
+ if (!isBroadcasting() && (!sourceHost.tracker))
+ if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30))
+ {
+ LOG_ERROR("Channel Auto bumped");
+ bump = true;
+ }
+
+ if (bump)
+ {
+ bump = false;
+ return true;
+ }else
+ return false;
+}
+
+// -----------------------------------
+int Channel::readStream(Stream &in,ChannelStream *source)
+{
+ //sys->sleep(300);
+
+ int error = 0;
+
+ info.numSkips = 0;
+
+ source->readHeader(in,this);
+
+ peercastApp->channelStart(&info);
+
+ rawData.lastWriteTime = 0;
+
+ bool wasBroadcasting=false;
+
+ unsigned int receiveStartTime = 0;
+
+ try
+ {
+ while (thread.active && !peercastInst->isQuitting)
+ {
+ if (checkIdle())
+ {
+ LOG_DEBUG("Channel idle");
+ break;
+ }
+
+ if (checkBump())
+ {
+ LOG_DEBUG("Channel bumped");
+ error = -1;
+ bumped = true;
+ break;
+ }
+
+ if (in.eof())
+ {
+ LOG_DEBUG("Channel eof");
+ break;
+ }
+
+ if (in.readReady())
+ {
+ error = source->readPacket(in,this);
+
+ if (error)
+ break;
+
+ //if (rawData.writePos > 0)
+ if (rawData.lastWriteTime > 0)
+ {
+ if (isBroadcasting())
+ {
+ if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
+ {
+ GnuID noID;
+ noID.clear();
+ broadcastTrackerUpdate(noID);
+ }
+ wasBroadcasting = true;
+
+ }else
+ {
+/* if (status != Channel::S_RECEIVING){
+ receiveStartTime = sys->getTime();
+ } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(info);
+ if (hl){
+ hl->clearHits(true);
+ }
+ chanMgr->hitlistlock.off();
+ receiveStartTime = 0;
+ }*/
+ setStatus(Channel::S_RECEIVING);
+ bumped = false;
+ }
+ source->updateStatus(this);
+ }
+ }
+
+ source->flush(in);
+
+ sys->sleepIdle();
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("readStream: %s",e.msg);
+ error = -1;
+ }
+
+ if (!servMgr->keepDownstreams) {
+ if (status == Channel::S_RECEIVING){
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+ }
+
+// setStatus(S_CLOSING);
+ setStatus(S_IDLE);
+
+ if (wasBroadcasting)
+ {
+ GnuID noID;
+ noID.clear();
+ broadcastTrackerUpdate(noID,true);
+ }
+
+ peercastApp->channelStop(&info);
+
+ source->readEnd(in,this);
+
+ return error;
+}
+
+// -----------------------------------
+void PeercastStream::readHeader(Stream &in,Channel *ch)
+{
+ if (in.readTag() != 'PCST')
+ throw StreamException("Not PeerCast stream");
+
+}
+// -----------------------------------
+void PeercastStream::readEnd(Stream &,Channel *)
+{
+
+}
+// -----------------------------------
+int PeercastStream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ {
+
+ pack.readPeercast(in);
+
+ MemoryStream mem(pack.data,pack.len);
+
+ switch(pack.type)
+ {
+ case ChanPacket::T_HEAD:
+ // update sync pos
+ ch->headPack = pack;
+ pack.pos = ch->streamPos;
+ ch->newPacket(pack);
+ ch->streamPos+=pack.len;
+ break;
+ case ChanPacket::T_DATA:
+ pack.pos = ch->streamPos;
+ ch->newPacket(pack);
+ ch->streamPos+=pack.len;
+ break;
+ case ChanPacket::T_META:
+ ch->insertMeta.fromMem(pack.data,pack.len);
+ {
+ if (pack.len)
+ {
+ XML xml;
+ xml.read(mem);
+ XML::Node *n = xml.findNode("channel");
+ if (n)
+ {
+ ChanInfo newInfo = ch->info;
+ newInfo.updateFromXML(n);
+ ChanHitList *chl = chanMgr->findHitList(ch->info);
+ if (chl)
+ newInfo.updateFromXML(n);
+ ch->updateInfo(newInfo);
+ }
+ }
+ }
+ break;
+#if 0
+ case ChanPacket::T_SYNC:
+ {
+ unsigned int s = mem.readLong();
+ if ((s-ch->syncPos) != 1)
+ {
+ LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
+ if (ch->syncPos)
+ {
+ ch->info.numSkips++;
+ if (ch->info.numSkips>50)
+ throw StreamException("Bumped - Too many skips");
+ }
+ }
+
+ ch->syncPos = s;
+ }
+ break;
+#endif
+
+ }
+
+ }
+ return 0;
+}
+
+// -----------------------------------
+void ChannelStream::readRaw(Stream &in, Channel *ch)
+{
+ ChanPacket pack;
+
+ const int readLen = 8192;
+
+ pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos+=pack.len;
+
+}
+// ------------------------------------------
+void RawStream::readHeader(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int RawStream::readPacket(Stream &in,Channel *ch)
+{
+ readRaw(in,ch);
+ return 0;
+}
+
+// ------------------------------------------
+void RawStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+
+// -----------------------------------
+void ChanPacket::init(ChanPacketv &p)
+{
+ type = p.type;
+ len = p.len;
+ pos = p.pos;
+ sync = p.sync;
+ skip = p.skip;
+ memcpy(data, p.data, len);
+}
+// -----------------------------------
+void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
+{
+ type = t;
+ if (l > MAX_DATALEN)
+ throw StreamException("Packet data too large");
+ len = l;
+ memcpy(data,p,len);
+ pos = _pos;
+ skip = false;
+}
+// -----------------------------------
+void ChanPacket::writeRaw(Stream &out)
+{
+ out.write(data,len);
+}
+// -----------------------------------
+void ChanPacket::writePeercast(Stream &out)
+{
+ unsigned int tp = 0;
+ switch (type)
+ {
+ case T_HEAD: tp = 'HEAD'; break;
+ case T_META: tp = 'META'; break;
+ case T_DATA: tp = 'DATA'; break;
+ }
+
+ if (type != T_UNKNOWN)
+ {
+ out.writeTag(tp);
+ out.writeShort(len);
+ out.writeShort(0);
+ out.write(data,len);
+ }
+}
+// -----------------------------------
+void ChanPacket::readPeercast(Stream &in)
+{
+ unsigned int tp = in.readTag();
+
+ switch (tp)
+ {
+ case 'HEAD': type = T_HEAD; break;
+ case 'DATA': type = T_DATA; break;
+ case 'META': type = T_META; break;
+ default: type = T_UNKNOWN;
+ }
+ len = in.readShort();
+ in.readShort();
+ if (len > MAX_DATALEN)
+ throw StreamException("Bad ChanPacket");
+ in.read(data,len);
+}
+// -----------------------------------
+int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
+{
+ lock.on();
+ buf.lock.on();
+
+ firstPos = 0;
+ lastPos = 0;
+ safePos = 0;
+ readPos = 0;
+
+ for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
+ {
+ //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
+ ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
+ if (src->type & accept)
+ {
+ if (src->pos >= reqPos)
+ {
+ lastPos = writePos;
+ //packets[writePos++] = *src;
+ packets[writePos++].init(*src);
+ }
+ }
+
+ }
+
+
+ buf.lock.off();
+ lock.off();
+ return lastPos-firstPos;
+}
+
+// -----------------------------------
+bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
+{
+ if (writePos == 0)
+ return false;
+
+ lock.on();
+
+ unsigned int fpos = getStreamPos(firstPos);
+ if (spos < fpos)
+ spos = fpos;
+
+
+ for(unsigned int i=firstPos; i<=lastPos; i++)
+ {
+ //ChanPacket &p = packets[i%MAX_PACKETS];
+ ChanPacketv &p = packets[i%MAX_PACKETS];
+ if (p.pos >= spos)
+ {
+ pack.init(p);
+ lock.off();
+ return true;
+ }
+ }
+
+ lock.off();
+ return false;
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getLatestPos()
+{
+ if (!writePos)
+ return 0;
+ else
+ return getStreamPos(lastPos);
+
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getOldestPos()
+{
+ if (!writePos)
+ return 0;
+ else
+ return getStreamPos(firstPos);
+}
+
+// -----------------------------------
+unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos)
+{
+ unsigned int min = getStreamPos(safePos);
+ unsigned int max = getStreamPos(lastPos);
+
+ if (min > spos)
+ return min;
+
+ if (max < spos)
+ return max;
+
+ return spos;
+}
+
+// -----------------------------------
+unsigned int ChanPacketBuffer::getStreamPos(unsigned int index)
+{
+ return packets[index%MAX_PACKETS].pos;
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index)
+{
+ return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
+}
+// -----------------------------------
+bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
+{
+ if (pack.len)
+ {
+ if (servMgr->keepDownstreams) {
+ unsigned int lpos = getLatestPos();
+ unsigned int diff = pack.pos - lpos;
+ if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
+ if (lpos && (diff == 0 || diff > 0xfff00000)) {
+ LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
+ return false;
+ }
+ }
+
+ if (willSkip()) // too far behind
+ {
+ lastSkipTime = sys->getTime();
+ return false;
+ }
+
+ lock.on();
+
+ pack.sync = writePos;
+ packets[writePos%MAX_PACKETS].init(pack);
+
+// LOG_DEBUG("packet.len = %d",pack.len);
+
+
+ lastPos = writePos;
+ writePos++;
+
+ if (writePos >= MAX_PACKETS)
+ firstPos = writePos-MAX_PACKETS;
+ else
+ firstPos = 0;
+
+ if (writePos >= NUM_SAFEPACKETS)
+ safePos = writePos - NUM_SAFEPACKETS;
+ else
+ safePos = 0;
+
+ if (updateReadPos)
+ readPos = writePos;
+
+ lastWriteTime = sys->getTime();
+
+ lock.off();
+ return true;
+ }
+
+ return false;
+}
+// -----------------------------------
+void ChanPacketBuffer::readPacket(ChanPacket &pack)
+{
+
+ unsigned int tim = sys->getTime();
+
+ if (readPos < firstPos)
+ throw StreamException("Read too far behind");
+
+ while (readPos >= writePos)
+ {
+ sys->sleepIdle();
+ if ((sys->getTime() - tim) > 30)
+ throw TimeoutException();
+ }
+ lock.on();
+ pack.init(packets[readPos%MAX_PACKETS]);
+ readPos++;
+ lock.off();
+
+ sys->sleepIdle();
+
+}
+// -----------------------------------
+bool ChanPacketBuffer::willSkip()
+{
+ return ((writePos-readPos) >= MAX_PACKETS);
+}
+
+// -----------------------------------
+void Channel::getStreamPath(char *str)
+{
+ char idStr[64];
+
+ getIDStr(idStr);
+
+ sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
+}
+
+
+
+// -----------------------------------
+void ChanMgr::startSearch(ChanInfo &info)
+{
+ searchInfo = info;
+ clearHitLists();
+ numFinds = 0;
+ lastHit = 0;
+// lastSearch = 0;
+ searchActive = true;
+}
+// -----------------------------------
+void ChanMgr::quit()
+{
+ LOG_DEBUG("ChanMgr is quitting..");
+ closeAll();
+}
+// -----------------------------------
+int ChanMgr::numIdleChannels()
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->thread.active)
+ if (ch->status == Channel::S_IDLE)
+ cnt++;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+void ChanMgr::closeOldestIdle()
+{
+ unsigned int idleTime = (unsigned int)-1;
+ Channel *ch = channel,*oldest=NULL;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->thread.active)
+ if (ch->status == Channel::S_IDLE)
+ if (ch->lastIdleTime < idleTime)
+ {
+ oldest = ch;
+ idleTime = ch->lastIdleTime;
+ }
+ ch=ch->next;
+ }
+
+ if (oldest)
+ oldest->thread.active = false;
+}
+
+// -----------------------------------
+void ChanMgr::closeAll()
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->thread.active)
+ ch->thread.shutdown();
+ ch=ch->next;
+ }
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.matchNameID(info))
+ return ch;
+ ch=ch->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Channel *ChanMgr::findChannelByName(const char *n)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (stricmp(ch->info.name,n)==0)
+ return ch;
+ ch=ch->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByIndex(int index)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ {
+ if (cnt == index)
+ return ch;
+ cnt++;
+ }
+ ch=ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByMount(const char *str)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (strcmp(ch->mount,str)==0)
+ return ch;
+ ch=ch->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByID(GnuID &id)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.id.isSame(id))
+ return ch;
+ ch=ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByChannelID(int id)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive()){
+ if (ch->channel_id == id){
+ return ch;
+ }
+ }
+ ch = ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.match(info))
+ {
+ chlist[cnt++] = ch;
+ if (cnt >= max)
+ break;
+ }
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->status == status)
+ {
+ chlist[cnt++] = ch;
+ if (cnt >= max)
+ break;
+ }
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
+{
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ {
+ c->stayConnected = stayConnected;
+ c->startGet();
+ return c;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findAndRelay(ChanInfo &info)
+{
+ char idStr[64];
+ info.id.toStr(idStr);
+ LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
+
+ if(!isIndexTxt(&info)) // for PCRaw (popup)
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
+
+
+ Channel *c = NULL;
+
+ WLockBlock wb(&(chanMgr->channellock));
+
+ wb.on();
+
+ c = findChannelByNameID(info);
+
+ if (!c)
+ {
+ c = chanMgr->createChannel(info,NULL);
+ if (c)
+ {
+ c->setStatus(Channel::S_SEARCHING);
+ c->startGet();
+ }
+ } else if (!(c->thread.active)){
+ c->thread.active = true;
+ c->thread.finish = false;
+ if (c->finthread){
+ c->finthread->finish = true;
+ c->finthread = NULL;
+ }
+ if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
+ c->setStatus(Channel::S_SEARCHING);
+ c->startGet();
+ }
+ }
+
+ wb.off();
+
+ for(int i=0; i<600; i++) // search for 1 minute.
+ {
+
+
+ wb.on();
+ c = findChannelByNameID(info);
+
+ if (!c)
+ {
+// peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+ return NULL;
+ }
+
+
+ if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
+ break;
+
+ wb.off();
+
+ sys->sleep(100);
+ }
+
+ return c;
+}
+// -----------------------------------
+ChanMgr::ChanMgr()
+{
+ channel = NULL;
+
+ hitlist = NULL;
+
+ currFindAndPlayChannel.clear();
+
+ broadcastMsg.clear();
+ broadcastMsgInterval=10;
+
+ broadcastID.generate(PCP_BROADCAST_FLAGS);
+
+ deadHitAge = 600;
+
+ icyIndex = 0;
+ icyMetaInterval = 8192;
+ maxRelaysPerChannel = 1;
+
+ searchInfo.init();
+
+ minBroadcastTTL = 1;
+ maxBroadcastTTL = 7;
+
+ pushTimeout = 60; // 1 minute
+ pushTries = 5; // 5 times
+ maxPushHops = 8; // max 8 hops away
+ maxUptime = 0; // 0 = none
+
+ prefetchTime = 10; // n seconds
+
+ hostUpdateInterval = 120; // 2 minutes
+
+ bufferTime = 5;
+
+ autoQuery = 0;
+ lastQuery = 0;
+
+ lastYPConnect = 0;
+ lastYPConnect2 = 0;
+
+}
+
+// -----------------------------------
+bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
+{
+ char buf[1024];
+ if (var == "numHitLists")
+ sprintf(buf,"%d",numHitLists());
+
+ else if (var == "numChannels")
+ sprintf(buf,"%d",numChannels());
+ else if (var == "djMessage")
+ strcpy(buf,broadcastMsg.cstr());
+ else if (var == "icyMetaInterval")
+ sprintf(buf,"%d",icyMetaInterval);
+ else if (var == "maxRelaysPerChannel")
+ sprintf(buf,"%d",maxRelaysPerChannel);
+ else if (var == "hostUpdateInterval")
+ sprintf(buf,"%d",hostUpdateInterval);
+ else if (var == "broadcastID")
+ broadcastID.toStr(buf);
+ else
+ return false;
+
+
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+bool Channel::writeVariable(Stream &out, const String &var, int index)
+{
+ char buf[1024];
+
+ buf[0]=0;
+
+ String utf8;
+
+ if (var == "name")
+ {
+ utf8 = info.name;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+
+ }else if (var == "bitrate")
+ {
+ sprintf(buf,"%d",info.bitrate);
+
+ }else if (var == "srcrate")
+ {
+ if (sourceData)
+ {
+ unsigned int tot = sourceData->getSourceRate();
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+ }else
+ strcpy(buf,"0");
+
+ }else if (var == "genre")
+ {
+ utf8 = info.genre;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "desc")
+ {
+ utf8 = info.desc;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "comment")
+ {
+ utf8 = info.comment;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "uptime")
+ {
+ String uptime;
+ if (info.lastPlayStart)
+ uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
+ else
+ uptime.set("-");
+ strcpy(buf,uptime.cstr());
+ }
+ else if (var == "type")
+ sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
+ else if (var == "ext")
+ sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
+ else if (var == "proto") {
+ switch(info.contentType) {
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ sprintf(buf, "mms://");
+ break;
+ default:
+ sprintf(buf, "http://");
+ }
+ }
+ else if (var == "localRelays")
+ sprintf(buf,"%d",localRelays());
+ else if (var == "localListeners")
+ sprintf(buf,"%d",localListeners());
+
+ else if (var == "totalRelays")
+ sprintf(buf,"%d",totalRelays());
+ else if (var == "totalListeners")
+ sprintf(buf,"%d",totalListeners());
+
+ else if (var == "status")
+ sprintf(buf,"%s",getStatusStr());
+ else if (var == "keep")
+ sprintf(buf,"%s",stayConnected?"Yes":"No");
+ else if (var == "id")
+ info.id.toStr(buf);
+ else if (var.startsWith("track."))
+ {
+
+ if (var == "track.title")
+ utf8 = info.track.title;
+ else if (var == "track.artist")
+ utf8 = info.track.artist;
+ else if (var == "track.album")
+ utf8 = info.track.album;
+ else if (var == "track.genre")
+ utf8 = info.track.genre;
+ else if (var == "track.contactURL")
+ utf8 = info.track.contact;
+
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+
+ }else if (var == "contactURL")
+ sprintf(buf,"%s",info.url.cstr());
+ else if (var == "streamPos")
+ sprintf(buf,"%d",streamPos);
+ else if (var == "sourceType")
+ strcpy(buf,getSrcTypeStr());
+ else if (var == "sourceProtocol")
+ strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
+ else if (var == "sourceURL")
+ {
+ if (sourceURL.isEmpty())
+ sourceHost.host.toStr(buf);
+ else
+ strcpy(buf,sourceURL.cstr());
+ }
+ else if (var == "headPos")
+ sprintf(buf,"%d",headPack.pos);
+ else if (var == "headLen")
+ sprintf(buf,"%d",headPack.len);
+ else if (var == "numHits")
+ {
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ int numHits = 0;
+ if (chl){
+// numHits = chl->numHits();
+ ChanHit *hit;
+ hit = chl->hit;
+ while(hit){
+ numHits++;
+ hit = hit->next;
+ }
+ }
+ sprintf(buf,"%d",numHits);
+ } else if (var == "isBroadcast")
+ strcpy(buf, (type == T_BROADCAST) ? "1":"0");
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+ Channel *c = channel;
+ while(c)
+ {
+ if ( c->isActive() && c->isBroadcasting() )
+ c->broadcastTrackerUpdate(svID,force);
+ c=c->next;
+ }
+}
+
+
+// -----------------------------------
+int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
+{
+ int cnt=0;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->sendPacketUp(pack,chanID,srcID,destID))
+ cnt++;
+ c=c->next;
+ }
+
+ return cnt;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
+{
+ //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
+ {
+
+ Host sh = servMgr->serverHost;
+ bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+ bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+ bool stable = servMgr->totalStreams>0;
+
+
+ GnuPacket hit;
+
+ int numChans=0;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->isPlaying())
+ {
+
+ bool tracker = c->isBroadcasting();
+
+ int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds
+
+ if (ttl < minTTL)
+ ttl = minTTL;
+
+ if (ttl > maxTTL)
+ ttl = maxTTL;
+
+ if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
+ {
+ int numOut=0;
+ numChans++;
+ if (serv)
+ {
+ serv->outputPacket(hit,false);
+ numOut++;
+ }
+
+ LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);
+
+ }
+ }
+ c=c->next;
+ }
+ //if (numChans)
+ // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);
+ }
+}
+// -----------------------------------
+void ChanMgr::setUpdateInterval(unsigned int v)
+{
+ hostUpdateInterval = v;
+}
+
+
+// -----------------------------------
+// message check
+#if 0
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeParent(PCP_BCST,3);
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeParent(PCP_MESG,1);
+ atom.writeString(PCP_MESG_DATA,msg.cstr());
+
+ mem.len = mem.pos;
+ mem.rewind();
+ pack.len = mem.len;
+
+ GnuID noID;
+ noID.clear();
+
+ BroadcastState bcs;
+ PCPStream::readAtom(atom,bcs);
+ //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+ //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
+ //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+ //LOG_DEBUG("Sent message to %d clients",cnt);
+#endif
+// -----------------------------------
+void ChanMgr::setBroadcastMsg(String &msg)
+{
+ if (!msg.isSame(broadcastMsg))
+ {
+ broadcastMsg = msg;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->isActive() && c->isBroadcasting())
+ {
+ ChanInfo newInfo = c->info;
+ newInfo.comment = broadcastMsg;
+ c->updateInfo(newInfo);
+ }
+ c=c->next;
+ }
+
+ }
+}
+
+
+// -----------------------------------
+void ChanMgr::clearHitLists()
+{
+
+// LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ while (hitlist)
+ {
+ peercastApp->delChannel(&hitlist->info);
+
+ ChanHitList *next = hitlist->next;
+
+ delete hitlist;
+
+ hitlist = next;
+ }
+// LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+Channel *ChanMgr::deleteChannel(Channel *delchan)
+{
+ lock.on();
+
+ Channel *ch = channel,*prev=NULL,*next=NULL;
+
+ while (ch)
+ {
+ if (ch == delchan)
+ {
+ Channel *next = ch->next;
+ if (prev)
+ prev->next = next;
+ else
+ channel = next;
+
+ if (delchan->sourceStream){
+ delchan->sourceStream->parent = NULL;
+ }
+
+ delete delchan;
+
+ break;
+ }
+ prev = ch;
+ ch=ch->next;
+ }
+
+
+ lock.off();
+ return next;
+}
+
+// -----------------------------------
+Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
+{
+ lock.on();
+
+ Channel *nc=NULL;
+
+ nc = new Channel();
+
+ nc->next = channel;
+ channel = nc;
+
+
+ nc->info = info;
+ nc->info.lastPlayStart = 0;
+ nc->info.lastPlayEnd = 0;
+ nc->info.status = ChanInfo::S_UNKNOWN;
+ if (mount)
+ nc->mount.set(mount);
+ nc->setStatus(Channel::S_WAIT);
+ nc->type = Channel::T_ALLOCATED;
+ nc->info.createdTime = sys->getTime();
+
+ LOG_CHANNEL("New channel created");
+
+ lock.off();
+ return nc;
+}
+// -----------------------------------
+int ChanMgr::pickHits(ChanHitSearch &chs)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->pickHits(chs))
+ {
+ chl->info.id;
+ return 1;
+ }
+ chl = chl->next;
+ }
+ return 0;
+}
+
+// -----------------------------------
+ChanHitList *ChanMgr::findHitList(ChanInfo &info)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.matchNameID(info))
+ return chl;
+
+ chl = chl->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::findHitListByID(GnuID &id)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.id.isSame(id))
+ return chl;
+ chl = chl->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+int ChanMgr::numHitLists()
+{
+ int num=0;
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ num++;
+ chl = chl->next;
+ }
+ return num;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::addHitList(ChanInfo &info)
+{
+ ChanHitList *chl = new ChanHitList();
+
+
+ chl->next = hitlist;
+ hitlist = chl;
+
+ chl->used = true;
+ chl->info = info;
+ chl->info.createdTime = sys->getTime();
+ peercastApp->addChannel(&chl->info);
+
+
+ return chl;
+}
+// -----------------------------------
+void ChanMgr::clearDeadHits(bool clearTrackers)
+{
+ unsigned int interval;
+
+ if (servMgr->isRoot)
+ interval = 1200; // mainly for old 0.119 clients
+ else
+ interval = hostUpdateInterval+120;
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = hitlist,*prev = NULL;
+ while (chl)
+ {
+ if (chl->isUsed())
+ {
+ if (chl->clearDeadHits(interval,clearTrackers) == 0)
+ {
+ if (!isBroadcasting(chl->info.id))
+ {
+ if (!chanMgr->findChannelByID(chl->info.id))
+ {
+ peercastApp->delChannel(&chl->info);
+
+ ChanHitList *next = chl->next;
+ if (prev)
+ prev->next = next;
+ else
+ hitlist = next;
+
+ delete chl;
+ chl = next;
+ continue;
+ }
+ }
+ }
+ }
+ prev = chl;
+ chl = chl->next;
+ }
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+bool ChanMgr::isBroadcasting(GnuID &id)
+{
+ Channel *ch = findChannelByID(id);
+ if (ch)
+ return ch->isBroadcasting();
+
+ return false;
+}
+// -----------------------------------
+bool ChanMgr::isBroadcasting()
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->isBroadcasting())
+ return true;
+
+ ch = ch->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+int ChanMgr::numChannels()
+{
+ int tot = 0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ tot++;
+ ch = ch->next;
+ }
+ return tot;
+}
+
+// -----------------------------------
+void ChanMgr::deadHit(ChanHit &hit)
+{
+ ChanHitList *chl = findHitListByID(hit.chanID);
+ if (chl)
+ chl->deadHit(hit);
+}
+// -----------------------------------
+void ChanMgr::delHit(ChanHit &hit)
+{
+ ChanHitList *chl = findHitListByID(hit.chanID);
+ if (chl)
+ chl->delHit(hit);
+}
+
+// -----------------------------------
+void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
+{
+ ChanHit hit;
+ hit.init();
+ hit.host = h;
+ hit.rhost[0] = h;
+ hit.rhost[1].init();
+ hit.tracker = tracker;
+ hit.recv = true;
+ hit.chanID = id;
+ addHit(hit);
+}
+// -----------------------------------
+ChanHit *ChanMgr::addHit(ChanHit &h)
+{
+ if (searchActive)
+ lastHit = sys->getTime();
+
+ ChanHitList *hl=NULL;
+
+ hl = findHitListByID(h.chanID);
+
+ if (!hl)
+ {
+ ChanInfo info;
+ info.id = h.chanID;
+ hl = addHitList(info);
+ }
+
+ if (hl)
+ {
+ return hl->addHit(h);
+ }else
+ return NULL;
+}
+
+// -----------------------------------
+class ChanFindInfo : public ThreadInfo
+{
+public:
+ ChanInfo info;
+ bool keep;
+};
+// -----------------------------------
+THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
+{
+ ChanFindInfo *cfi = (ChanFindInfo *)th;
+
+ ChanInfo info;
+ info = cfi->info;
+
+
+ Channel *ch = chanMgr->findChannelByNameID(info);
+
+ chanMgr->currFindAndPlayChannel = info.id;
+
+ if (!ch)
+ ch = chanMgr->findAndRelay(info);
+
+ if (ch)
+ {
+ // check that a different channel hasn`t be selected already.
+ if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
+ chanMgr->playChannel(ch->info);
+
+ if (cfi->keep)
+ ch->stayConnected = cfi->keep;
+ }
+
+ delete cfi;
+ return 0;
+}
+// -----------------------------------
+void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
+{
+ ChanFindInfo *cfi = new ChanFindInfo;
+ cfi->info = info;
+ cfi->keep = keep;
+ cfi->func = findAndPlayChannelProc;
+
+
+ sys->startThread(cfi);
+}
+// -----------------------------------
+void ChanMgr::playChannel(ChanInfo &info)
+{
+
+ char str[128],fname[256],idStr[128];
+
+ sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
+ info.id.toStr(idStr);
+
+ PlayList::TYPE type;
+
+
+ if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+ {
+ type = PlayList::T_ASX;
+ // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
+ // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);
+ }else
+ sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
+ }else if (info.contentType == ChanInfo::T_OGM)
+ {
+ type = PlayList::T_RAM;
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/play.ram",servMgr->modulePath);
+ }else
+ sprintf(fname,"%s/play.ram",peercastApp->getPath());
+
+ }else
+ {
+ type = PlayList::T_SCPLS;
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/play.pls",servMgr->modulePath);
+ }else
+ sprintf(fname,"%s/play.pls",peercastApp->getPath());
+ }
+
+
+ PlayList *pls = new PlayList(type,1);
+ pls->addChannel(str,info);
+
+
+ LOG_DEBUG("Writing %s",fname);
+ FileStream file;
+ file.openWriteReplace(fname);
+ pls->write(file);
+ file.close();
+
+
+ LOG_DEBUG("Executing: %s",fname);
+ sys->executeFile(fname);
+ delete pls;
+
+}
+
+// -----------------------------------
+ChanHitList::ChanHitList()
+{
+ info.init();
+ lastHitTime = 0;
+ used = false;
+ hit = NULL;
+}
+// -----------------------------------
+ChanHitList::~ChanHitList()
+{
+ chanMgr->hitlistlock.on();
+ while (hit)
+ hit = deleteHit(hit);
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+void ChanHit::pickNearestIP(Host &h)
+{
+ for(int i=0; i<2; i++)
+ {
+ if (h.classType() == rhost[i].classType())
+ {
+ host = rhost[i];
+ break;
+ }
+ }
+}
+
+// -----------------------------------
+void ChanHit::init()
+{
+ host.init();
+
+ rhost[0].init();
+ rhost[1].init();
+
+ next = NULL;
+
+ numListeners = 0;
+ numRelays = 0;
+
+ dead = tracker = firewalled = stable = yp = false;
+ recv = cin = direct = relay = true;
+ relayfull = chfull = ratefull = false;
+ direct = 0;
+ numHops = 0;
+ time = upTime = 0;
+ lastContact = 0;
+
+ version = 0;
+ version_vp = 0;
+
+ version_ex_prefix[0] = ' ';
+ version_ex_prefix[1] = ' ';
+ version_ex_number = 0;
+
+ status = 0;
+
+ sessionID.clear();
+ chanID.clear();
+
+
+ oldestPos = newestPos = 0;
+ uphost.init();
+ uphostHops = 0;
+}
+
+// -----------------------------------
+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)
+{
+ init();
+ firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
+ numListeners = numl;
+ numRelays = numr;
+ upTime = uptm;
+ stable = servMgr->totalStreams>0;
+ sessionID = servMgr->sessionID;
+ recv = connected;
+
+ direct = !servMgr->directFull();
+// relay = !servMgr->relaysFull();
+ cin = !servMgr->controlInFull();
+
+ relayfull = servMgr->relaysFull();
+ chfull = isFull;
+
+ Channel *c = chanMgr->channel;
+ int noRelay = 0;
+ unsigned int needRate = 0;
+ unsigned int allRate = 0;
+ while(c){
+ if (c->isPlaying()){
+ allRate += c->info.bitrate * c->localRelays();
+ if ((c != ch) && (c->localRelays() == 0)){
+ if(!isIndexTxt(c)) // for PCRaw (relay)
+ noRelay++;
+ needRate+=c->info.bitrate;
+ }
+ }
+ c = c->next;
+ }
+ int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+ if (ch->localRelays()){
+ if (noRelay > diff){
+ noRelay = diff;
+ }
+ } else {
+ noRelay = 0;
+ needRate = 0;
+ }
+
+ // for PCRaw (relay) start.
+ bool force_off = false;
+
+ if(isIndexTxt(ch))
+ force_off = true;
+ // for PCRaw (relay) end.
+
+// ratefull = servMgr->bitrateFull(needRate+bitrate);
+ ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
+
+ //relay = (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays);
+ relay = (!relayfull || force_off) && (!chfull) && (!ratefull)
+ && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off); // for PCRaw (relay) (force_off)
+
+/* if (relayfull){
+ LOG_DEBUG("Reject by relay full");
+ }
+ if (chfull){
+ LOG_DEBUG("Reject by channel full");
+ }
+ if (ratefull){
+ LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+ }*/
+
+ host = servMgr->serverHost;
+
+ version = PCP_CLIENT_VERSION;
+ version_vp = PCP_CLIENT_VERSION_VP;
+#ifdef VERSION_EX
+ strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
+ version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
+#else
+ version_ex_prefix[0] = ' ';
+ version_ex_prefix[1] = ' ';
+ version_ex_number = 0;
+#endif
+
+ status = ch->status;
+
+ rhost[0] = Host(host.ip,host.port);
+ rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
+
+ if (firewalled)
+ rhost[0].port = 0;
+
+ oldestPos = oldp;
+ newestPos = newp;
+
+ uphost.ip = ch->sourceHost.host.ip;
+ uphost.port = ch->sourceHost.host.port;
+ uphostHops = 1;
+}
+
+// -----------------------------------
+void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
+{
+ bool addChan=chanID.isSet();
+ bool uphostdata=(uphost.ip != 0);
+
+ int fl1 = 0;
+ if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
+ if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
+ if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
+ if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
+ if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
+ if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
+
+ atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0));
+
+ if (addChan)
+ atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
+ atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
+ atom.writeInt(PCP_HOST_IP,rhost[0].ip);
+ atom.writeShort(PCP_HOST_PORT,rhost[0].port);
+ atom.writeInt(PCP_HOST_IP,rhost[1].ip);
+ atom.writeShort(PCP_HOST_PORT,rhost[1].port);
+ atom.writeInt(PCP_HOST_NUML,numListeners);
+ atom.writeInt(PCP_HOST_NUMR,numRelays);
+ atom.writeInt(PCP_HOST_UPTIME,upTime);
+ atom.writeInt(PCP_HOST_VERSION,version);
+ atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
+ if (version_ex_number){
+ atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
+ atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
+ }
+ atom.writeChar(PCP_HOST_FLAGS1,fl1);
+ atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
+ atom.writeInt(PCP_HOST_NEWPOS,newestPos);
+ if (uphostdata){
+ atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
+ atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
+ atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
+ }
+}
+// -----------------------------------
+bool ChanHit::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "rhost0")
+ {
+ if (servMgr->enableGetName) //JP-EX s
+ {
+ char buf2[256];
+ if (firewalled)
+ {
+ if (numRelays==0)
+ strcpy(buf,"<font color=red>");
+ else
+ strcpy(buf,"<font color=orange>");
+ }
+ else {
+ if (!relay){
+ if (numRelays==0){
+ strcpy(buf,"<font color=purple>");
+ } else {
+ strcpy(buf,"<font color=blue>");
+ }
+ } else {
+ strcpy(buf,"<font color=green>");
+ }
+ }
+
+ rhost[0].toStr(buf2);
+ strcat(buf,buf2);
+
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,rhost[0].ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ strcat(buf,"</font>");
+ } //JP-EX e
+ else
+ rhost[0].toStr(buf);
+ }
+ else if (var == "rhost1")
+ rhost[1].toStr(buf);
+ else if (var == "numHops")
+ sprintf(buf,"%d",numHops);
+ else if (var == "numListeners")
+ sprintf(buf,"%d",numListeners);
+ else if (var == "numRelays")
+ sprintf(buf,"%d",numRelays);
+ else if (var == "uptime")
+ {
+ String timeStr;
+ timeStr.setFromStopwatch(upTime);
+ strcpy(buf,timeStr.cstr());
+ }else if (var == "update")
+ {
+ String timeStr;
+ if (timeStr)
+ timeStr.setFromStopwatch(sys->getTime()-time);
+ else
+ timeStr.set("-");
+ strcpy(buf,timeStr.cstr());
+ }else if (var == "isFirewalled"){
+ sprintf(buf,"%d",firewalled?1:0);
+ }else if (var == "version"){
+ sprintf(buf,"%d",version);
+ }else if (var == "agent"){
+ if (version){
+ if (version_ex_number){
+ sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
+ } else if (version_vp){
+ sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
+ } else {
+ sprintf(buf,"v0.%d", version);
+ }
+ } else {
+ strcpy(buf, "0");
+ }
+ }
+ else if (var == "check")
+ {
+ char buf2[256];
+ strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
+ rhost[0].IPtoStr(buf2);
+ strcat(buf, buf2);
+ strcat(buf, "')\">_</a>");
+ }
+ else if (var == "uphost") // tree
+ uphost.toStr(buf);
+ else if (var == "uphostHops") // tree
+ sprintf(buf,"%d",uphostHops);
+ else if (var == "canRelay") // tree
+ sprintf(buf, "%d",relay);
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+int ChanHitList::getTotalListeners()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ cnt+=h->numListeners;
+ h=h->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalRelays()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ cnt+=h->numRelays;
+ h=h->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalFirewalled()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ if (h->firewalled)
+ cnt++;
+ h=h->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
+{
+ return 0;
+}
+
+void ChanHitList::clearHits(bool flg)
+{
+ ChanHit *c = hit, *prev = NULL;
+
+ while(c){
+ if (flg || (c->numHops != 0)){
+ ChanHit *next = c->next;
+ if (prev)
+ prev->next = next;
+ else
+ hit = next;
+
+ delete c;
+ c = next;
+ } else {
+ prev = c;
+ c = c->next;
+ }
+ }
+}
+
+// -----------------------------------
+ChanHit *ChanHitList::deleteHit(ChanHit *ch)
+{
+ ChanHit *c = hit,*prev=NULL;
+ while (c)
+ {
+ if (c == ch)
+ {
+ ChanHit *next = c->next;
+ if (prev)
+ prev->next = next;
+ else
+ hit = next;
+
+ delete c;
+
+ return next;
+ }
+ prev=c;
+ c=c->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+ChanHit *ChanHitList::addHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ char uphostStr[64];
+ h.uphost.toStr(uphostStr);
+ if (h.uphost.ip){
+ LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
+ } else {
+ LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
+ }
+
+ // dont add our own hits
+ if (servMgr->sessionID.isSame(h.sessionID))
+ return NULL;
+
+
+ lastHitTime = sys->getTime();
+ h.time = lastHitTime;
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
+ if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
+ {
+ if (!ch->dead)
+ {
+ if (ch->numHops > 0 && h.numHops == 0)
+ // downstream hit recieved as RelayHost
+ return ch;
+ ChanHit *next = ch->next;
+ *ch = h;
+ ch->next = next;
+ return ch;
+ }
+ }
+ ch=ch->next;
+ }
+
+ // clear hits with same session ID (IP may have changed)
+ if (h.sessionID.isSet())
+ {
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->sessionID.isSame(h.sessionID))
+ {
+ ch = deleteHit(ch);
+ continue;
+ }
+ ch=ch->next;
+ }
+ }
+
+
+ // else add new hit
+ {
+ ChanHit *ch = new ChanHit();
+ *ch = h;
+ ch->chanID = info.id;
+ ch->next = hit;
+ hit = ch;
+ return ch;
+ }
+
+ return NULL;
+}
+
+
+// -----------------------------------
+int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
+{
+ int cnt=0;
+ unsigned int ctime = sys->getTime();
+
+// LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ {
+ if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
+ {
+// ch = deleteHit(ch);
+
+ if (ch->firewalled){
+// LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
+ if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
+ ch = deleteHit(ch);
+ } else {
+ ch->numHops = 0;
+ ch->numListeners = 0;
+ ch = ch->next;
+ }
+ } else {
+ ch = deleteHit(ch);
+ }
+
+ continue;
+ }else
+ cnt++;
+ }
+ ch = ch->next;
+ }
+// LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+ return cnt;
+}
+
+
+// -----------------------------------
+void ChanHitList::deadHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+ {
+ ch->dead = true;
+ }
+ ch = ch->next;
+ }
+}
+// -----------------------------------
+void ChanHitList::delHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+ {
+ ch=deleteHit(ch);
+ continue;
+ }
+ ch = ch->next;
+ }
+}
+// -----------------------------------
+int ChanHitList::numHits()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead && ch->numHops)
+ cnt++;
+ ch = ch->next;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numListeners()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead && ch->numHops)
+ cnt += ch->numListeners;
+ ch=ch->next;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numRelays()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ cnt += ch->numRelays;
+ ch=ch->next;
+ }
+
+ return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::numTrackers()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if ((ch->host.ip && !ch->dead) && (ch->tracker))
+ cnt++;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numFirewalled()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ cnt += ch->firewalled?1:0;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::closestHit()
+{
+ unsigned int hop=10000;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->numHops < hop)
+ hop = ch->numHops;
+ ch=ch->next;
+ }
+
+ return hop;
+}
+// -----------------------------------
+int ChanHitList::furthestHit()
+{
+ unsigned int hop=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->numHops > hop)
+ hop = ch->numHops;
+ ch=ch->next;
+ }
+
+ return hop;
+}
+// -----------------------------------
+unsigned int ChanHitList::newestHit()
+{
+ unsigned int time=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->time > time)
+ time = ch->time;
+ ch=ch->next;
+ }
+
+ return time;
+}
+// -----------------------------------
+int ChanHitList::pickHits(ChanHitSearch &chs)
+{
+ ChanHit best,*bestP=NULL;
+ best.init();
+ best.numHops = 255;
+ best.time = 0;
+
+ unsigned int ctime = sys->getTime();
+
+ ChanHit *c = hit;
+ while (c)
+ {
+ if (c->host.ip && !c->dead)
+ {
+ if (!chs.excludeID.isSame(c->sessionID))
+ if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
+ if ((c->numHops<=best.numHops)) // (c->time>=best.time))
+ if (c->relay || (!c->relay && chs.useBusyRelays))
+ if (c->cin || (!c->cin && chs.useBusyControls))
+ {
+
+ if (chs.trackersOnly && c->tracker)
+ {
+ if (chs.matchHost.ip)
+ {
+ if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[1]; // use lan ip
+ }
+ }else if (c->firewalled == chs.useFirewalled)
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[0]; // use wan ip
+ }
+ }else if (!chs.trackersOnly && !c->tracker)
+ {
+ if (chs.matchHost.ip)
+ {
+ if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[1]; // use lan ip
+ }
+ }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[0]; // use wan ip
+ }
+ }
+ }
+ }
+ c=c->next;
+ }
+
+ if (bestP)
+ {
+ if (chs.numResults < ChanHitSearch::MAX_RESULTS)
+ {
+ if (chs.waitDelay)
+ bestP->lastContact = ctime;
+ chs.best[chs.numResults++] = best;
+ return 1;
+ }
+
+ }
+
+ return 0;
+}
+
+
+// -----------------------------------
+int ChanHitList::pickSourceHits(ChanHitSearch &chs)
+{
+ if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
+ return 0;
+}
+
+
+// -----------------------------------
+const char *ChanInfo::getTypeStr(TYPE t)
+{
+ switch (t)
+ {
+ case T_RAW: return "RAW";
+
+ case T_MP3: return "MP3";
+ case T_OGG: return "OGG";
+ case T_OGM: return "OGM";
+ case T_WMA: return "WMA";
+
+ case T_MOV: return "MOV";
+ case T_MPG: return "MPG";
+ case T_NSV: return "NSV";
+ case T_WMV: return "WMV";
+
+ case T_PLS: return "PLS";
+ case T_ASX: return "ASX";
+
+ default: return "UNKNOWN";
+ }
+}
+// -----------------------------------
+const char *ChanInfo::getProtocolStr(PROTOCOL t)
+{
+ switch (t)
+ {
+ case SP_PEERCAST: return "PEERCAST";
+ case SP_HTTP: return "HTTP";
+ case SP_FILE: return "FILE";
+ case SP_MMS: return "MMS";
+ case SP_PCP: return "PCP";
+ default: return "UNKNOWN";
+ }
+}
+// -----------------------------------
+ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
+{
+ if (stricmp(str,"PEERCAST")==0)
+ return SP_PEERCAST;
+ else if (stricmp(str,"HTTP")==0)
+ return SP_HTTP;
+ else if (stricmp(str,"FILE")==0)
+ return SP_FILE;
+ else if (stricmp(str,"MMS")==0)
+ return SP_MMS;
+ else if (stricmp(str,"PCP")==0)
+ return SP_PCP;
+ else
+ return SP_UNKNOWN;
+}
+
+// -----------------------------------
+const char *ChanInfo::getTypeExt(TYPE t)
+{
+ switch(t)
+ {
+ case ChanInfo::T_OGM:
+ case ChanInfo::T_OGG:
+ return ".ogg";
+ case ChanInfo::T_MP3:
+ return ".mp3";
+ case ChanInfo::T_MOV:
+ return ".mov";
+ case ChanInfo::T_NSV:
+ return ".nsv";
+ case ChanInfo::T_WMV:
+ return ".wmv";
+ case ChanInfo::T_WMA:
+ return ".wma";
+ default:
+ return "";
+ }
+}
+// -----------------------------------
+ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
+{
+ if (stricmp(str,"MP3")==0)
+ return T_MP3;
+ else if (stricmp(str,"OGG")==0)
+ return T_OGG;
+ else if (stricmp(str,"OGM")==0)
+ return T_OGM;
+ else if (stricmp(str,"RAW")==0)
+ return T_RAW;
+ else if (stricmp(str,"NSV")==0)
+ return T_NSV;
+ else if (stricmp(str,"WMA")==0)
+ return T_WMA;
+ else if (stricmp(str,"WMV")==0)
+ return T_WMV;
+ else if (stricmp(str,"PLS")==0)
+ return T_PLS;
+ else if (stricmp(str,"M3U")==0)
+ return T_PLS;
+ else if (stricmp(str,"ASX")==0)
+ return T_ASX;
+ else
+ return T_UNKNOWN;
+}
+// -----------------------------------
+bool ChanInfo::matchNameID(ChanInfo &inf)
+{
+ if (inf.id.isSet())
+ if (id.isSame(inf.id))
+ return true;
+
+ if (!inf.name.isEmpty())
+ if (name.contains(inf.name))
+ return true;
+
+ return false;
+}
+// -----------------------------------
+bool ChanInfo::match(ChanInfo &inf)
+{
+ bool matchAny=true;
+
+ if (inf.status != S_UNKNOWN)
+ {
+ if (status != inf.status)
+ return false;
+ }
+
+ if (inf.bitrate != 0)
+ {
+ if (bitrate == inf.bitrate)
+ return true;
+ matchAny = false;
+ }
+
+ if (inf.id.isSet())
+ {
+ if (id.isSame(inf.id))
+ return true;
+ matchAny = false;
+ }
+
+ if (inf.contentType != T_UNKNOWN)
+ {
+ if (contentType == inf.contentType)
+ return true;
+ matchAny = false;
+ }
+
+ if (!inf.name.isEmpty())
+ {
+ if (name.contains(inf.name))
+ return true;
+ matchAny = false;
+ }
+
+ if (!inf.genre.isEmpty())
+ {
+ if (genre.contains(inf.genre))
+ return true;
+ matchAny = false;
+ }
+
+ return matchAny;
+}
+// -----------------------------------
+bool TrackInfo::update(TrackInfo &inf)
+{
+ bool changed = false;
+
+ if (!contact.isSame(inf.contact))
+ {
+ contact = inf.contact;
+ changed = true;
+ }
+
+ if (!title.isSame(inf.title))
+ {
+ title = inf.title;
+ changed = true;
+ }
+
+ if (!artist.isSame(inf.artist))
+ {
+ artist = inf.artist;
+ changed = true;
+ }
+
+ if (!album.isSame(inf.album))
+ {
+ album = inf.album;
+ changed = true;
+ }
+
+ if (!genre.isSame(inf.genre))
+ {
+ genre = inf.genre;
+ changed = true;
+ }
+
+
+ return changed;
+}
+
+
+// -----------------------------------
+bool ChanInfo::update(ChanInfo &info)
+{
+ bool changed = false;
+
+
+
+ // check valid id
+ if (!info.id.isSet())
+ return false;
+
+ // only update from chaninfo that has full name etc..
+ if (info.name.isEmpty())
+ return false;
+
+ // check valid broadcaster key
+ if (bcID.isSet())
+ {
+ if (!bcID.isSame(info.bcID))
+ {
+ LOG_ERROR("ChanInfo BC key not valid");
+ return false;
+ }
+ }else
+ {
+ bcID = info.bcID;
+ }
+
+
+
+ if (bitrate != info.bitrate)
+ {
+ bitrate = info.bitrate;
+ changed = true;
+ }
+
+ if (contentType != info.contentType)
+ {
+ contentType = info.contentType;
+ changed = true;
+ }
+
+ if (!desc.isSame(info.desc)) //JP-EX
+ {
+ desc = info.desc;
+ changed = true;
+ }
+
+ if (!name.isSame(info.name))
+ {
+ name = info.name;
+ changed = true;
+ }
+
+ if (!comment.isSame(info.comment))
+ {
+ comment = info.comment;
+ changed = true;
+ }
+
+ if (!genre.isSame(info.genre))
+ {
+ genre = info.genre;
+ changed = true;
+ }
+
+ if (!url.isSame(info.url))
+ {
+ url = info.url;
+ changed = true;
+ }
+
+ if (track.update(info.track))
+ changed = true;
+
+
+ return changed;
+}
+// -----------------------------------
+void ChanInfo::initNameID(const char *n)
+{
+ init();
+ id.fromStr(n);
+ if (!id.isSet())
+ name.set(n);
+}
+
+// -----------------------------------
+void ChanInfo::init()
+{
+ status = S_UNKNOWN;
+ name.clear();
+ bitrate = 0;
+ contentType = T_UNKNOWN;
+ srcProtocol = SP_UNKNOWN;
+ id.clear();
+ url.clear();
+ genre.clear();
+ comment.clear();
+ track.clear();
+ lastPlayStart = 0;
+ lastPlayEnd = 0;
+ numSkips = 0;
+ bcID.clear();
+ createdTime = 0;
+}
+// -----------------------------------
+void ChanInfo::readTrackXML(XML::Node *n)
+{
+ track.clear();
+ readXMLString(track.title,n,"title");
+ readXMLString(track.contact,n,"contact");
+ readXMLString(track.artist,n,"artist");
+ readXMLString(track.album,n,"album");
+ readXMLString(track.genre,n,"genre");
+}
+// -----------------------------------
+unsigned int ChanInfo::getUptime()
+{
+ // calculate uptime and cap if requested by settings.
+ unsigned int upt;
+ upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
+ if (chanMgr->maxUptime)
+ if (upt > chanMgr->maxUptime)
+ upt = chanMgr->maxUptime;
+ return upt;
+}
+// -----------------------------------
+unsigned int ChanInfo::getAge()
+{
+ return sys->getTime()-createdTime;
+}
+
+// ------------------------------------------
+void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
+{
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+ if (id == PCP_CHAN_TRACK_TITLE)
+ {
+ atom.readString(track.title.data,sizeof(track.title.data),d);
+ }else if (id == PCP_CHAN_TRACK_CREATOR)
+ {
+ atom.readString(track.artist.data,sizeof(track.artist.data),d);
+ }else if (id == PCP_CHAN_TRACK_URL)
+ {
+ atom.readString(track.contact.data,sizeof(track.contact.data),d);
+ }else if (id == PCP_CHAN_TRACK_ALBUM)
+ {
+ atom.readString(track.album.data,sizeof(track.album.data),d);
+ }else
+ atom.skip(c,d);
+ }
+}
+// ------------------------------------------
+void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
+{
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+ if (id == PCP_CHAN_INFO_NAME)
+ {
+ atom.readString(name.data,sizeof(name.data),d);
+ }else if (id == PCP_CHAN_INFO_BITRATE)
+ {
+ bitrate = atom.readInt();
+ }else if (id == PCP_CHAN_INFO_GENRE)
+ {
+ atom.readString(genre.data,sizeof(genre.data),d);
+ }else if (id == PCP_CHAN_INFO_URL)
+ {
+ atom.readString(url.data,sizeof(url.data),d);
+ }else if (id == PCP_CHAN_INFO_DESC)
+ {
+ atom.readString(desc.data,sizeof(desc.data),d);
+ }else if (id == PCP_CHAN_INFO_COMMENT)
+ {
+ atom.readString(comment.data,sizeof(comment.data),d);
+ }else if (id == PCP_CHAN_INFO_TYPE)
+ {
+ char type[16];
+ atom.readString(type,sizeof(type),d);
+ contentType = ChanInfo::getTypeFromStr(type);
+ }else
+ atom.skip(c,d);
+ }
+}
+
+// -----------------------------------
+void ChanInfo::writeInfoAtoms(AtomStream &atom)
+{
+ atom.writeParent(PCP_CHAN_INFO,7);
+ atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
+ atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
+ atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
+ atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
+ atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
+ atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
+ atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));
+
+}
+// -----------------------------------
+void ChanInfo::writeTrackAtoms(AtomStream &atom)
+{
+ atom.writeParent(PCP_CHAN_TRACK,4);
+ atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
+ atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
+ atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
+ atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
+}
+
+
+// -----------------------------------
+XML::Node *ChanInfo::createChannelXML()
+{
+ char idStr[64];
+
+ String nameUNI = name;
+ nameUNI.convertTo(String::T_UNICODESAFE);
+
+ String urlUNI = url;
+ urlUNI.convertTo(String::T_UNICODESAFE);
+
+ String genreUNI = genre;
+ genreUNI.convertTo(String::T_UNICODESAFE);
+
+ String descUNI = desc;
+ descUNI.convertTo(String::T_UNICODESAFE);
+
+ String commentUNI;
+ commentUNI = comment;
+ commentUNI.convertTo(String::T_UNICODESAFE);
+
+
+ id.toStr(idStr);
+
+
+ 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\"",
+ nameUNI.cstr(),
+ idStr,
+ bitrate,
+ getTypeStr(contentType),
+ genreUNI.cstr(),
+ descUNI.cstr(),
+ urlUNI.cstr(),
+ getUptime(),
+ commentUNI.cstr(),
+ numSkips,
+ getAge(),
+ bcID.getFlags()
+ );
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createQueryXML()
+{
+ char buf[512];
+ char idStr[64];
+
+
+ String nameHTML = name;
+ nameHTML.convertTo(String::T_HTML);
+ String genreHTML = genre;
+ genreHTML.convertTo(String::T_HTML);
+
+ buf[0]=0;
+ if (!nameHTML.isEmpty())
+ {
+ strcat(buf," name=\"");
+ strcat(buf,nameHTML.cstr());
+ strcat(buf,"\"");
+ }
+
+ if (!genreHTML.isEmpty())
+ {
+ strcat(buf," genre=\"");
+ strcat(buf,genreHTML.cstr());
+ strcat(buf,"\"");
+ }
+
+ if (id.isSet())
+ {
+ id.toStr(idStr);
+ strcat(buf," id=\"");
+ strcat(buf,idStr);
+ strcat(buf,"\"");
+ }
+
+
+ return new XML::Node("channel %s",buf);
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createRelayChannelXML()
+{
+ char idStr[64];
+
+ id.toStr(idStr);
+
+
+ return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
+ idStr,
+ getUptime(),
+ numSkips,
+ getAge()
+ );
+}// -----------------------------------
+XML::Node *ChanInfo::createTrackXML()
+{
+ String titleUNI = track.title;
+ titleUNI.convertTo(String::T_UNICODESAFE);
+
+ String artistUNI = track.artist;
+ artistUNI.convertTo(String::T_UNICODESAFE);
+
+ String albumUNI = track.album;
+ albumUNI.convertTo(String::T_UNICODESAFE);
+
+ String genreUNI = track.genre;
+ genreUNI.convertTo(String::T_UNICODESAFE);
+
+ String contactUNI = track.contact;
+ contactUNI.convertTo(String::T_UNICODESAFE);
+
+
+
+ return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
+ titleUNI.cstr(),
+ artistUNI.cstr(),
+ albumUNI.cstr(),
+ genreUNI.cstr(),
+ contactUNI.cstr()
+ );
+}
+
+// -----------------------------------
+void ChanInfo::init(XML::Node *n)
+{
+ init();
+
+ updateFromXML(n);
+}
+// -----------------------------------
+void ChanInfo::updateFromXML(XML::Node *n)
+{
+ String typeStr,idStr;
+
+ readXMLString(name,n,"name");
+ readXMLString(genre,n,"genre");
+ readXMLString(url,n,"url");
+ readXMLString(desc,n,"desc");
+
+
+ int br = n->findAttrInt("bitrate");
+ if (br)
+ bitrate = br;
+
+ readXMLString(typeStr,n,"type");
+ if (!typeStr.isEmpty())
+ contentType = getTypeFromStr(typeStr.cstr());
+
+
+ readXMLString(idStr,n,"id");
+ if (!idStr.isEmpty())
+ id.fromStr(idStr.cstr());
+
+ readXMLString(comment,n,"comment");
+
+ XML::Node *tn = n->findNode("track");
+ if (tn)
+ readTrackXML(tn);
+
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
+{
+ init();
+
+ name.set(n);
+ bitrate = br;
+ contentType = tp;
+ id = cid;
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *fn)
+{
+ init();
+
+ if (fn)
+ name.set(fn);
+}
+// -----------------------------------
+void PlayList::readASX(Stream &in)
+{
+ LOG_DEBUG("Reading ASX");
+ XML xml;
+
+ try
+ {
+ xml.read(in);
+ }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
+
+ if (xml.root)
+ {
+ XML::Node *n = xml.root->child;
+ while (n)
+ {
+ if (stricmp("entry",n->getName())==0)
+ {
+ XML::Node *rf = n->findNode("ref");
+ if (rf)
+ {
+ char *hr = rf->findAttr("href");
+ if (hr)
+ {
+ addURL(hr,"");
+ //LOG("asx url %s",hr);
+ }
+
+ }
+ }
+ n=n->sibling;
+ }
+ }
+}
+// -----------------------------------
+void PlayList::readSCPLS(Stream &in)
+{
+ char tmp[256];
+ while (in.readLine(tmp,sizeof(tmp)))
+ {
+ if (strnicmp(tmp,"file",4)==0)
+ {
+ char *p = strstr(tmp,"=");
+ if (p)
+ addURL(p+1,"");
+ }
+ }
+}
+// -----------------------------------
+void PlayList::readPLS(Stream &in)
+{
+ char tmp[256];
+ while (in.readLine(tmp,sizeof(tmp)))
+ {
+ if (tmp[0] != '#')
+ addURL(tmp,"");
+ }
+}
+// -----------------------------------
+void PlayList::writeSCPLS(Stream &out)
+{
+ out.writeLine("[playlist]");
+ out.writeLine("");
+ out.writeLineF("NumberOfEntries=%d",numURLs);
+
+ for(int i=0; i<numURLs; i++)
+ {
+ out.writeLineF("File%d=%s",i+1,urls[i].cstr());
+ out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
+ out.writeLineF("Length%d=-1",i+1);
+ }
+ out.writeLine("Version=2");
+}
+// -----------------------------------
+void PlayList::writePLS(Stream &out)
+{
+ for(int i=0; i<numURLs; i++)
+ out.writeLineF("%s",urls[i].cstr());
+}
+// -----------------------------------
+void PlayList::writeRAM(Stream &out)
+{
+ for(int i=0; i<numURLs; i++)
+ out.writeLineF("%s",urls[i].cstr());
+}
+
+// -----------------------------------
+void PlayList::writeASX(Stream &out)
+{
+ out.writeLine("<ASX Version=\"3.0\">");
+ for(int i=0; i<numURLs; i++)
+ {
+ out.writeLine("<ENTRY>");
+ out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
+ out.writeLine("</ENTRY>");
+ }
+ out.writeLine("</ASX>");
+}
+
+
+// -----------------------------------
+void PlayList::addChannel(const char *path, ChanInfo &info)
+{
+ String url;
+
+ char idStr[64];
+
+ info.id.toStr(idStr);
+ char *nid = info.id.isSet()?idStr:info.name.cstr();
+
+ sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
+ addURL(url.cstr(),info.name);
+}
+
+// -----------------------------------
+void ChanHitSearch::init()
+{
+ matchHost.init();
+ waitDelay = 0;
+ useFirewalled = false;
+ trackersOnly = false;
+ useBusyRelays = true;
+ useBusyControls = true;
+ excludeID.clear();
+ numResults = 0;
+
+ //seed = sys->getTime();
+ //srand(seed);
+}
+
+int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
+{
+ int cnt = 0;
+ int loop = 1;
+ int index = 0;
+ int prob;
+ int rnd;
+ static int base = 0x400;
+ ChanHit tmpHit[MAX_RESULTS];
+ static WLock seqLock;
+ static unsigned int riSequence = 0;
+
+ //srand(seed);
+ //seed += 11;
+
+ unsigned int seq;
+ seqLock.on();
+ seq = riSequence++;
+ riSequence &= 0xffffff;
+ seqLock.off();
+
+ ChanHit *hit = chl->hit;
+
+ while(hit){
+ if (hit->host.ip && !hit->dead){
+ if (
+ (!exID.isSame(hit->sessionID))
+// && (hit->relay)
+ && (!hit->tracker)
+ && (!hit->firewalled)
+ && (hit->numHops != 0)
+ ){
+ if ( (hit->rhost[0].ip == host1.ip)
+ && hit->rhost[1].isValid()
+ && (host2.ip != hit->rhost[1].ip)
+ ){
+ best[0] = *hit;
+ best[0].host = hit->rhost[1];
+ index++;
+ }
+ if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
+ best[0] = *hit;
+ best[0].host = hit->rhost[1];
+ index++;
+ }
+
+ loop = (index / MAX_RESULTS) + 1;
+ //prob = (float)1 / (float)loop;
+ prob = base / loop;
+ //rnd = (float)rand() / (float)RAND_MAX;
+ rnd = rand() % base;
+ if (hit->numHops == 1){
+ if (tmpHit[index % MAX_RESULTS].numHops == 1){
+ if (rnd < prob){
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ } else {
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ } else {
+ if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ }
+
+// char tmp[50];
+// hit->host.toStr(tmp);
+// LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
+ }
+ }
+ hit = hit->next;
+ }
+
+ if (index > MAX_RESULTS){
+ cnt = MAX_RESULTS;
+ } else {
+ cnt = index;
+ }
+
+/* int use[MAX_RESULTS];
+ memset(use, 0, sizeof(use));
+ int i;
+ for (i = 0; i < cnt; i++){
+ use[i] = -1;
+ }
+ int r;
+ for (i = 0; i < cnt; i++){
+ do {
+ r = rand();
+// LOG_DEBUG("%d",r);
+ r = r % cnt;
+ if (use[r] == -1){
+ use[r] = i;
+ break;
+ }
+ } while(1);
+ }
+ for (i = 0; i < cnt; i++){
+// LOG_DEBUG("%d", use[i]);
+ best[use[i]] = tmpHit[i];
+ }*/
+
+ int use[MAX_RESULTS];
+ int i;
+ for (i = 0; i < cnt; i++) {
+ use[i] = (i + seq) % cnt;
+ }
+
+ for (i = 0; i < cnt; i++){
+// LOG_DEBUG("%d", use[i]);
+ best[use[i]] = tmpHit[i];
+ }
+// for (i = 0; i < cnt; i++){
+// char tmp[50];
+// best[i].host.toStr(tmp);
+// LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);
+// }
+
+ return cnt;
+}
--- /dev/null
+// ------------------------------------------------
+// File : channel.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CHANNEL_H
+#define _CHANNEL_H
+
+#include "sys.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "asf.h"
+#include "cstream.h"
+
+class AtomStream;
+class ChanHitSearch;
+
+// --------------------------------------------------
+struct MP3Header
+{
+ int lay;
+ int version;
+ int error_protection;
+ int bitrate_index;
+ int sampling_frequency;
+ int padding;
+ int extension;
+ int mode;
+ int mode_ext;
+ int copyright;
+ int original;
+ int emphasis;
+ int stereo;
+};
+
+// ----------------------------------
+class TrackInfo
+{
+public:
+ void clear()
+ {
+ contact.clear();
+ title.clear();
+ artist.clear();
+ album.clear();
+ genre.clear();
+ }
+
+ void convertTo(String::TYPE t)
+ {
+ contact.convertTo(t);
+ title.convertTo(t);
+ artist.convertTo(t);
+ album.convertTo(t);
+ genre.convertTo(t);
+ }
+
+ bool update(TrackInfo &);
+
+ ::String contact,title,artist,album,genre;
+};
+
+
+
+// ----------------------------------
+class ChanInfo
+{
+public:
+ enum TYPE
+ {
+ T_UNKNOWN,
+
+ T_RAW,
+ T_MP3,
+ T_OGG,
+ T_OGM,
+ T_MOV,
+ T_MPG,
+ T_NSV,
+
+ T_WMA,
+ T_WMV,
+
+ T_PLS,
+ T_ASX
+ };
+
+
+ enum PROTOCOL
+ {
+ SP_UNKNOWN,
+ SP_PEERCAST,
+ SP_HTTP,
+ SP_FILE,
+ SP_MMS,
+ SP_PCP
+ };
+
+
+ enum STATUS
+ {
+ S_UNKNOWN,
+ S_PLAY
+ };
+
+ ChanInfo() {init();}
+
+ void init();
+ void init(const char *);
+ void init(const char *, GnuID &, TYPE, int);
+ void init(XML::Node *);
+ void initNameID(const char *);
+
+ void updateFromXML(XML::Node *);
+
+ void readTrackXML(XML::Node *);
+ void readServentXML(XML::Node *);
+ bool update(ChanInfo &);
+ XML::Node *createQueryXML();
+ XML::Node *createChannelXML();
+ XML::Node *createRelayChannelXML();
+ XML::Node *createTrackXML();
+ bool match(XML::Node *);
+ bool match(ChanInfo &);
+ bool matchNameID(ChanInfo &);
+
+ void writeInfoAtoms(AtomStream &atom);
+ void writeTrackAtoms(AtomStream &atom);
+
+ void readInfoAtoms(AtomStream &,int);
+ void readTrackAtoms(AtomStream &,int);
+
+ unsigned int getUptime();
+ unsigned int getAge();
+ bool isActive() {return id.isSet();}
+ bool isPrivate() {return bcID.getFlags() & 1;}
+ static const char *getTypeStr(TYPE);
+ static const char *getProtocolStr(PROTOCOL);
+ static const char *getTypeExt(TYPE);
+ static TYPE getTypeFromStr(const char *str);
+ static PROTOCOL getProtocolFromStr(const char *str);
+
+ ::String name;
+ GnuID id,bcID;
+ int bitrate;
+ TYPE contentType;
+ PROTOCOL srcProtocol;
+ unsigned int lastPlayStart,lastPlayEnd;
+ unsigned int numSkips;
+ unsigned int createdTime;
+
+ STATUS status;
+
+ TrackInfo track;
+ ::String desc,genre,url,comment;
+
+};
+
+
+// ----------------------------------
+class ChanHit
+{
+public:
+ void init();
+ void initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int);
+ XML::Node *createXML();
+
+ void writeAtoms(AtomStream &,GnuID &);
+ bool writeVariable(Stream &, const String &);
+
+ void pickNearestIP(Host &);
+
+ Host host;
+ Host rhost[2];
+ unsigned int numListeners,numRelays,numHops;
+ unsigned int time,upTime,lastContact;
+ unsigned int hitID;
+ GnuID sessionID,chanID;
+ unsigned int version;
+ unsigned int version_vp;
+
+ bool firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1;
+ bool relayfull:1,chfull:1,ratefull:1;
+
+ ChanHit *next;
+
+ int status;
+ int servent_id;
+
+ unsigned int oldestPos,newestPos;
+ Host uphost;
+ unsigned int uphostHops;
+
+ char version_ex_prefix[2];
+ unsigned int version_ex_number;
+};
+// ----------------------------------
+class ChanHitList
+{
+public:
+ ChanHitList();
+ ~ChanHitList();
+
+ int contactTrackers(bool,int,int,int);
+
+ ChanHit *addHit(ChanHit &);
+ void delHit(ChanHit &);
+ void deadHit(ChanHit &);
+ void clearHits(bool);
+ int numHits();
+ int numListeners();
+ int numRelays();
+ int numFirewalled();
+ int numTrackers();
+ int closestHit();
+ int furthestHit();
+ unsigned int newestHit();
+
+ int pickHits(ChanHitSearch &);
+ int pickSourceHits(ChanHitSearch &);
+
+ bool isUsed() {return used;}
+ int clearDeadHits(unsigned int,bool);
+ XML::Node *createXML(bool addHits = true);
+
+ ChanHit *deleteHit(ChanHit *);
+
+ int getTotalListeners();
+ int getTotalRelays();
+ int getTotalFirewalled();
+
+ bool used;
+ ChanInfo info;
+ ChanHit *hit;
+ unsigned int lastHitTime;
+ ChanHitList *next;
+
+
+};
+// ----------------------------------
+class ChanHitSearch
+{
+public:
+ enum
+ {
+ MAX_RESULTS = 8
+ };
+
+ ChanHitSearch() { init(); }
+ void init();
+
+ ChanHit best[MAX_RESULTS];
+ Host matchHost;
+ unsigned int waitDelay;
+ bool useFirewalled;
+ bool trackersOnly;
+ bool useBusyRelays,useBusyControls;
+ GnuID excludeID;
+ int numResults;
+ unsigned int seed;
+
+ int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl);
+};
+
+// ----------------------------------
+class ChanMeta
+{
+public:
+ enum {
+ MAX_DATALEN = 65536
+ };
+
+ void init()
+ {
+ len = 0;
+ cnt = 0;
+ startPos = 0;
+ }
+
+ void fromXML(XML &);
+ void fromMem(void *,int);
+ void addMem(void *,int);
+
+ unsigned int len,cnt,startPos;
+ char data[MAX_DATALEN];
+};
+
+
+
+// ------------------------------------------
+class RawStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+};
+
+// ------------------------------------------
+class PeercastStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+// ------------------------------------------
+class ChannelSource
+{
+public:
+ virtual ~ChannelSource() {}
+ virtual void stream(Channel *) = 0;
+
+ virtual int getSourceRate() {return 0;}
+
+};
+// ------------------------------------------
+class PeercastSource : public ChannelSource
+{
+public:
+
+
+ virtual void stream(Channel *);
+
+};
+
+
+// ----------------------------------
+class Channel
+{
+public:
+
+ enum STATUS
+ {
+ S_NONE,
+ S_WAIT,
+ S_CONNECTING,
+ S_REQUESTING,
+ S_CLOSING,
+ S_RECEIVING,
+ S_BROADCASTING,
+ S_ABORT,
+ S_SEARCHING,
+ S_NOHOSTS,
+ S_IDLE,
+ S_ERROR,
+ S_NOTFOUND
+ };
+
+ enum TYPE
+ {
+ T_NONE,
+ T_ALLOCATED,
+ T_BROADCAST,
+ T_RELAY
+ };
+
+ enum SRC_TYPE
+ {
+ SRC_NONE,
+ SRC_PEERCAST,
+ SRC_SHOUTCAST,
+ SRC_ICECAST,
+ SRC_URL
+ };
+
+
+ Channel();
+ void reset();
+ void endThread(bool flg);
+
+ void startMP3File(char *);
+ void startGet();
+ void startICY(ClientSocket *,SRC_TYPE);
+ void startURL(const char *);
+
+
+ ChannelStream *createSource();
+
+ void resetPlayTime();
+
+ bool notFound()
+ {
+ return (status == S_NOTFOUND);
+ }
+
+ bool isPlaying()
+ {
+ return (status == S_RECEIVING) || (status == S_BROADCASTING);
+ }
+
+ bool isReceiving()
+ {
+ return (status == S_RECEIVING);
+ }
+
+ bool isBroadcasting()
+ {
+ return (status == S_BROADCASTING);
+ }
+
+ bool isFull();
+
+ bool checkBump();
+
+ bool checkIdle();
+ void sleepUntil(double);
+
+ bool isActive()
+ {
+ return type != T_NONE;
+ }
+
+
+ void connectFetch();
+ int handshakeFetch();
+
+ bool isIdle() {return isActive() && (status==S_IDLE);}
+
+ static THREAD_PROC stream(ThreadInfo *);
+
+ static THREAD_PROC waitFinish(ThreadInfo *);
+
+ void setStatus(STATUS s);
+ const char *getSrcTypeStr() {return srcTypes[srcType];}
+ const char *getStatusStr() {return statusMsgs[status];}
+ const char *getName() {return info.name.cstr();}
+ GnuID getID() {return info.id;}
+ int getBitrate() {return info.bitrate; }
+ void getIDStr(char *s) {info.id.toStr(s);}
+ void getStreamPath(char *);
+
+ void broadcastTrackerUpdate(GnuID &,bool = false);
+ bool sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+
+ bool writeVariable(Stream &, const String &,int);
+
+ bool acceptGIV(ClientSocket *);
+
+ void updateInfo(ChanInfo &);
+
+ int readStream(Stream &,ChannelStream *);
+
+ void checkReadDelay(unsigned int);
+
+ void processMp3Metadata(char *);
+
+ void readHeader();
+
+ void startStream();
+
+ XML::Node *createRelayXML(bool);
+
+ void newPacket(ChanPacket &);
+
+ int localListeners();
+ int localRelays();
+
+ int totalListeners();
+ int totalRelays();
+
+ ::String mount;
+ ChanMeta insertMeta;
+ ChanPacket headPack;
+
+ ChanPacketBuffer rawData;
+
+ ChannelStream *sourceStream;
+ unsigned int streamIndex;
+
+
+ ChanInfo info;
+ ChanHit sourceHost;
+
+ GnuID remoteID;
+
+
+ ::String sourceURL;
+
+ bool bump,stayConnected;
+ int icyMetaInterval;
+ unsigned int streamPos;
+ unsigned int skipCount; //JP-EX
+ bool readDelay;
+
+ TYPE type;
+ ChannelSource *sourceData;
+
+ SRC_TYPE srcType;
+
+ MP3Header mp3Head;
+ ThreadInfo thread;
+ ThreadInfo *finthread;
+
+ unsigned int lastIdleTime;
+ int status;
+ static char *statusMsgs[],*srcTypes[];
+
+ ClientSocket *sock;
+ ClientSocket *pushSock;
+
+ unsigned int lastTrackerUpdate;
+ unsigned int lastMetaUpdate;
+
+ double startTime,syncTime;
+
+ WEvent syncEvent;
+
+ Channel *next;
+
+ int channel_id;
+ ChanHit chDisp;
+ ChanHit trackerHit;
+ bool bumped;
+ unsigned int lastSkipTime;
+ unsigned int lastStopTime;
+};
+
+// ----------------------------------
+class ChanMgr
+{
+public:
+ enum {
+ MAX_IDLE_CHANNELS = 8, // max. number of channels that can be left idle
+ MAX_METAINT = 8192 // must be at least smaller than ChanPacket data len (ie. about half)
+
+ };
+
+
+ ChanMgr();
+
+ Channel *deleteChannel(Channel *);
+
+ Channel *createChannel(ChanInfo &,const char *);
+ Channel *findChannelByName(const char *);
+ Channel *findChannelByIndex(int);
+ Channel *findChannelByMount(const char *);
+ Channel *findChannelByID(GnuID &);
+ Channel *findChannelByNameID(ChanInfo &);
+ Channel *findPushChannel(int);
+ Channel *findChannelByChannelID(int id);
+
+ void broadcastTrackerSettings();
+ void setUpdateInterval(unsigned int v);
+ void broadcastRelays(Servent *,int,int);
+
+ int broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+ void broadcastTrackerUpdate(GnuID &,bool = false);
+
+ bool writeVariable(Stream &, const String &,int);
+
+ int findChannels(ChanInfo &,Channel **,int);
+ int findChannelsByStatus(Channel **,int,Channel::STATUS);
+
+ int numIdleChannels();
+ int numChannels();
+
+ void closeOldestIdle();
+ void closeAll();
+ void quit();
+
+ void addHit(Host &,GnuID &,bool);
+ ChanHit *addHit(ChanHit &);
+ void delHit(ChanHit &);
+ void deadHit(ChanHit &);
+ void setFirewalled(Host &);
+
+ ChanHitList *findHitList(ChanInfo &);
+ ChanHitList *findHitListByID(GnuID &);
+ ChanHitList *addHitList(ChanInfo &);
+
+ void clearHitLists();
+ void clearDeadHits(bool);
+ int numHitLists();
+
+ void setBroadcastMsg(::String &);
+
+ Channel *createRelay(ChanInfo &,bool);
+ Channel *findAndRelay(ChanInfo &);
+ void startSearch(ChanInfo &);
+
+ void playChannel(ChanInfo &);
+ void findAndPlayChannel(ChanInfo &,bool);
+
+ bool isBroadcasting(GnuID &);
+ bool isBroadcasting();
+
+ int pickHits(ChanHitSearch &);
+
+
+
+ Channel *channel;
+ ChanHitList *hitlist;
+
+ GnuID broadcastID;
+
+ ChanInfo searchInfo;
+
+ int numFinds;
+ ::String broadcastMsg;
+ unsigned int broadcastMsgInterval;
+ unsigned int lastHit,lastQuery;
+ unsigned int maxUptime;
+ bool searchActive;
+ unsigned int deadHitAge;
+ int icyMetaInterval;
+ int maxRelaysPerChannel;
+ WLock lock;
+ int minBroadcastTTL,maxBroadcastTTL;
+ int pushTimeout,pushTries,maxPushHops;
+ unsigned int autoQuery;
+ unsigned int prefetchTime;
+ unsigned int lastYPConnect;
+ unsigned int lastYPConnect2;
+ unsigned int icyIndex;
+
+ unsigned int hostUpdateInterval;
+ unsigned int bufferTime;
+
+ GnuID currFindAndPlayChannel;
+
+ WLock channellock;
+ WLock hitlistlock;
+};
+// ----------------------------------
+class PlayList
+{
+public:
+
+ enum TYPE
+ {
+ T_NONE,
+ T_SCPLS,
+ T_PLS,
+ T_ASX,
+ T_RAM,
+ };
+
+ PlayList(TYPE t, int max)
+ {
+ maxURLs = max;
+ numURLs = 0;
+ type = t;
+ urls = new ::String[max];
+ titles = new ::String[max];
+ }
+
+ ~PlayList()
+ {
+ delete [] urls;
+ delete [] titles;
+ }
+
+ void addURL(const char *url, const char *tit)
+ {
+ if (numURLs < maxURLs)
+ {
+ urls[numURLs].set(url);
+ titles[numURLs].set(tit);
+ numURLs++;
+ }
+ }
+ void addChannels(const char *,Channel **,int);
+ void addChannel(const char *,ChanInfo &);
+
+ void writeSCPLS(Stream &);
+ void writePLS(Stream &);
+ void writeASX(Stream &);
+ void writeRAM(Stream &);
+
+ void readSCPLS(Stream &);
+ void readPLS(Stream &);
+ void readASX(Stream &);
+
+ void read(Stream &s)
+ {
+ try
+ {
+ switch (type)
+ {
+ case T_SCPLS: readSCPLS(s); break;
+ case T_PLS: readPLS(s); break;
+ case T_ASX: readASX(s); break;
+ }
+ }catch(StreamException &) {} // keep pls regardless of errors (eof isn`t handled properly in sockets)
+ }
+
+ void write(Stream &s)
+ {
+ switch (type)
+ {
+ case T_SCPLS: writeSCPLS(s); break;
+ case T_PLS: writePLS(s); break;
+ case T_ASX: writeASX(s); break;
+ case T_RAM: writeRAM(s); break;
+ }
+ }
+
+ TYPE type;
+ int numURLs,maxURLs;
+ ::String *urls,*titles;
+};
+
+// ----------------------------------
+
+extern ChanMgr *chanMgr;
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info);
+bool isIndexTxt(Channel *ch);
+int numMaxRelaysIndexTxt(Channel *ch);
+int canStreamIndexTxt(Channel *ch);
+// for PCRaw end
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : common.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#pragma warning (disable: 4996)
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+// ----------------------------------
+class GeneralException
+{
+public:
+ GeneralException(const char *m, int e = 0)
+ {
+ strcpy(msg,m);
+ err=e;
+ }
+ char msg[128];
+ int err;
+};
+
+// -------------------------------------
+class StreamException : public GeneralException
+{
+public:
+ StreamException(const char *m) : GeneralException(m) {}
+ StreamException(const char *m,int e) : GeneralException(m,e) {}
+};
+
+// ----------------------------------
+class SockException : public StreamException
+{
+public:
+ SockException(const char *m="Socket") : StreamException(m) {}
+ SockException(const char *m, int e) : StreamException(m,e) {}
+};
+// ----------------------------------
+class EOFException : public StreamException
+{
+public:
+ EOFException(const char *m="EOF") : StreamException(m) {}
+ EOFException(const char *m, int e) : StreamException(m,e) {}
+};
+
+// ----------------------------------
+class CryptException : public StreamException
+{
+public:
+ CryptException(const char *m="Crypt") : StreamException(m) {}
+ CryptException(const char *m, int e) : StreamException(m,e) {}
+};
+
+
+// ----------------------------------
+class TimeoutException : public StreamException
+{
+public:
+ TimeoutException(const char *m="Timeout") : StreamException(m) {}
+};
+// --------------------------------
+class GnuID
+{
+public:
+ bool isSame(GnuID &gid)
+ {
+ for(int i=0; i<16; i++)
+ if (gid.id[i] != id[i])
+ return false;
+ return true;
+ }
+
+
+ bool isSet()
+ {
+ for(int i=0; i<16; i++)
+ if (id[i] != 0)
+ return true;
+ return false;
+ }
+
+ void clear()
+ {
+ for(int i=0; i<16; i++)
+ id[i] = 0;
+ storeTime = 0;
+ }
+
+
+ void generate(unsigned char = 0);
+ void encode(class Host *, const char *,const char *,unsigned char);
+
+ void toStr(char *);
+ void fromStr(const char *);
+
+ unsigned char getFlags();
+
+ unsigned char id[16];
+ unsigned int storeTime;
+};
+// --------------------------------
+class GnuIDList
+{
+public:
+ GnuIDList(int);
+ ~GnuIDList();
+ void clear();
+ void add(GnuID &);
+ bool contains(GnuID &);
+ int numUsed();
+ unsigned int getOldest();
+
+ GnuID *ids;
+ int maxID;
+};
+
+
+// ----------------------------------
+class Host
+{
+ inline unsigned int ip3()
+ {
+ return (ip>>24);
+ }
+ inline unsigned int ip2()
+ {
+ return (ip>>16)&0xff;
+ }
+ inline unsigned int ip1()
+ {
+ return (ip>>8)&0xff;
+ }
+ inline unsigned int ip0()
+ {
+ return ip&0xff;
+ }
+
+public:
+ Host(){init();}
+ Host(unsigned int i, unsigned short p)
+ {
+ ip = i;
+ port = p;
+ value = 0;
+ }
+
+ void init()
+ {
+ ip = 0;
+ port = 0;
+ value = 0;
+ }
+
+
+ bool isMemberOf(Host &);
+
+ bool isSame(Host &h)
+ {
+ return (h.ip == ip) && (h.port == port);
+ }
+
+ bool classType() {return globalIP();}
+
+ bool globalIP()
+ {
+ // local host
+ if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1))
+ return false;
+
+ // class A
+ if (ip3() == 10)
+ return false;
+
+ // class B
+ if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31))
+ return false;
+
+ // class C
+ if ((ip3() == 192) && (ip2() == 168))
+ return false;
+
+ return true;
+ }
+ bool localIP()
+ {
+ return !globalIP();
+ }
+
+ bool loopbackIP()
+ {
+// return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1));
+ return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1));
+ }
+
+ bool isValid()
+ {
+ return (ip != 0);
+ }
+
+
+ bool isSameType(Host &h)
+ {
+ return ( (globalIP() && h.globalIP()) ||
+ (!globalIP() && !h.globalIP()) );
+ }
+
+ void IPtoStr(char *str)
+ {
+ sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff);
+ }
+
+ void toStr(char *str)
+ {
+ sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port);
+ }
+
+ void fromStrIP(const char *,int);
+ void fromStrName(const char *,int);
+
+ bool isLocalhost();
+
+
+ union
+ {
+ unsigned int ip;
+// unsigned char ipByte[4];
+ };
+
+ unsigned short port;
+ unsigned int value;
+};
+// ----------------------------------
+#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) )
+#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) )
+#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24))
+#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c))
+#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0'))
+#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f))
+
+// ----------------------------------
+inline bool isWhiteSpace(char c)
+{
+ return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t');
+}
+
+// ----------------------------------
+inline int strToID(char *str)
+{
+ union {
+ int i;
+ char s[8];
+ };
+ strncpy(s,str,4);
+ return i;
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg);
+bool cmpCGIarg(char *str, char *arg, char *value);
+bool hasCGIarg(char *str, char *arg);
+
+// ----------------------------------
+extern void LOG(const char *fmt,...);
+
+extern void LOG_ERROR(const char *fmt,...);
+extern void LOG_DEBUG(const char *fmt,...);
+extern void LOG_NETWORK(const char *fmt,...);
+extern void LOG_CHANNEL(const char *fmt,...);
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : cstream.h
+// Date: 12-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CSTREAM_H
+#define _CSTREAM_H
+
+// ----------------------------------
+
+class Channel;
+class ChanPacket;
+class ChanPacketv;
+class Stream;
+
+
+// ----------------------------------
+class ChanPacket
+{
+public:
+ enum
+ {
+ MAX_DATALEN = 16384
+ };
+
+ enum TYPE
+ {
+ T_UNKNOWN = 0,
+ T_HEAD = 1,
+ T_DATA = 2,
+ T_META = 4,
+ T_PCP = 16,
+ T_ALL = 0xff
+ };
+
+ ChanPacket()
+ {
+ init();
+ }
+
+ void init()
+ {
+ type = T_UNKNOWN;
+ len = 0;
+ pos = 0;
+ sync = 0;
+ skip = false;
+ }
+ void init(ChanPacketv &p);
+ void init(TYPE t, const void *, unsigned int , unsigned int );
+
+ void writeRaw(Stream &);
+ void writePeercast(Stream &);
+ void readPeercast(Stream &);
+
+
+ unsigned int sync;
+ unsigned int pos;
+ TYPE type;
+ unsigned int len;
+ char data[MAX_DATALEN];
+ bool skip;
+
+};
+// ----------------------------------
+class ChanPacketv
+{
+public:
+ enum {BSIZE = 0x100};
+ ChanPacketv()
+ {
+ init();
+ }
+ ~ChanPacketv()
+ {
+ free();
+ }
+
+ void free()
+ {
+ if (data) {
+ delete [] data;
+ data = NULL;
+ datasize = 0;
+ }
+ }
+ void reset()
+ {
+ free();
+ init();
+ }
+ void init()
+ {
+ type = ChanPacket::T_UNKNOWN;
+ len = 0;
+ pos = 0;
+ sync = 0;
+ skip = false;
+ data = NULL;
+ datasize = 0;
+ }
+ void init(ChanPacket &p)
+ {
+ if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) {
+ free();
+ data = NULL;
+ datasize = 0;
+ }
+ type = p.type;
+ len = p.len;
+ pos = p.pos;
+ sync = p.sync;
+ skip = p.skip;
+ if (!data) {
+ datasize = (len & ~(BSIZE - 1)) + BSIZE;
+ data = new char[datasize];
+ }
+ memcpy(data, p.data, len);
+ }
+ void init(ChanPacketv &p)
+ {
+ ChanPacket tp;
+ tp.init(p);
+ init(tp);
+ }
+
+ void writeRaw(Stream &);
+ void writePeercast(Stream &);
+ void readPeercast(Stream &);
+
+ unsigned int sync;
+ unsigned int pos;
+ ChanPacket::TYPE type;
+ unsigned int len;
+ char *data;
+ unsigned int datasize;
+ bool skip;
+
+};
+// ----------------------------------
+class ChanPacketBuffer
+{
+public:
+ enum {
+ MAX_PACKETS = 64,
+ NUM_SAFEPACKETS = 60
+ };
+
+ void init()
+ {
+ lock.on();
+ lastPos = firstPos = safePos = 0;
+ readPos = writePos = 0;
+ accept = 0;
+ lastWriteTime = 0;
+ for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset();
+ lock.off();
+
+ lastSkipTime = 0;
+ }
+
+ int copyFrom(ChanPacketBuffer &,unsigned in);
+
+ bool writePacket(ChanPacket &,bool = false);
+ void readPacket(ChanPacket &);
+
+ bool willSkip();
+
+ int numPending() {return writePos-readPos;}
+
+ unsigned int getLatestPos();
+ unsigned int getOldestPos();
+ unsigned int findOldestPos(unsigned int);
+ bool findPacket(unsigned int,ChanPacket &);
+ unsigned int getStreamPos(unsigned int);
+ unsigned int getStreamPosEnd(unsigned int);
+ unsigned int getLastSync();
+
+ //ChanPacket packets[MAX_PACKETS];
+ ChanPacketv packets[MAX_PACKETS];
+ volatile unsigned int lastPos,firstPos,safePos;
+ volatile unsigned int readPos,writePos;
+ unsigned int accept;
+ unsigned int lastWriteTime;
+ WLock lock;
+
+ unsigned int lastSkipTime;
+};
+
+// ----------------------------------
+class ChannelStream
+{
+public:
+ ChannelStream()
+ :numListeners(0)
+ ,numRelays(0)
+ ,isPlaying(false)
+ ,fwState(0)
+ ,lastUpdate(0)
+ ,lastCheckTime(0)
+ ,parent(NULL)
+ {}
+ virtual ~ChannelStream() {}
+
+ void updateStatus(Channel *);
+ bool getStatus(Channel *,ChanPacket &);
+
+ virtual void kill() {}
+ virtual bool sendPacket(ChanPacket &,GnuID &) {return false;}
+ virtual void flush(Stream &) {}
+ virtual void readHeader(Stream &,Channel *)=0;
+ virtual int readPacket(Stream &,Channel *)=0;
+ virtual void readEnd(Stream &,Channel *)=0;
+
+ void readRaw(Stream &,Channel *);
+
+ int numRelays;
+ int numListeners;
+ bool isPlaying;
+ int fwState;
+ unsigned int lastUpdate;
+ unsigned int lastCheckTime;
+
+ Channel *parent;
+};
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : gnutella.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// GnuPacket is a Gnutella protocol packet.
+// GnuStream is a Stream that reads/writes GnuPackets
+//
+//
+// (c) 2002 peercast.org
+//
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "gnutella.h"
+#include "stream.h"
+#include "common.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "stats.h"
+#include <stdlib.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------
+const char *GNU_FUNC_STR(int func)
+{
+ switch (func)
+ {
+ case GNU_FUNC_PING: return "PING"; break;
+ case GNU_FUNC_PONG: return "PONG"; break;
+ case GNU_FUNC_QUERY: return "QUERY"; break;
+ case GNU_FUNC_HIT: return "HIT"; break;
+ case GNU_FUNC_PUSH: return "PUSH"; break;
+ default: return "UNKNOWN"; break;
+ }
+}
+
+// ---------------------------
+const char *GnuStream::getRouteStr(R_TYPE r)
+{
+ switch(r)
+ {
+ case R_PROCESS: return "PROCESS"; break;
+ case R_DEAD: return "DEAD"; break;
+ case R_DISCARD: return "DISCARD"; break;
+ case R_ACCEPTED: return "ACCEPTED"; break;
+ case R_BROADCAST: return "BROADCAST"; break;
+ case R_ROUTE: return "ROUTE"; break;
+ case R_DUPLICATE: return "DUPLICATE"; break;
+ case R_BADVERSION: return "BADVERSION"; break;
+ case R_DROP: return "DROP"; break;
+ default: return "UNKNOWN"; break;
+ }
+}
+// ---------------------------
+void GnuPacket::makeChecksumID()
+{
+ for(unsigned int i=0; i<len; i++)
+ id.id[i%16] += data[i];
+}
+
+// ---------------------------
+void GnuPacket::initPing(int t)
+{
+ func = GNU_FUNC_PING;
+ ttl = t;
+ hops = 0;
+ len = 0;
+
+ id.generate();
+}
+// ---------------------------
+void GnuPacket::initPong(Host &h, bool ownPong, GnuPacket &ping)
+{
+ func = GNU_FUNC_PONG;
+ ttl = ping.hops;
+ hops = 0;
+ len = 14;
+ id = ping.id;
+
+ MemoryStream pk(data,len);
+
+ pk.writeShort(h.port); // port
+ pk.writeLong(SWAP4(h.ip)); // ip
+ if (ownPong)
+ {
+ pk.writeLong(chanMgr->numChannels()); // cnt
+ pk.writeLong(servMgr->totalOutput(false)); // total
+ }else{
+ pk.writeLong(0); // cnt
+ pk.writeLong(0); // total
+ }
+
+
+}
+// ---------------------------
+void GnuPacket::initPush(ChanHit &ch, Host &sh)
+{
+#if 0
+ func = GNU_FUNC_PUSH;
+ ttl = ch.numHops;
+ hops = 0;
+ len = 26;
+ id.generate();
+
+ MemoryStream data(data,len);
+
+ // ID of Hit packet
+ data.write(ch.packetID.id,16);
+
+ // index of channel
+ data.writeLong(ch.index);
+
+ data.writeLong(SWAP4(sh.ip)); // ip
+ data.writeShort(sh.port); // port
+#endif
+}
+
+
+// ---------------------------
+bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl)
+{
+ if (!ch)
+ return false;
+
+ func = GNU_FUNC_HIT;
+ hops = 0;
+ id.generate();
+
+ ttl = maxttl;
+
+
+ MemoryStream mem(data,MAX_DATA);
+
+ mem.writeChar(1); // num hits
+ mem.writeShort(h.port); // port
+ mem.writeLong(SWAP4(h.ip)); // ip
+
+ if (query)
+ mem.writeLong(0); // speed - route
+ else
+ mem.writeLong(1); // broadcast
+
+
+ //mem.writeLong(ch->index); // index
+ mem.writeLong(0); // index
+ mem.writeShort(ch->getBitrate()); // bitrate
+ mem.writeShort(ch->localListeners()); // num listeners
+
+ mem.writeChar(0); // no name
+
+ XML xml;
+ XML::Node *cn = ch->info.createChannelXML();
+ cn->add(ch->info.createTrackXML());
+ xml.setRoot(cn);
+ xml.writeCompact(mem);
+
+ mem.writeChar(0); // extra null
+
+
+ // QHD
+ mem.writeLong('PCST'); // vendor ID
+ mem.writeChar(2); // public sector length
+
+ int f1 = 0, f2 = 0;
+
+ f1 = 1 | 4 | 8 | 32 | 64; // use push | busy | stable | broadcast | tracker
+
+ if (push) f2 |= 1;
+ if (busy) f2 |= 4;
+ if (stable) f2 |= 8;
+ if (!query) f2 |= 32;
+ if (tracker) f2 |= 64;
+
+ mem.writeChar(f1);
+ mem.writeChar(f2);
+
+ {
+ // write private sector
+ char pbuf[256];
+ MemoryStream pmem(pbuf,sizeof(pbuf));
+ XML xml;
+ XML::Node *pn = servMgr->createServentXML();
+ xml.setRoot(pn);
+ xml.writeCompact(pmem);
+ pmem.writeChar(0); // add null terminator
+ if (pmem.pos <= 255)
+ {
+ mem.writeChar(pmem.pos);
+ mem.write(pmem.buf,pmem.pos);
+ }else
+ mem.writeChar(0);
+ }
+
+
+ // queryID/not used
+ if (query)
+ mem.write(query->id.id,16);
+ else
+ mem.write(id.id,16);
+
+ len = mem.pos;
+
+ LOG_NETWORK("Created Hit packet: %d bytes",len);
+
+ if (len >= MAX_DATA)
+ return false;
+
+// servMgr->addReplyID(id);
+ return true;
+}
+
+
+// ---------------------------
+void GnuPacket::initFind(const char *str, XML *xml, int maxTTL)
+{
+
+ func = GNU_FUNC_QUERY;
+ ttl = maxTTL;
+ hops = 0;
+ id.generate();
+
+ MemoryStream mem(data,MAX_DATA);
+
+ mem.writeShort(0); // min speed
+
+ if (str)
+ {
+ int slen = strlen(str);
+ mem.write((void *)str,slen+1); // string
+ }else
+ mem.writeChar(0); // null string
+
+
+ if (xml)
+ xml->writeCompact(mem);
+
+ len = mem.pos;
+}
+
+// ---------------------------
+void GnuStream::ping(int ttl)
+{
+ GnuPacket ping;
+ ping.initPing(ttl);
+// servMgr->addReplyID(ping.id);
+ sendPacket(ping);
+ LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]);
+}
+
+// ---------------------------
+void GnuStream::sendPacket(GnuPacket &p)
+{
+ try
+ {
+ lock.on();
+ packetsOut++;
+ stats.add(Stats::NUMPACKETSOUT);
+
+ switch(p.func)
+ {
+ case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break;
+ case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break;
+ case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break;
+ case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break;
+ case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break;
+ default: stats.add(Stats::NUMOTHEROUT); break;
+ }
+
+
+ write(p.id.id,16);
+ writeChar(p.func); // ping func
+ writeChar(p.ttl); // ttl
+ writeChar(p.hops); // hops
+ writeLong(p.len); // len
+
+ if (p.len)
+ write(p.data,p.len);
+
+ stats.add(Stats::PACKETDATAOUT,23+p.len);
+
+ lock.off();
+ }catch(StreamException &e)
+ {
+ lock.off();
+ throw e;
+ }
+}
+// ---------------------------
+bool GnuStream::readPacket(GnuPacket &p)
+{
+ try
+ {
+ lock.on();
+ packetsIn++;
+ stats.add(Stats::NUMPACKETSIN);
+
+ read(p.id.id,16);
+ p.func = readChar();
+ p.ttl = readChar();
+ p.hops = readChar();
+ p.len = readLong();
+
+
+ if ((p.hops >= 1) && (p.hops <= 10))
+ stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1));
+
+ stats.add(Stats::PACKETDATAIN,23+p.len);
+
+ switch(p.func)
+ {
+ case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break;
+ case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break;
+ case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break;
+ case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break;
+ case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break;
+ default: stats.add(Stats::NUMOTHERIN); break;
+ }
+
+
+ if (p.len)
+ {
+ if (p.len > GnuPacket::MAX_DATA)
+ {
+ while (p.len--)
+ readChar();
+ lock.off();
+ return false;
+ }
+ read(p.data,p.len);
+ }
+
+ lock.off();
+ return true;
+ }catch(StreamException &e)
+ {
+ lock.off();
+ throw e;
+ }
+}
+
+// ---------------------------
+GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID)
+{
+
+ R_TYPE ret = R_DISCARD;
+
+ MemoryStream data(in.data,in.len);
+
+ Host remoteHost = serv->getHost();
+
+ in.ttl--;
+ in.hops++;
+
+ routeID = in.id;
+
+
+
+ switch(in.func)
+ {
+ case GNU_FUNC_PING: // ping
+ {
+ LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x",
+ remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff,
+ in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]
+ );
+ Host sh = servMgr->serverHost;
+ if (sh.isValid())
+ {
+ if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull()))
+ {
+ GnuPacket pong;
+ pong.initPong(sh,true,in);
+ if (serv->outputPacket(pong,true))
+ LOG_NETWORK("pong out");
+ }
+ ret = R_BROADCAST;
+ }
+ }
+ break;
+ case GNU_FUNC_PONG: // pong
+ {
+ {
+ int ip,port,cnt,total;
+ port = data.readShort();
+ ip = data.readLong();
+ cnt = data.readLong();
+ total = data.readLong();
+
+ ip = SWAP4(ip);
+
+
+ Host h;
+ h.ip = ip;
+ h.port = port;
+
+ char sIP[64],rIP[64];
+ h.toStr(sIP);
+ remoteHost.toStr(rIP);
+
+ LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]);
+
+
+ ret = R_DISCARD;
+
+ if (h.isValid())
+ {
+
+ #if 0
+ // accept if this pong is a reply from one of our own pings, otherwise route back
+ if (servMgr->isReplyID(in.id))
+ {
+ servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+ ret = R_ACCEPTED;
+ }else
+ ret = R_ROUTE;
+ #endif
+ }
+
+ }
+ }
+ break;
+ case GNU_FUNC_QUERY: // query
+ ret = R_BROADCAST;
+
+ {
+ Host sh = servMgr->serverHost;
+ if (!sh.isValid())
+ sh.ip = 127<<24|1;
+
+ char words[256];
+ short spd = data.readShort();
+ data.readString(words,sizeof(words));
+ words[sizeof(words)-1] = 0;
+
+ MemoryStream xm(&data.buf[data.pos],data.len-data.pos);
+ xm.buf[xm.len] = 0;
+
+ Channel *hits[16];
+ int numHits=0;
+
+ if (strncmp(xm.buf,"<?xml",5)==0)
+ {
+ XML xml;
+ xml.read(xm);
+ XML::Node *cn = xml.findNode("channel");
+ if (cn)
+ {
+ ChanInfo info;
+ info.init(cn);
+ info.status = ChanInfo::S_PLAY;
+ numHits = chanMgr->findChannels(info,hits,16);
+ }
+ LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits);
+ }else{
+ ChanInfo info;
+ info.name.set(words);
+ info.genre.set(words);
+ info.id.fromStr(words);
+ info.status = ChanInfo::S_PLAY;
+ numHits = chanMgr->findChannels(info,hits,16);
+ LOG_NETWORK("query STR: %s : found %d",words,numHits);
+ }
+
+
+
+ for(int i=0; i<numHits; i++)
+ {
+ bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+ bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+ bool stable = servMgr->totalStreams>0;
+ bool tracker = hits[i]->isBroadcasting();
+
+ GnuPacket hit;
+ if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops))
+ serv->outputPacket(hit,true);
+ }
+ }
+ break;
+ case GNU_FUNC_PUSH: // push
+ {
+
+ GnuID pid;
+ data.read(pid.id,16);
+
+ //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]);
+ //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]);
+
+
+ int index = data.readLong();
+ int ip = data.readLong();
+ int port = data.readShort();
+
+
+ ip = SWAP4(ip);
+
+ Host h(ip,port);
+ char hostName[64];
+ h.toStr(hostName);
+
+#if 0
+ if (servMgr->isReplyID(pid))
+ {
+#if 0
+ Channel *c = chanMgr->findChannelByIndex(index);
+
+ if (!c)
+ {
+ LOG_NETWORK("push 0x%x to %s: Not found",index,hostName);
+ }else
+ {
+ if (!c->isFull() && !servMgr->streamFull())
+ {
+ LOG_NETWORK("push: 0x%x to %s: OK",index,hostName);
+
+ Servent *s = servMgr->allocServent();
+ if (s)
+ s->initGIV(h,c->info.id);
+ }else
+ LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName);
+ }
+#endif
+ ret = R_ACCEPTED;
+ }else{
+ LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName);
+ routeID = pid;
+ ret = R_ROUTE;
+ }
+#endif
+ }
+ break;
+ case GNU_FUNC_HIT: // hit
+ {
+ ret = R_DISCARD;
+
+ ChanHit hit;
+ if (readHit(data,hit,in.hops,in.id))
+ {
+
+ char flstr[64];
+ flstr[0]=0;
+ if (hit.firewalled) strcat(flstr,"Push,");
+ if (hit.tracker) strcat(flstr,"Tracker,");
+
+#if 0
+ if ((spd == 0) && (!isBroadcastHit))
+ {
+ if (servMgr->isReplyID(queryID))
+ {
+ ret = R_ACCEPTED;
+ LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }else
+ {
+ routeID = queryID;
+ ret = R_ROUTE;
+ LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }
+ }else
+ {
+ ret = R_BROADCAST;
+ LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }
+#else
+ ret = R_BROADCAST;
+ LOG_NETWORK("broadcast-hit: %s",flstr);
+#endif
+ }
+ }
+ break;
+ default:
+ LOG_NETWORK("packet: %d",in.func);
+ break;
+ }
+
+
+ if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0))
+ if ((ret == R_BROADCAST) || (ret == R_ROUTE))
+ ret = R_DEAD;
+
+ return ret;
+}
+
+// ---------------------------
+bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id)
+{
+ int i;
+ int num = data.readChar(); // hits
+ int port = data.readShort(); // port
+ int ip = data.readLong(); // ip
+ ip = SWAP4(ip);
+ int spd = data.readLong(); // speed/broadcast
+
+ Host h(ip,port);
+ char hostName[64];
+
+ h.IPtoStr(hostName);
+
+ bool dataValid=true;
+
+ ChanHit *hits[100];
+ int numHits=0;
+
+ for(i=0; i<num; i++)
+ {
+ int index,bitrate,listeners;
+
+
+ index = data.readLong(); // index
+ bitrate = data.readShort(); // bitrate
+ listeners = data.readShort(); // listeners
+
+ // read name .. not used.
+ char fname[256];
+ data.readString(fname,sizeof(fname));
+ fname[sizeof(fname)-1] = 0;
+
+ ch.init();
+ ch.firewalled = false; // default to NO as we dont get the info until the next section.
+ ch.host = h;
+ ch.numListeners = listeners;
+ ch.numHops = hops;
+ ch.rhost[0] = ch.host;
+
+ ChanInfo info;
+
+
+ {
+ char xmlData[4000];
+ int xlen = data.readString(xmlData,sizeof(xmlData));
+
+ if ((strncmp(xmlData,"<?xml",5)==0) && (xlen < GnuPacket::MAX_DATA))
+ {
+ //LOG_NETWORK("Hit XML: %s",xmlData);
+
+ MemoryStream xm(xmlData,xlen);
+ XML xml;
+ xml.read(xm);
+ XML::Node *n = xml.findNode("channel");
+ if (n)
+ {
+ info.init(n);
+ char idStr[64];
+ info.id.toStr(idStr);
+ LOG_NETWORK("got hit %s %s",idStr,info.name.cstr());
+
+ ch.upTime = n->findAttrInt("uptime");
+
+ }else
+ LOG_NETWORK("Missing Channel node");
+ }else
+ {
+ LOG_NETWORK("Missing XML data");
+ //LOG_NETWORK("%s",xmlData);
+ dataValid = false;
+ }
+ }
+
+ if (info.id.isSet())
+ {
+ if (!chanMgr->findHitList(info))
+ chanMgr->addHitList(info);
+
+ ch.recv = true;
+ ch.chanID = info.id;
+ ChanHit *chp = chanMgr->addHit(ch);
+
+ if ((chp) && (numHits<100))
+ hits[numHits++] = chp;
+ }
+
+ }
+
+
+ int vendor = data.readLong(); // vendor ID
+
+ int pubLen = data.readChar(); // public sec length - should be 2
+
+ int f1 = data.readChar() & 0xff; // flags 1
+ int f2 = data.readChar() & 0xff; // flags 2
+
+ pubLen -= 2;
+ while (pubLen-->0)
+ data.readChar();
+
+
+ char agentStr[16];
+ agentStr[0]=0;
+ int maxPreviewTime=0;
+
+ // read private sector with peercast servant specific info
+ int privLen = data.readChar();
+
+ if (privLen)
+ {
+ char privData[256];
+ data.read(privData,privLen);
+ if (strncmp(privData,"<?xml",5)==0)
+ {
+ MemoryStream xm(privData,privLen);
+ XML xml;
+ xml.read(xm);
+ XML::Node *sn = xml.findNode("servent");
+ if (sn)
+ {
+ char *ag = sn->findAttr("agent");
+ if (ag)
+ {
+ strncpy(agentStr,ag,16);
+ agentStr[15]=0;
+ }
+ maxPreviewTime = sn->findAttrInt("preview");
+ }
+
+ }
+ }
+
+
+ // not used anymore
+ GnuID queryID;
+ data.read(queryID.id,16);
+
+ bool isBroadcastHit=false;
+ if (f1 & 32)
+ isBroadcastHit = (f2 & 32)!=0;
+
+ for(i=0; i<numHits; i++)
+ {
+ if (f1 & 1)
+ hits[i]->firewalled = (f2 & 1)!=0;
+
+ if (f1 & 64)
+ hits[i]->tracker = (f2 & 64)!=0;
+
+ }
+
+ return dataValid;
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : gnutella.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GNUTELLA_H
+#define _GNUTELLA_H
+
+// --------------------------------
+#include "stream.h"
+#include "sys.h"
+
+
+
+#define GNUTELLA_SETUP 0
+
+
+// --------------------------------
+static const int GNU_FUNC_PING = 0;
+static const int GNU_FUNC_PONG = 1;
+static const int GNU_FUNC_QUERY = 128;
+static const int GNU_FUNC_HIT = 129;
+static const int GNU_FUNC_PUSH = 64;
+
+extern const char *GNU_FUNC_STR(int);
+
+// --------------------------------
+static const char *GNU_PEERCONN = "PEERCAST CONNECT/0.1";
+static const char *GNU_CONNECT = "GNUTELLA CONNECT/0.6";
+static const char *GNU_OK = "GNUTELLA/0.6 200 OK";
+static const char *PCX_PCP_CONNECT = "pcp";
+
+static const char *PCX_HS_OS = "x-peercast-os:";
+static const char *PCX_HS_DL = "x-peercast-download:";
+static const char *PCX_HS_ID = "x-peercast-id:";
+static const char *PCX_HS_CHANNELID = "x-peercast-channelid:";
+static const char *PCX_HS_NETWORKID = "x-peercast-networkid:";
+static const char *PCX_HS_MSG = "x-peercast-msg:";
+static const char *PCX_HS_SUBNET = "x-peercast-subnet:";
+static const char *PCX_HS_FULLHIT = "x-peercast-fullhit:";
+static const char *PCX_HS_MINBCTTL = "x-peercast-minbcttl:";
+static const char *PCX_HS_MAXBCTTL = "x-peercast-maxbcttl:";
+static const char *PCX_HS_RELAYBC = "x-peercast-relaybc:";
+static const char *PCX_HS_PRIORITY = "x-peercast-priority:";
+static const char *PCX_HS_FLOWCTL = "x-peercast-flowctl:";
+static const char *PCX_HS_PCP = "x-peercast-pcp:";
+static const char *PCX_HS_PINGME = "x-peercast-pingme:";
+static const char *PCX_HS_PORT = "x-peercast-port:";
+static const char *PCX_HS_REMOTEIP = "x-peercast-remoteip:";
+static const char *PCX_HS_POS = "x-peercast-pos:";
+static const char *PCX_HS_SESSIONID = "x-peercast-sessionid:";
+
+// official version number sent to relay to check for updates
+static const char *PCX_OS_WIN32 = "Win32";
+static const char *PCX_OS_LINUX = "Linux";
+static const char *PCX_OS_MACOSX = "Apple-OSX";
+static const char *PCX_OS_WINAMP2 = "Win32-WinAmp2";
+static const char *PCX_OS_ACTIVEX = "Win32-ActiveX";
+
+static const char *PCX_DL_URL = "http://www.peercast.org/download.php";
+
+// version number sent to other clients
+static const char *PCX_OLDAGENT = "PeerCast/0.119E";
+
+
+
+
+
+// version number used inside packets GUIDs
+static const int PEERCAST_PACKETID = 0x0000119E;
+
+static const char *MIN_ROOTVER = "0.119E";
+
+static const char *MIN_CONNECTVER = "0.119D";
+static const int MIN_PACKETVER = 0x0000119D;
+
+static const char *ICY_OK = "ICY 200 OK";
+
+// --------------------------------
+
+static const int DEFAULT_PORT = 7144;
+
+// --------------------------------
+
+class Servent;
+class Channel;
+class ChanHit;
+
+
+// --------------------------------
+class GnuPacket
+{
+public:
+
+
+ // --------------------------------
+ class Hash
+ {
+ public:
+
+ bool isSame(Hash &h)
+ {
+ return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum);
+ }
+
+ bool isSameID(Hash &h)
+ {
+ return (idChecksum == h.idChecksum);
+ }
+
+ unsigned int idChecksum;
+ unsigned int dataChecksum;
+
+ };
+ // --------------------------------
+
+ enum {
+ MAX_DATA = 2000
+ };
+
+ void initPing(int);
+ void initPong(Host &, bool, GnuPacket &);
+ void initFind(const char *, class XML *,int);
+ bool initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int);
+ void initPush(ChanHit &, Host &);
+
+
+ void makeChecksumID();
+
+ unsigned char func;
+ unsigned char ttl;
+ unsigned char hops;
+ unsigned int len;
+ Hash hash;
+ GnuID id;
+
+ char data[MAX_DATA];
+};
+// --------------------------------
+class GnuPacketBuffer
+{
+public:
+ GnuPacketBuffer(int s)
+ :size(s)
+ ,packets(new GnuPacket[size])
+ {
+ reset();
+ }
+ ~GnuPacketBuffer()
+ {
+ delete [] packets;
+ }
+
+ void reset()
+ {
+ readPtr = writePtr = 0;
+ }
+
+ GnuPacket *curr()
+ {
+ if (numPending())
+ return &packets[readPtr%size];
+ else
+ return NULL;
+
+ }
+ void next()
+ {
+ readPtr++;
+ }
+
+ int findMinHop()
+ {
+ int min=100;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ {
+ int idx = (readPtr+i)%size;
+ if (packets[idx].hops < min)
+ min = packets[idx].hops;
+ }
+ return min;
+ }
+ int findMaxHop()
+ {
+ int max=0;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ {
+ int idx = (readPtr+i)%size;
+ if (packets[idx].hops > max)
+ max = packets[idx].hops;
+ }
+ return max;
+ }
+
+ int percentFull()
+ {
+ return (numPending()*100) / size;
+ }
+
+
+ int sizeOfPending()
+ {
+ int tot=0;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ tot+=packets[(readPtr+i)%size].len;
+ return tot;
+ }
+
+ int numPending()
+ {
+ return writePtr-readPtr;
+ }
+
+ bool write(GnuPacket &p)
+ {
+ if ((writePtr-readPtr) >= size)
+ return false;
+ else
+ {
+ packets[writePtr%size] = p;
+ writePtr++;
+ return true;
+ }
+ }
+
+ int size;
+ GnuPacket *packets;
+ int readPtr,writePtr;
+};
+
+
+
+// --------------------------------
+class GnuStream : public IndirectStream
+{
+public:
+
+ enum R_TYPE
+ {
+ R_PROCESS,
+ R_DEAD,
+ R_DISCARD,
+ R_ACCEPTED,
+ R_BROADCAST,
+ R_ROUTE,
+ R_DUPLICATE,
+ R_BADVERSION,
+ R_DROP
+ };
+
+ GnuStream()
+ {
+ init(NULL);
+ }
+
+ void init(Stream *s)
+ {
+ IndirectStream::init(s);
+ packetsIn = packetsOut = 0;
+ }
+
+ bool readPacket(GnuPacket &);
+ void sendPacket(GnuPacket &);
+ R_TYPE processPacket(GnuPacket &, Servent *, GnuID &);
+
+ static const char *getRouteStr(R_TYPE);
+ bool readHit(Stream &data, ChanHit &ch,int,GnuID &);
+
+
+
+ void ping(int);
+
+ int packetsIn,packetsOut;
+ WLock lock;
+};
+
+
+#endif
--- /dev/null
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+
+// ---------------------------------------
+class HTML : public XML
+{
+public:
+ HTML(const char *);
+
+
+ void startNode(XML::Node *, const char * = NULL);
+ void addLink(const char *, const char *);
+ void addArgLink(const char *, const char *);
+ XML::Node *startTag(const char *, const char * = NULL,...);
+ XML::Node *startTagEnd(const char *, const char * = NULL,...);
+ void startSingleTagEnd(const char *,...);
+ void startTableRow(int);
+ void end();
+ void addRefresh(int);
+
+ char defArgs[128];
+ XML::Node *currNode,*headNode,*htmlNode;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : html.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// HTML protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "html.h"
+#include "http.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "servmgr.h"
+#include "channel.h"
+#include "stats.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------
+HTML::HTML(const char *t, Stream &o)
+{
+ o.writeCRLF = false;
+ out = new WriteBufferStream(8192, &o);
+ out->writeCRLF = false;
+
+ title.set(t);
+ tagLevel = 0;
+ refresh = 0;
+}
+
+HTML::~HTML()
+{
+ try {
+ out->flush();
+ } catch (StreamException &) {}
+ delete out;
+}
+
+// --------------------------------------
+void HTML::writeOK(const char *content)
+{
+ out->writeLine(HTTP_SC_OK);
+ out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache");
+ out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ out->writeLineF("%s %s",HTTP_HS_CONTENT,content);
+ out->writeLine("");
+}
+// --------------------------------------
+void HTML::writeVariable(Stream &s,const String &varName, int loop)
+{
+ bool r=false;
+ if (varName.startsWith("servMgr."))
+ r=servMgr->writeVariable(s,varName+8);
+ else if (varName.startsWith("chanMgr."))
+ r=chanMgr->writeVariable(s,varName+8,loop);
+ else if (varName.startsWith("stats."))
+ r=stats.writeVariable(s,varName+6);
+ else if (varName.startsWith("sys."))
+ {
+ if (varName == "sys.log.dumpHTML")
+ {
+ sys->logBuf->dumpHTML(s);
+ r=true;
+ }
+ }
+ else if (varName.startsWith("loop."))
+ {
+ if (varName.startsWith("loop.channel."))
+ {
+ Channel *ch = chanMgr->findChannelByIndex(loop);
+ if (ch)
+ r = ch->writeVariable(s,varName+13,loop);
+ }else if (varName.startsWith("loop.servent."))
+ {
+ Servent *sv = servMgr->findServentByIndex(loop);
+ if (sv)
+ r = sv->writeVariable(s,varName+13);
+ }else if (varName.startsWith("loop.filter."))
+ {
+ ServFilter *sf = &servMgr->filters[loop];
+ r = sf->writeVariable(s,varName+12);
+
+ }else if (varName.startsWith("loop.bcid."))
+ {
+ BCID *bcid = servMgr->findValidBCID(loop);
+ if (bcid)
+ r = bcid->writeVariable(s,varName+10);
+
+ }else if (varName == "loop.indexEven")
+ {
+ s.writeStringF("%d",(loop&1)==0);
+ r = true;
+ }else if (varName == "loop.index")
+ {
+ s.writeStringF("%d",loop);
+ r = true;
+ }else if (varName.startsWith("loop.hit."))
+ {
+ char *idstr = getCGIarg(tmplArgs,"id=");
+ if (idstr)
+ {
+ GnuID id;
+ id.fromStr(idstr);
+ ChanHitList *chl = chanMgr->findHitListByID(id);
+ if (chl)
+ {
+ int cnt=0;
+ ChanHit *ch = chl->hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ {
+ if (cnt == loop)
+ {
+ r = ch->writeVariable(s,varName+9);
+ break;
+ }
+ cnt++;
+ }
+ ch=ch->next;
+ }
+
+ }
+ }
+ }
+
+ }
+ else if (varName.startsWith("page."))
+ {
+ if (varName.startsWith("page.channel."))
+ {
+ char *idstr = getCGIarg(tmplArgs,"id=");
+ if (idstr)
+ {
+ GnuID id;
+ id.fromStr(idstr);
+ Channel *ch = chanMgr->findChannelByID(id);
+ if (ch)
+ r = ch->writeVariable(s,varName+13,loop);
+ }
+ }else
+ {
+
+ String v = varName+5;
+ v.append('=');
+ char *a = getCGIarg(tmplArgs,v);
+ if (a)
+ {
+ s.writeString(a);
+ r=true;
+ }
+ }
+ }
+
+
+ if (!r)
+ s.writeString(varName);
+}
+// --------------------------------------
+int HTML::getIntVariable(const String &varName,int loop)
+{
+ String val;
+ MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+ writeVariable(mem,varName,loop);
+
+ return atoi(val.cstr());
+}
+// --------------------------------------
+bool HTML::getBoolVariable(const String &varName,int loop)
+{
+ String val;
+ MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+ writeVariable(mem,varName,loop);
+
+ // integer
+ if ((val[0] >= '0') && (val[0] <= '9'))
+ return atoi(val.cstr()) != 0;
+
+ // string
+ if (val[0]!=0)
+ return true;
+
+ return false;
+}
+
+// --------------------------------------
+void HTML::readIf(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ bool varCond=true;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '}')
+ {
+ if (getBoolVariable(var,loop)==varCond)
+ {
+ if (readTemplate(in,outp,loop))
+ readTemplate(in,NULL,loop);
+ }else{
+ if (readTemplate(in,NULL,loop))
+ readTemplate(in,outp,loop);
+ }
+ return;
+ }else if (c == '!')
+ {
+ varCond = !varCond;
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+
+// --------------------------------------
+void HTML::readLoop(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '}')
+ {
+ int cnt = getIntVariable(var,loop);
+
+ if (cnt)
+ {
+ int spos = in.getPosition();
+ for(int i=0; i<cnt; i++)
+ {
+ in.seekTo(spos);
+ readTemplate(in,outp,i);
+ }
+ }else
+ {
+ readTemplate(in,NULL,0);
+ }
+ return;
+
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+
+// --------------------------------------
+int HTML::readCmd(Stream &in,Stream *outp,int loop)
+{
+ String cmd;
+
+ int tmpl = TMPL_UNKNOWN;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (String::isWhitespace(c) || (c=='}'))
+ {
+ if (cmd == "loop")
+ {
+ readLoop(in,outp,loop);
+ tmpl = TMPL_LOOP;
+ }else if (cmd == "if")
+ {
+ readIf(in,outp,loop);
+ tmpl = TMPL_IF;
+ }else if (cmd == "end")
+ {
+ tmpl = TMPL_END;
+ }
+ else if (cmd == "else")
+ {
+ tmpl = TMPL_ELSE;
+ }
+ break;
+ }else
+ {
+ cmd.append(c);
+ }
+ }
+ return tmpl;
+}
+
+// --------------------------------------
+void HTML::readVariable(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ while (!in.eof())
+ {
+ char c = in.readChar();
+ if (c == '}')
+ {
+ if (outp)
+ writeVariable(*outp,var,loop);
+ return;
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+// --------------------------------------
+bool HTML::readTemplate(Stream &in,Stream *outp,int loop)
+{
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '{')
+ {
+ c = in.readChar();
+ if (c == '$')
+ {
+ readVariable(in,outp,loop);
+ }
+ else if (c == '@')
+ {
+ int t = readCmd(in,outp,loop);
+ if (t == TMPL_END)
+ return false;
+ else if (t == TMPL_ELSE)
+ return true;
+ }
+ else if (c == '{')
+ {
+ if (outp)
+ outp->writeChar(c);
+ }
+ else
+ throw StreamException("Unknown template escape");
+ }else
+ {
+ if (outp)
+ outp->writeChar(c);
+ }
+ }
+ return false;
+}
+
+// --------------------------------------
+void HTML::writeTemplate(const char *fileName, const char *args)
+{
+ FileStream file;
+ MemoryStream mm;
+ try
+ {
+ file.openReadOnly(fileName);
+ mm.readFromFile(file);
+
+ tmplArgs = args;
+ readTemplate(mm,out,0);
+
+ }catch(StreamException &e)
+ {
+ out->writeString(e.msg);
+ out->writeString(" : ");
+ out->writeString(fileName);
+ }
+
+ mm.free2();
+ file.close();
+}
+// --------------------------------------
+void HTML::writeRawFile(const char *fileName)
+{
+ FileStream file;
+ try
+ {
+ file.openReadOnly(fileName);
+
+ file.writeTo(*out,file.length());
+
+ }catch(StreamException &)
+ {
+ }
+
+ file.close();
+}
+
+// --------------------------------------
+void HTML::locateTo(const char *url)
+{
+ out->writeLine(HTTP_SC_FOUND);
+ out->writeLineF("Location: %s",url);
+ out->writeLine("");
+}
+// --------------------------------------
+void HTML::startHTML()
+{
+ startNode("html");
+}
+// --------------------------------------
+void HTML::startBody()
+{
+ startNode("body");
+}
+// --------------------------------------
+void HTML::addHead()
+{
+ char buf[512];
+ startNode("head");
+ startTagEnd("title",title.cstr());
+ startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"");
+
+ if (!refreshURL.isEmpty())
+ {
+ sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr());
+ startTagEnd(buf);
+ }else if (refresh)
+ {
+ sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh);
+ startTagEnd(buf);
+ }
+
+
+ end();
+}
+// --------------------------------------
+void HTML::addContent(const char *s)
+{
+ out->writeString(s);
+}
+// --------------------------------------
+void HTML::startNode(const char *tag, const char *data)
+{
+ const char *p = tag;
+ char *o = &currTag[tagLevel][0];
+
+ int i;
+ for(i=0; i<MAX_TAGLEN-1; i++)
+ {
+ char c = *p++;
+ if ((c==0) || (c==' '))
+ break;
+ else
+ *o++ = c;
+ }
+ *o = 0;
+
+ out->writeString("<");
+ out->writeString(tag);
+ out->writeString(">");
+ if (data)
+ out->writeString(data);
+
+ tagLevel++;
+ if (tagLevel >= MAX_TAGLEVEL)
+ throw StreamException("HTML too deep!");
+}
+// --------------------------------------
+void HTML::end()
+{
+ tagLevel--;
+ if (tagLevel < 0)
+ throw StreamException("HTML premature end!");
+
+ out->writeString("</");
+ out->writeString(&currTag[tagLevel][0]);
+ out->writeString(">");
+}
+// --------------------------------------
+void HTML::addLink(const char *url, const char *text, bool toblank)
+{
+ char buf[1024];
+
+ sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":"");
+ startNode(buf,text);
+ end();
+}
+// --------------------------------------
+void HTML::startTag(const char *tag, const char *fmt,...)
+{
+ if (fmt)
+ {
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tag,tmp);
+
+ va_end(ap);
+ }else{
+ startNode(tag,NULL);
+ }
+}
+// --------------------------------------
+void HTML::startTagEnd(const char *tag, const char *fmt,...)
+{
+ if (fmt)
+ {
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tag,tmp);
+
+ va_end(ap);
+ }else{
+ startNode(tag,NULL);
+ }
+ end();
+}
+// --------------------------------------
+void HTML::startSingleTagEnd(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tmp);
+
+ va_end(ap);
+ end();
+}
+
+// --------------------------------------
+void HTML::startTableRow(int i)
+{
+ if (i & 1)
+ startTag("tr bgcolor=\"#dddddd\" align=\"left\"");
+ else
+ startTag("tr bgcolor=\"#eeeeee\" align=\"left\"");
+}
--- /dev/null
+// ------------------------------------------------
+// File : html.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+#include "sys.h"
+
+class FileStream;
+class WriteBufferStream;
+
+// ---------------------------------------
+class HTML
+{
+public:
+ enum
+ {
+ MAX_TAGLEVEL = 64,
+ MAX_TAGLEN = 64
+ };
+
+ enum
+ {
+ TMPL_UNKNOWN,
+ TMPL_LOOP,
+ TMPL_IF,
+ TMPL_ELSE,
+ TMPL_END
+ };
+
+ HTML(const char *,Stream &);
+ ~HTML();
+
+ void startNode(const char *, const char * = NULL);
+ void addLink(const char *, const char *, bool = false);
+ void startTag(const char *, const char * = NULL,...);
+ void startTagEnd(const char *, const char * = NULL,...);
+ void startSingleTagEnd(const char *,...);
+ void startTableRow(int);
+ void end();
+ void setRefresh(int sec) {refresh = sec;}
+ void setRefreshURL(const char *u){refreshURL.set(u);}
+ void addHead();
+ void startHTML();
+ void startBody();
+
+ void locateTo(const char *);
+ void addContent(const char *);
+
+ void writeOK(const char *);
+ void writeTemplate(const char *, const char *);
+ void writeRawFile(const char *);
+ void writeVariable(Stream &,const String &,int);
+ int getIntVariable(const String &,int);
+ bool getBoolVariable(const String &,int);
+
+
+ void readIf(Stream &,Stream *,int);
+ void readLoop(Stream &,Stream *,int);
+ void readVariable(Stream &,Stream *,int);
+ bool readTemplate(Stream &,Stream *,int);
+ int readCmd(Stream &,Stream *,int);
+
+
+ const char *tmplArgs;
+ String title,refreshURL;
+ char currTag[MAX_TAGLEVEL][MAX_TAGLEN];
+ int tagLevel;
+ int refresh;
+ WriteBufferStream *out;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : http.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// HTTP protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "http.h"
+#include "sys.h"
+#include "common.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+//-----------------------------------------
+bool HTTP::checkResponse(int r)
+{
+ if (readResponse()!=r)
+ {
+ LOG_ERROR("Unexpected HTTP: %s",cmdLine);
+ throw StreamException("Unexpected HTTP response");
+ return false;
+ }
+
+ return true;
+}
+//-----------------------------------------
+void HTTP::readRequest()
+{
+ readLine(cmdLine,sizeof(cmdLine));
+}
+//-----------------------------------------
+int HTTP::readResponse()
+{
+ readLine(cmdLine,sizeof(cmdLine));
+
+ char *cp = cmdLine;
+
+ while (*cp) if (*++cp == ' ') break;
+ while (*cp) if (*++cp != ' ') break;
+
+ char *scp = cp;
+
+ while (*cp) if (*++cp == ' ') break;
+ *cp = 0;
+
+ return atoi(scp);
+}
+
+//-----------------------------------------
+bool HTTP::nextHeader()
+{
+ if (readLine(cmdLine,sizeof(cmdLine)))
+ {
+ char *ap = strstr(cmdLine,":");
+ if (ap)
+ while (*++ap)
+ if (*ap!=' ')
+ break;
+ arg = ap;
+ return true;
+ }else
+ {
+ arg = NULL;
+ return false;
+ }
+
+}
+//-----------------------------------------
+bool HTTP::isHeader(const char *hs)
+{
+ return stristr(cmdLine,hs) != NULL;
+}
+//-----------------------------------------
+bool HTTP::isRequest(const char *rq)
+{
+ return strncmp(cmdLine,rq,strlen(rq)) == 0;
+}
+//-----------------------------------------
+char *HTTP::getArgStr()
+{
+ return arg;
+}
+//-----------------------------------------
+int HTTP::getArgInt()
+{
+ if (arg)
+ return atoi(arg);
+ else
+ return 0;
+}
+//-----------------------------------------
+void HTTP::getAuthUserPass(char *user, char *pass)
+{
+ if (arg)
+ {
+ char *s = stristr(arg,"Basic");
+ if (s)
+ {
+ while (*s)
+ if (*s++ == ' ')
+ break;
+ String str;
+ str.set(s,String::T_BASE64);
+ str.convertTo(String::T_ASCII);
+ s = strstr(str.cstr(),":");
+ if (s)
+ {
+ *s = 0;
+ if (user)
+ strcpy(user,str.cstr());
+ if (pass)
+ strcpy(pass,s+1);
+ }
+ }
+ }
+}
+// -----------------------------------
+void CookieList::init()
+{
+ for(int i=0; i<MAX_COOKIES; i++)
+ list[i].clear();
+
+ neverExpire = false;
+}
+
+// -----------------------------------
+bool CookieList::contains(Cookie &c)
+{
+ if ((c.id[0]) && (c.ip))
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].compare(c))
+ return true;
+
+ return false;
+}
+// -----------------------------------
+void Cookie::logDebug(const char *str, int ind)
+{
+ char ipstr[64];
+ Host h;
+ h.ip = ip;
+ h.IPtoStr(ipstr);
+
+ LOG_DEBUG("%s %d: %s - %s",str,ind,ipstr,id);
+}
+
+// -----------------------------------
+bool CookieList::add(Cookie &c)
+{
+ if (contains(c))
+ return false;
+
+ unsigned int oldestTime=(unsigned int)-1;
+ int oldestIndex=0;
+
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].time <= oldestTime)
+ {
+ oldestIndex = i;
+ oldestTime = list[i].time;
+ }
+
+ c.logDebug("Added cookie",oldestIndex);
+ c.time = sys->getTime();
+ list[oldestIndex]=c;
+ return true;
+}
+// -----------------------------------
+void CookieList::remove(Cookie &c)
+{
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].compare(c))
+ list[i].clear();
+}
--- /dev/null
+// ------------------------------------------------
+// File : http.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+#include "stream.h"
+
+// -------------------------------------
+class HTTPException : public StreamException
+{
+public:
+ HTTPException(const char *m, int c) : StreamException(m) {code=c;}
+ int code;
+};
+
+// --------------------------------------------
+static const char *HTTP_SC_OK = "HTTP/1.0 200 OK";
+static const char *HTTP_SC_NOTFOUND = "HTTP/1.0 404 Not Found";
+static const char *HTTP_SC_UNAVAILABLE = "HTTP/1.0 503 Service Unavailable";
+static const char *HTTP_SC_UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
+static const char *HTTP_SC_FOUND = "HTTP/1.0 302 Found";
+static const char *HTTP_SC_BADREQUEST = "HTTP/1.0 400 Bad Request";
+static const char *HTTP_SC_FORBIDDEN = "HTTP/1.0 403 Forbidden";
+static const char *HTTP_SC_SWITCH = "HTTP/1.0 101 Switch protocols";
+
+static const char *RTSP_SC_OK = "RTSP/1.0 200 OK";
+
+
+static const char *HTTP_PROTO1 = "HTTP/1.";
+static const char *RTSP_PROTO1 = "RTSP/1.";
+
+static const char *HTTP_HS_SERVER = "Server:";
+static const char *HTTP_HS_AGENT = "User-Agent:";
+static const char *HTTP_HS_CONTENT = "Content-Type:";
+static const char *HTTP_HS_CACHE = "Cache-Control:";
+static const char *HTTP_HS_CONNECTION = "Connection:";
+static const char *HTTP_HS_SETCOOKIE = "Set-Cookie:";
+static const char *HTTP_HS_COOKIE = "Cookie:";
+static const char *HTTP_HS_HOST = "Host:";
+static const char *HTTP_HS_ACCEPT = "Accept:";
+static const char *HTTP_HS_LENGTH = "Content-Length:";
+
+static const char *MIME_MP3 = "audio/mpeg";
+static const char *MIME_XMP3 = "audio/x-mpeg";
+static const char *MIME_OGG = "application/ogg";
+static const char *MIME_XOGG = "application/x-ogg";
+static const char *MIME_MOV = "video/quicktime";
+static const char *MIME_MPG = "video/mpeg";
+static const char *MIME_NSV = "video/nsv";
+static const char *MIME_ASF = "video/x-ms-asf";
+static const char *MIME_ASX = "video/x-ms-asf"; // same as ASF
+static const char *MIME_MMS = "application/x-mms-framed";
+
+static const char *MIME_RAM = "audio/x-pn-realaudio";
+
+
+static const char *MIME_WMA = "audio/x-ms-wma";
+static const char *MIME_WMV = "video/x-ms-wmv";
+
+static const char *MIME_HTML = "text/html";
+static const char *MIME_XML = "text/xml";
+static const char *MIME_CSS = "text/css";
+static const char *MIME_TEXT = "text/plain";
+static const char *MIME_PLS = "audio/mpegurl";
+static const char *MIME_XPLS = "audio/x-mpegurl";
+static const char *MIME_XSCPLS = "audio/x-scpls";
+static const char *MIME_SDP = "application/sdp";
+static const char *MIME_M3U = "audio/m3u";
+static const char *MIME_MPEGURL = "audio/mpegurl";
+static const char *MIME_XM3U = "audio/x-mpegurl";
+static const char *MIME_XPEERCAST = "application/x-peercast";
+static const char *MIME_XPCP = "application/x-peercast-pcp";
+static const char *MIME_RAW = "application/binary";
+static const char *MIME_JPEG = "image/jpeg";
+static const char *MIME_GIF = "image/gif";
+static const char *MIME_PNG = "image/png";
+
+
+// --------------------------------------------
+class Cookie
+{
+public:
+ Cookie()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ time = 0;
+ ip = 0;
+ id[0]=0;
+ }
+
+ void set(const char *i, unsigned int nip)
+ {
+ strncpy(id,i,sizeof(id)-1);
+ id[sizeof(id)-1]=0;
+ ip = nip;
+ }
+ bool compare(Cookie &c)
+ {
+ if (c.ip == ip)
+ if (strcmp(c.id,id)==0)
+ return true;
+
+ return false;
+ }
+
+ void logDebug(const char *,int);
+
+ unsigned int ip;
+ char id[64];
+ unsigned int time;
+};
+
+// --------------------------------------------
+class CookieList
+{
+public:
+ enum {
+ MAX_COOKIES = 32
+ };
+
+
+
+ void init();
+ bool add(Cookie &);
+ void remove(Cookie &);
+ bool contains(Cookie &);
+
+
+ Cookie list[MAX_COOKIES];
+ bool neverExpire;
+
+};
+
+// --------------------------------------------
+class HTTP : public IndirectStream
+{
+public:
+ HTTP(Stream &s)
+ {
+ init(&s);
+ }
+
+ void initRequest(const char *r)
+ {
+ strcpy(cmdLine,r);
+ }
+ void readRequest();
+ bool isRequest(const char *);
+
+ int readResponse();
+ bool checkResponse(int);
+
+ bool nextHeader();
+ bool isHeader(const char *);
+ char *getArgStr();
+ int getArgInt();
+
+ void getAuthUserPass(char *, char *);
+
+ char cmdLine[8192],*arg;
+
+};
+
+#endif
--- /dev/null
+#include "icy.h"
+#include "socket.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void ICYSource::stream(Channel *ch)
+{
+ ChannelStream *source=NULL;
+ try
+ {
+
+ if (!ch->sock)
+ throw StreamException("ICY channel has no socket");
+
+ ch->resetPlayTime();
+
+ ch->setStatus(Channel::S_BROADCASTING);
+ source = ch->createSource();
+ ch->readStream(*ch->sock,source);
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Channel aborted: %s",e.msg);
+ }
+
+
+ ch->setStatus(Channel::S_CLOSING);
+
+ if (ch->sock)
+ {
+ ch->sock->close();
+ delete ch->sock;
+ ch->sock = NULL;
+ }
+
+ if (source)
+ delete source;
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : icy.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ICY_H
+#define _ICY_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class ICYSource : public ChannelSource
+{
+public:
+ virtual void stream(Channel *);
+
+};
+
+
+
+
+#endif
--- /dev/null
+#ifndef _ID_H
+#define _ID_H
+
+#include <string.h>
+
+// ---------------------------------------------------
+class IDString
+{
+private:
+ enum
+ {
+ LENGTH = 31
+ };
+
+ char data[LENGTH+1];
+public:
+ IDString(const char *id,int cnt)
+ {
+ if (cnt >= LENGTH)
+ cnt=LENGTH;
+ int i;
+ for(i=0; i<cnt; i++)
+ data[i]=id[i];
+ data[i]=0;
+ }
+
+ operator const char *()
+ {
+ return str();
+ }
+
+ const char *str() {return data;}
+
+};
+
+
+
+
+// ---------------------------------------------------
+class ID4
+{
+private:
+ union
+ {
+ int iv;
+ char cv[4];
+ };
+
+public:
+
+ ID4()
+ : iv( 0 )
+ {
+ }
+
+ ID4(int i)
+ :iv(i)
+ {
+ }
+
+ ID4(const char *id)
+ :iv(0)
+ {
+ if (id)
+ for(int i=0; i<4; i++)
+ if ((cv[i]=id[i])==0)
+ break;
+ }
+
+ void clear()
+ {
+ iv = 0;
+ }
+
+ operator int() const
+ {
+ return iv;
+ }
+
+ int operator == (ID4 id) const
+ {
+ return iv==id.iv;
+ }
+ int operator != (ID4 id) const
+ {
+ return iv!=id.iv;
+ }
+
+ bool isSet() const {return iv!=0;}
+
+
+ int getValue() const {return iv;}
+ IDString getString() const {return IDString(cv,4);}
+ void *getData() {return cv;}
+
+};
+
+
+
+
+#endif
--- /dev/null
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95¶\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95¶\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24 Remove static variables
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14 First version
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "identify_encoding.h"
+
+enum encoding_id
+{
+ eid_KNOWN = 0,
+ eid_ASCII = 1,
+ eid_JIS = 2,
+ eid_SJIS = 3,
+ eid_EUCJP = 4,
+ eid_UTF8 = 5
+};
+
+const char *encoding_str[] =
+{
+ "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8"
+};
+
+static int
+is_ascii(ie_state_t *st, const unsigned char *p)
+{
+ if (!(isprint(*p) || isspace(*p)) || *p >= 0x80)
+ st->flag = 0;
+ return st->flag;
+}
+
+static int
+is_jis(ie_state_t *st, const unsigned char *p)
+{
+ if (*p >= 0x80)
+ st->flag = 0;
+ return st->flag;
+}
+
+static int
+is_sjis(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0x81 && *p <= 0x9f) st->c_type = 1;
+ else if (*p >= 0xe0 && *p <= 0xef) st->c_type = 1;
+ else if (*p >= 0xa1 && *p <= 0xdf) st->state = 0;
+ else st->flag = 1;
+ }
+ break;
+ case 1:
+ if (*p >= 0x40 && *p <= 0x7e) st->state = 0;
+ else if (*p >= 0x80 && *p <= 0xfc) st->state = 0;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+static int
+is_eucjp(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0xa1 && *p <= 0xfe) st->c_type = 1;
+ else if (*p == 0x8e ) st->c_type = 2;
+ else if (*p == 0x8f ) st->c_type = 3;
+ else st->flag = 0;
+ }
+ break;
+ case 1:
+ switch (st->c_type)
+ {
+ case 1:
+ if (*p >= 0xa1 && *p <= 0xfe) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 2:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 3:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 2;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+ break;
+ case 2:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 0;
+ else st->flag = 0;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+static int
+is_utf8(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0xc2 && *p <= 0xdf) st->c_type = 1;
+ else if (*p == 0xe0 ) st->c_type = 2;
+ else if (*p >= 0xe1 && *p <= 0xef) st->c_type = 3;
+ else if (*p == 0xf0 ) st->c_type = 4;
+ else if (*p >= 0xf1 && *p <= 0xf3) st->c_type = 5;
+ else if (*p == 0xf4 ) st->c_type = 6;
+ else st->flag = 0;
+ }
+ break;
+ case 1:
+ switch (st->c_type)
+ {
+ case 1:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 2:
+ if (*p >= 0xa0 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 3:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 4:
+ if (*p >= 0x90 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 5:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 6:
+ if (*p >= 0x80 && *p <= 0x8f) st->state = 2;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+ break;
+ case 2:
+ if (st->c_type >= 2 && st->c_type <= 3)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ }else if (st->c_type >= 4 && st->c_type <= 6)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 3;
+ else st->flag = 0;
+ }else{
+ st->flag = 0;
+ }
+ break;
+ case 3:
+ if (st->c_type >= 4 && st->c_type <= 6)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ }else{
+ st->flag = 0;
+ }
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+identify_encoding_t*
+identify_encoding_open(enum identify_encoding_order order)
+{
+ identify_encoding_t* cd;
+ cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t));
+
+ if (cd == NULL)
+ {
+ cd = (identify_encoding_t*)(-1);
+ }else{
+ cd->order = order;
+ identify_encoding_reset(cd);
+ }
+ return cd;
+}
+
+void
+identify_encoding_close(identify_encoding_t* cd)
+{
+ if (cd != (identify_encoding_t*)(-1) || cd != NULL)
+ {
+ free(cd);
+ }
+}
+
+static void
+identify_encoding_reset_state(ie_state_t* st)
+{
+ st->flag = 1;
+ st->state = 0;
+ st->c_type = 0;
+}
+
+void
+identify_encoding_reset(identify_encoding_t* cd)
+{
+ identify_encoding_reset_state(&(cd->st_ascii));
+ identify_encoding_reset_state(&(cd->st_jis));
+ identify_encoding_reset_state(&(cd->st_sjis));
+ identify_encoding_reset_state(&(cd->st_eucjp));
+ identify_encoding_reset_state(&(cd->st_utf8));
+}
+
+const char*
+identify_encoding(identify_encoding_t *cd, char* instr)
+{
+ int n;
+ unsigned char *p;
+ enum encoding_id eid = eid_KNOWN;
+
+ identify_encoding_reset(cd);
+
+ for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++)
+ {
+ if (cd->st_ascii.flag == 1) is_ascii(&(cd->st_ascii), p);
+ if (cd->st_jis.flag == 1) is_jis(&(cd->st_jis), p);
+ if (cd->st_sjis.flag == 1) is_sjis(&(cd->st_sjis), p);
+ if (cd->st_eucjp.flag == 1) is_eucjp(&(cd->st_eucjp), p);
+ if (cd->st_utf8.flag == 1) is_utf8(&(cd->st_utf8), p);
+ }
+
+ if (cd->st_ascii.flag == 1) eid = eid_ASCII;
+ else if (cd->st_jis.flag == 1) eid = eid_JIS;
+ else if (cd->st_utf8.flag == 1) eid = eid_UTF8;
+ else if (cd->order == ieo_EUCJP)
+ {
+ if (cd->st_eucjp.flag == 1) eid = eid_EUCJP;
+ else if (cd->st_sjis.flag == 1) eid = eid_SJIS;
+ }else{
+ if (cd->st_sjis.flag == 1) eid = eid_SJIS;
+ else if (cd->st_eucjp.flag == 1) eid = eid_EUCJP;
+ }
+
+ return encoding_str[ eid ];
+}
--- /dev/null
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95¶\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95¶\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24 Remove static variables
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14 First version
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#ifndef IDENTIFY_ENCODING_H
+#define IDENTIFY_ENCODING_H
+
+#define IDENTIFY_MAX_LENGTH 256
+
+enum identify_encoding_order {
+ ieo_EUCJP = 0,
+ ieo_SJIS = 1
+};
+
+typedef struct {
+ int flag;
+ int state;
+ int c_type;
+} ie_state_t;
+
+typedef struct {
+ enum identify_encoding_order order;
+ ie_state_t st_ascii;
+ ie_state_t st_jis;
+ ie_state_t st_sjis;
+ ie_state_t st_eucjp;
+ ie_state_t st_utf8;
+} identify_encoding_t;
+
+identify_encoding_t* identify_encoding_open(enum identify_encoding_order order);
+void identify_encoding_close(identify_encoding_t* cd);
+void identify_encoding_reset(identify_encoding_t* cd);
+const char *identify_encoding(identify_encoding_t *cd, char* instr);
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : inifile.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// .INI file reading/writing class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "inifile.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+ void openReadOnly(const char *);
+ void openWriteReplace(const char *);
+// -----------------------------------------
+bool IniFile::openReadOnly(const char *fn)
+{
+ try
+ {
+ fStream.openReadOnly(fn);
+ }catch(StreamException &)
+ {
+ return false;
+ }
+ return true;
+}
+// -----------------------------------------
+bool IniFile::openWriteReplace(const char *fn)
+{
+ try
+ {
+ fStream.openWriteReplace(fn);
+#if defined(_LINUX) || defined(__APPLE__)
+ fStream.writeCRLF = false;
+#endif
+
+ }catch(StreamException &)
+ {
+ return false;
+ }
+ return true;
+}
+// -----------------------------------------
+void IniFile::close()
+{
+ fStream.close();
+}
+
+
+// -----------------------------------------
+bool IniFile::readNext()
+{
+ if (fStream.eof())
+ return false;
+
+ try
+ {
+ fStream.readLine(currLine,256);
+ }catch(StreamException &)
+ {
+ return false;
+ }
+
+
+ // find end of value name and null terminate
+ char *nend = strstr(currLine,"=");
+
+ if (nend)
+ {
+ *nend = 0;
+ valueStr = trimstr(nend+1);
+ }else
+ valueStr = NULL;
+
+ nameStr = trimstr(currLine);
+
+ return true;
+}
+// -----------------------------------------
+bool IniFile::isName(const char *str)
+{
+ return stricmp(getName(),str)==0;
+}
+
+// -----------------------------------------
+char * IniFile::getName()
+{
+ return nameStr;
+}
+// -----------------------------------------
+int IniFile::getIntValue()
+{
+ if (valueStr)
+ return atoi(valueStr);
+ else
+ return 0;
+}
+// -----------------------------------------
+char * IniFile::getStrValue()
+{
+ if (valueStr)
+ return valueStr;
+ else
+ return "";
+}
+// -----------------------------------------
+bool IniFile::getBoolValue()
+{
+ if (!valueStr)
+ return false;
+
+
+ if ( (stricmp(valueStr,"yes")==0) ||
+ (stricmp(valueStr,"y")==0) ||
+ (stricmp(valueStr,"1")==0) )
+ return true;
+
+ return false;
+}
+
+// -----------------------------------------
+void IniFile::writeIntValue(const char *name, int iv)
+{
+ sprintf(currLine,"%s = %d",name,iv);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeStrValue(const char *name, const char *sv)
+{
+ sprintf(currLine,"%s = %s",name,sv);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeSection(const char *name)
+{
+ fStream.writeLine("");
+ sprintf(currLine,"[%s]",name);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeBoolValue(const char *name, int v)
+{
+ sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No");
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeLine(const char *str)
+{
+ fStream.writeLine(str);
+}
--- /dev/null
+// ------------------------------------------------
+// File : inifile.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _INIFILE
+#define _INIFILE
+
+#include "stream.h"
+
+// -----------------------------------------
+class IniFile
+{
+public:
+ bool openReadOnly(const char *);
+ bool openWriteReplace(const char *);
+ void close();
+
+ bool readNext();
+
+ bool isName(const char *);
+ char * getName();
+ int getIntValue();
+ char * getStrValue();
+ bool getBoolValue();
+
+ void writeSection(const char *);
+ void writeIntValue(const char *, int);
+ void writeStrValue(const char *, const char *);
+ void writeBoolValue(const char *, int);
+ void writeLine(const char *);
+
+
+ FileStream fStream;
+ char currLine[256];
+ char *nameStr,*valueStr;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : jis.cpp
+// Date: 1-april-2004
+// Author: giles
+//
+// ShiftJIS/EUC to Unicode conversions
+// (modified version of program by Y. Kuno, see below)
+//
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+/* J2Uc.c --- written by Y. Kuno, July 1996. */
+/* Compile with -DSJIS if you want to convert from SJIS; otherwise */
+/* EUC-JP is assumed. */
+/* We are thankful to following people for permitting us free use */
+/* of the following materials. */
+/* * Itaru Ichikawa (Fujitsu) --- nkf 1.4 source code. */
+/* * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */
+/* This source code can freely be used, distributed, modified provided */
+/* that this credit is also included in the source code. */
+
+// -----------------------------------
+
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// -----------------------------------
+
+#define SJ0162 0x00e1 /* 01 - 62 ku offset */
+#define SJ6394 0x0161 /* 63 - 94 ku offset */
+
+
+// -----------------------------------
+static unsigned short uniTable[94][94] = {
+{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,
+ 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,
+ 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230,
+ 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,
+ 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,
+ 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,
+ 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283,
+ 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,},
+{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,
+ 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835,
+ 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0,
+ 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811,
+ 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837,
+ 9834,8224,8225,182,0,0,0,0,9711,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302,
+ 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319,
+ 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,
+ 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347,
+ 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,
+ 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,},
+{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,
+ 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,
+ 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,
+ 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,
+ 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,
+ 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,
+ 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,
+ 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,
+ 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,
+ 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,
+ 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,
+ 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,
+ 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,
+ 12533,12534,0,0,0,0,0,0,0,0,},
+{913,914,915,916,917,918,919,920,921,922,923,924,
+ 925,926,927,928,929,931,932,933,934,935,936,937,0,
+ 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954,
+ 955,956,957,958,959,960,961,963,964,965,966,967,
+ 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,
+ 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,
+ 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,
+ 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,
+ 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,},
+{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,
+ 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,
+ 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,
+ 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,
+ 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,
+ 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,
+ 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,
+ 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,
+ 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,
+ 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,},
+{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,
+ 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,
+ 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,
+ 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,
+ 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,
+ 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,
+ 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,
+ 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,},
+{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,
+ 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,
+ 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,
+ 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,
+ 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,
+ 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,
+ 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,
+ 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,},
+{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,
+ 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,
+ 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,
+ 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,
+ 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,
+ 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,
+ 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,
+ 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,},
+{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,
+ 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,
+ 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,
+ 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,
+ 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,
+ 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,
+ 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,
+ 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,},
+{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,
+ 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,
+ 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,
+ 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,
+ 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,
+ 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,
+ 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,
+ 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,},
+{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,
+ 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,
+ 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,
+ 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,
+ 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,
+ 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,
+ 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,
+ 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,},
+{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,
+ 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,
+ 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,
+ 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,
+ 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,
+ 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,
+ 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,
+ 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,},
+{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,
+ 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,
+ 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,
+ 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,
+ 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,
+ 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,
+ 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,
+ 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,},
+{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,
+ 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,
+ 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,
+ 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,
+ 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,
+ 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,
+ 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,
+ 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,},
+{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,
+ 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,
+ 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,
+ 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,
+ 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,
+ 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,
+ 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,
+ 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,},
+{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,
+ 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,
+ 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,
+ 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,
+ 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,
+ 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,
+ 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,
+ 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,},
+{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,
+ 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,
+ 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,
+ 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,
+ 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,
+ 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,
+ 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,
+ 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,},
+{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,
+ 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,
+ 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,
+ 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,
+ 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,
+ 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,
+ 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,
+ 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,},
+{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,
+ 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,
+ 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,
+ 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,
+ 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,
+ 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,
+ 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,
+ 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,},
+{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,
+ 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,
+ 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,
+ 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,
+ 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,
+ 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,
+ 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,
+ 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,},
+{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,
+ 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,
+ 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,
+ 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,
+ 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,
+ 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,
+ 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,
+ 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,},
+{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,
+ 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,
+ 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,
+ 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,
+ 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,
+ 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,
+ 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,
+ 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,},
+{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,
+ 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,
+ 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,
+ 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,
+ 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,
+ 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,
+ 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,
+ 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,},
+{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,
+ 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,
+ 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,
+ 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,
+ 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,
+ 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,
+ 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,
+ 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,},
+{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,
+ 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,
+ 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,
+ 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,
+ 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,
+ 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,
+ 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,
+ 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,},
+{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,
+ 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,
+ 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,
+ 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,
+ 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,
+ 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,
+ 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,
+ 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,},
+{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,
+ 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,
+ 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,
+ 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,
+ 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,
+ 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,
+ 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,
+ 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,},
+{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,
+ 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,
+ 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,
+ 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,
+ 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,
+ 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,
+ 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,
+ 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,},
+{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,
+ 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,
+ 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,
+ 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,
+ 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,
+ 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,
+ 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,
+ 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,},
+{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,
+ 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,
+ 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,
+ 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,
+ 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,
+ 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,
+ 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,
+ 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,},
+{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,
+ 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,
+ 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,
+ 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,
+ 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,
+ 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,
+ 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,
+ 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,},
+{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,
+ 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,
+ 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,
+ 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,
+ 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,
+ 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,
+ 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,
+ 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,},
+{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,
+ 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,
+ 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,
+ 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,
+ 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,
+ 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,
+ 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,
+ 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,},
+{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,
+ 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,
+ 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,
+ 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,
+ 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,
+ 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,
+ 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,
+ 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,},
+{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,
+ 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,
+ 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,
+ 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,
+ 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,
+ 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,
+ 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,
+ 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,},
+{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,
+ 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,
+ 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,
+ 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,
+ 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,
+ 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,
+ 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,
+ 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,
+ 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,
+ 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,
+ 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,
+ 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,},
+{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,
+ 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,
+ 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,
+ 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,
+ 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,
+ 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,
+ 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,
+ 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,},
+{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,
+ 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,
+ 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,
+ 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,
+ 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,
+ 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,
+ 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,
+ 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,},
+{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,
+ 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,
+ 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,
+ 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,
+ 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,
+ 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,
+ 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,
+ 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,},
+{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,
+ 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,
+ 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,
+ 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,
+ 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,
+ 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,
+ 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,
+ 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,},
+{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,
+ 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,
+ 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,
+ 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,
+ 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,
+ 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,
+ 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,
+ 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,},
+{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,
+ 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,
+ 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,
+ 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,
+ 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,
+ 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,
+ 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,
+ 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,},
+{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,
+ 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,
+ 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,
+ 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,
+ 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,
+ 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,
+ 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,
+ 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,},
+{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,
+ 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,
+ 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,
+ 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,
+ 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,
+ 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,
+ 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,
+ 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,},
+{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,
+ 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,
+ 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,
+ 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,
+ 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,
+ 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,
+ 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,
+ 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,},
+{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,
+ 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,
+ 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,
+ 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,
+ 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,
+ 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,
+ 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,
+ 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,},
+{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,
+ 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,
+ 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,
+ 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,
+ 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,
+ 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,
+ 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,
+ 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,},
+{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,
+ 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,
+ 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,
+ 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,
+ 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,
+ 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,
+ 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,
+ 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,},
+{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,
+ 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,
+ 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,
+ 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,
+ 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,
+ 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,
+ 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,
+ 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,},
+{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,
+ 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,
+ 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,
+ 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,
+ 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,
+ 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,
+ 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,
+ 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,},
+{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,
+ 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,
+ 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,
+ 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,
+ 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,
+ 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,
+ 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,
+ 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,},
+{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,
+ 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,
+ 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,
+ 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,
+ 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,
+ 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,
+ 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,
+ 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,},
+{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,
+ 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,
+ 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,
+ 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,
+ 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,
+ 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,
+ 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,
+ 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,},
+{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,
+ 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,
+ 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,
+ 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,
+ 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,
+ 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,
+ 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,
+ 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,},
+{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,
+ 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,
+ 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,
+ 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,
+ 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,
+ 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,
+ 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,
+ 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,},
+{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,
+ 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,
+ 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,
+ 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,
+ 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,
+ 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,
+ 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,
+ 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,},
+{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,
+ 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,
+ 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,
+ 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,
+ 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,
+ 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,
+ 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,
+ 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,},
+{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,
+ 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,
+ 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,
+ 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,
+ 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,
+ 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,
+ 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,
+ 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,},
+{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,
+ 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,
+ 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,
+ 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,
+ 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,
+ 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,
+ 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,
+ 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,},
+{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,
+ 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,
+ 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,
+ 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,
+ 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,
+ 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,
+ 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,
+ 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,},
+{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,
+ 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,
+ 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,
+ 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,
+ 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,
+ 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,
+ 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,
+ 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,},
+{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,
+ 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,
+ 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,
+ 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,
+ 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,
+ 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,
+ 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,
+ 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,},
+{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,
+ 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,
+ 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,
+ 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,
+ 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,
+ 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,
+ 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,
+ 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,},
+{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,
+ 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,
+ 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,
+ 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,
+ 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,
+ 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,
+ 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,
+ 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,},
+{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,
+ 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,
+ 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,
+ 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,
+ 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,
+ 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,
+ 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,
+ 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,},
+{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,
+ 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,
+ 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,
+ 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,
+ 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,
+ 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,
+ 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,
+ 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,},
+{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,
+ 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,
+ 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,
+ 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,
+ 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,
+ 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,
+ 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,
+ 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,},
+{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,
+ 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,
+ 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,
+ 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,
+ 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,
+ 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,
+ 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,
+ 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,},
+{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,
+ 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,
+ 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,
+ 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,
+ 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,
+ 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,
+ 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,
+ 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,},
+{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,
+ 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,
+ 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,
+ 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,
+ 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,
+ 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,
+ 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,
+ 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,},
+{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,
+ 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,
+ 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,
+ 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,
+ 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,
+ 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,
+ 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,
+ 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,},
+{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+};
+
+
+// ------------------------------------------------------------
+unsigned short JISConverter::sjisToUnicode(unsigned short sjis)
+{
+ unsigned short u;
+ unsigned int c = sjis>>8;
+ unsigned int c1 = sjis&0xff;
+
+ c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394);
+ if(c1 < 0x9f)
+ {
+ c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f);
+ }
+ else
+ {
+ c1 = c1 - 0x7e; c++;
+ }
+ c -= 33;
+ c1 -= 33;
+ if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+ u = 0x3013;
+ else
+ {
+ u = uniTable[c][c1];
+ if(!u)
+ u = 0x3013;
+ }
+
+ return u;
+}
+// ------------------------------------------------------------
+unsigned short JISConverter::eucToUnicode(unsigned short euc)
+{
+ unsigned short u;
+ unsigned int c = euc>>8;
+ unsigned int c1 = euc&0xff;
+
+ c &= 0x7f;
+ c -= 33;
+ c1 &= 0x7f;
+ c1 -= 33;
+ if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+ u = 0x3013;
+ else
+ {
+ u = uniTable[c][c1];
+ if(!u)
+ u = 0x3013;
+ }
+ return u;
+}
--- /dev/null
+// ------------------------------------------------
+// File : jis.h
+// Date: 1-april-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _JIS_H
+#define _JIS_H
+
+// ----------------------------------
+class JISConverter
+{
+public:
+
+ static unsigned short sjisToUnicode(unsigned short);
+ static unsigned short eucToUnicode(unsigned short);
+};
+
+
+
+#endif
+
+
--- /dev/null
+// ------------------------------------------------
+// File : mms.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mms.h"
+#include "asf.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+ASFInfo parseASFHeader(Stream &in);
+
+
+// ------------------------------------------
+void MMSStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MMSStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MMSStream::readPacket(Stream &in,Channel *ch)
+{
+ {
+ ASFChunk chunk;
+
+ chunk.read(in);
+
+ switch (chunk.type)
+ {
+ case 0x4824: // asf header
+ {
+ MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data));
+
+ chunk.write(mem);
+
+
+
+
+ MemoryStream asfm(chunk.data,chunk.dataLen);
+ ASFObject asfHead;
+ asfHead.readHead(asfm);
+
+ ASFInfo asf = parseASFHeader(asfm);
+ LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate);
+ for(int i=0; i<ASFInfo::MAX_STREAMS; i++)
+ {
+ ASFStream *s = &asf.streams[i];
+ if (s->id)
+ LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate);
+ }
+
+ ch->info.bitrate = asf.bitrate/1000;
+
+ ch->headPack.type = ChanPacket::T_HEAD;
+ ch->headPack.len = mem.pos;
+ ch->headPack.pos = ch->streamPos;
+ ch->newPacket(ch->headPack);
+
+ ch->streamPos += ch->headPack.len;
+
+ break;
+ }
+ case 0x4424: // asf data
+ {
+
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack.data));
+
+ chunk.write(mem);
+
+ pack.type = ChanPacket::T_DATA;
+ pack.len = mem.pos;
+ pack.pos = ch->streamPos;
+
+ ch->newPacket(pack);
+ ch->streamPos += pack.len;
+
+ break;
+ }
+ default:
+ throw StreamException("Unknown ASF chunk");
+
+ }
+
+ }
+ return 0;
+}
+
+
+// -----------------------------------
+ASFInfo parseASFHeader(Stream &in)
+{
+ ASFInfo asf;
+
+ try
+ {
+ int numHeaders = in.readLong();
+
+ in.readChar();
+ in.readChar();
+
+ LOG_CHANNEL("ASF Headers: %d",numHeaders);
+ for(int i=0; i<numHeaders; i++)
+ {
+
+ ASFObject obj;
+
+ unsigned int l = obj.readHead(in);
+ obj.readData(in,l);
+
+
+ MemoryStream data(obj.data,obj.lenLo);
+
+
+ switch (obj.type)
+ {
+ case ASFObject::T_FILE_PROP:
+ {
+ data.skip(32);
+
+ unsigned int dpLo = data.readLong();
+ unsigned int dpHi = data.readLong();
+
+ data.skip(24);
+
+ data.readLong();
+ //data.writeLong(1); // flags = broadcast, not seekable
+
+ int min = data.readLong();
+ int max = data.readLong();
+ int br = data.readLong();
+
+ if (min != max)
+ throw StreamException("ASF packetsizes (min/max) must match");
+
+ asf.packetSize = max;
+ asf.bitrate = br;
+ asf.numPackets = dpLo;
+ break;
+ }
+ case ASFObject::T_STREAM_BITRATE:
+ {
+ int cnt = data.readShort();
+ for(int i=0; i<cnt; i++)
+ {
+ unsigned int id = data.readShort();
+ int bitrate = data.readLong();
+ if (id < ASFInfo::MAX_STREAMS)
+ asf.streams[id].bitrate = bitrate;
+ }
+ break;
+ }
+ case ASFObject::T_STREAM_PROP:
+ {
+ ASFStream s;
+ s.read(data);
+ asf.streams[s.id].id = s.id;
+ asf.streams[s.id].type = s.type;
+ break;
+ }
+ }
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("ASF: %s",e.msg);
+ }
+
+ return asf;
+}
+
+
--- /dev/null
+// ------------------------------------------------
+// File : mms.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MMS_H
+#define _MMS_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MMSStream : public ChannelStream
+{
+public:
+
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mp3.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// ------------------------------------------
+void MP3Stream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MP3Stream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MP3Stream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ if (ch->icyMetaInterval)
+ {
+
+ int rlen = ch->icyMetaInterval;
+
+ while (rlen)
+ {
+ int rl = rlen;
+ if (rl > ChanMgr::MAX_METAINT)
+ rl = ChanMgr::MAX_METAINT;
+
+ pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+ ch->streamPos+=pack.len;
+
+ rlen-=rl;
+ }
+
+ unsigned char len;
+ in.read(&len,1);
+ if (len)
+ {
+ if (len*16 > 1024) len = 1024/16;
+ char buf[1024];
+ in.read(buf,len*16);
+ ch->processMp3Metadata(buf);
+ }
+
+ }else{
+
+ pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos += pack.len;
+ }
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : mp3.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MP3_H
+#define _MP3_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MP3Stream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : nsv.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "nsv.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void NSVStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void NSVStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int NSVStream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ if (ch->icyMetaInterval)
+ {
+
+ int rlen = ch->icyMetaInterval;
+
+ while (rlen)
+ {
+ int rl = rlen;
+ if (rl > ChanMgr::MAX_METAINT)
+ rl = ChanMgr::MAX_METAINT;
+
+ pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+ ch->streamPos+=pack.len;
+
+ rlen-=rl;
+ }
+
+ unsigned char len;
+ in.read(&len,1);
+ if (len)
+ {
+ if (len*16 > 1024) len = 1024/16;
+ char buf[1024];
+ in.read(buf,len*16);
+ ch->processMp3Metadata(buf);
+ }
+
+ }else{
+
+ pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos += pack.len;
+ }
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : nsv.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _NSV_H
+#define _NSV_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class NSVStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "ogg.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+static int test=0;
+// ------------------------------------------
+void OGGStream::readHeader(Stream &,Channel *)
+{
+ test = 0;
+}
+
+// ------------------------------------------
+void OGGStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int OGGStream::readPacket(Stream &in,Channel *ch)
+{
+ OggPage ogg;
+ ChanPacket pack;
+
+ ogg.read(in);
+
+ if (ogg.isBOS())
+ {
+ if (!vorbis.needHeader() && !theora.needHeader())
+ {
+ ch->headPack.len = 0;
+ }
+
+ if (ogg.detectVorbis())
+ vorbis.bos(ogg.getSerialNo());
+ if (ogg.detectTheora())
+ theora.bos(ogg.getSerialNo());
+ }
+
+ if (ogg.isEOS())
+ {
+
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ {
+ LOG_CHANNEL("Vorbis stream: EOS");
+ vorbis.eos();
+ }
+ if (ogg.getSerialNo() == theora.serialNo)
+ {
+ LOG_CHANNEL("Theora stream: EOS");
+ theora.eos();
+ }
+ }
+
+ if (vorbis.needHeader() || theora.needHeader())
+ {
+
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ vorbis.readHeader(ch,ogg);
+ else if (ogg.getSerialNo() == theora.serialNo)
+ theora.readHeader(ch,ogg);
+ else
+ throw StreamException("Bad OGG serial no.");
+
+
+ if (!vorbis.needHeader() && !theora.needHeader())
+ {
+
+ ch->info.bitrate = 0;
+
+ if (vorbis.isActive())
+ ch->info.bitrate += vorbis.bitrate;
+
+ if (theora.isActive())
+ {
+ ch->info.bitrate += theora.bitrate;
+ ch->info.contentType = ChanInfo::T_OGM;
+ }
+
+
+ ch->headPack.type = ChanPacket::T_HEAD;
+ ch->headPack.pos = ch->streamPos;
+
+ ch->startTime = sys->getDTime();
+
+ ch->streamPos += ch->headPack.len;
+
+ ch->newPacket(ch->headPack);
+ LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len);
+ }
+
+ }else
+ {
+
+
+ pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos);
+ ch->newPacket(pack);
+
+ ch->streamPos+=pack.len;
+
+ if (theora.isActive())
+ {
+ if (ogg.getSerialNo() == theora.serialNo)
+ {
+ ch->sleepUntil(theora.getTime(ogg));
+ }
+ }else if (vorbis.isActive())
+ {
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ {
+ ch->sleepUntil(vorbis.getTime(ogg));
+ }
+ }
+
+ }
+ return 0;
+}
+
+// -----------------------------------
+void OggSubStream::readHeader(Channel *ch,OggPage &ogg)
+{
+ if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN)
+ throw StreamException("OGG packet too big");
+
+ if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN)
+ throw StreamException("OGG packet too big for headMeta");
+
+// copy complete packet into head packet
+ memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen);
+ ch->headPack.len += ogg.headLen+ogg.bodyLen;
+
+ // add body to packet
+ memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen);
+ pack.bodyLen += ogg.bodyLen;
+
+ pack.addLacing(ogg);
+
+ if (pack.numPackets >= maxHeaders)
+ procHeaders(ch);
+
+}
+// -----------------------------------
+void OggVorbisSubStream::procHeaders(Channel *ch)
+{
+ unsigned int packPtr=0;
+
+ for(int i=0; i<pack.numPackets; i++)
+ {
+ MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+ packPtr += pack.packetSizes[i];
+
+ char id[8];
+
+ vin.read(id,7);
+ id[7]=0;
+
+ switch (id[0])
+ {
+ case 1: // ident
+ LOG_CHANNEL("OGG Vorbis Header: Ident (%d bytes)",vin.len);
+ readIdent(vin,ch->info);
+ break;
+ case 3: // comment
+ {
+ LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len);
+ ChanInfo newInfo = ch->info;
+ readComment(vin,newInfo);
+ ch->updateInfo(newInfo);
+ }
+ break;
+ case 5: // setup
+ LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len);
+ //readSetup(vin);
+ break;
+ default:
+ throw StreamException("Unknown Vorbis packet header type");
+ break;
+ }
+ }
+
+}
+// -----------------------------------
+double OggTheoraSubStream::getTime(OggPage &ogg)
+{
+ int64_t iframe=ogg.granPos>>granposShift;
+ int64_t pframe=ogg.granPos-(iframe<<granposShift);
+
+ return (iframe+pframe)*frameTime;
+}
+// -----------------------------------
+void OggTheoraSubStream::readInfo(Stream &in, ChanInfo &info)
+{
+ int verMaj = in.readBits(8);
+ int verMin = in.readBits(8);
+ int verSub = in.readBits(8);
+
+ int encWidth = in.readBits(16) << 4;
+ int encHeight = in.readBits(16) << 4;
+
+ in.readBits(24+24+8+8);
+
+ int fpsNum = in.readBits(32);
+ int fpsDen = in.readBits(32);
+
+ float fps = (float)fpsNum/(float)fpsDen;
+ frameTime = (double)fpsDen/(double)fpsNum;
+
+ in.readBits(24+24+8);
+
+ bitrate = in.readBits(24) / 1000;
+ int quality = in.readBits(6);
+
+ granposShift = in.readBits(5);
+
+ LOG_CHANNEL("OGG Theora Info: %dx%dx%.1ffps %dkbps %dQ %dG",encWidth,encHeight,fps,bitrate,quality,granposShift);
+
+
+}
+// -----------------------------------
+void OggTheoraSubStream::procHeaders(Channel *ch)
+{
+ unsigned int packPtr=0;
+
+ for(int i=0; i<pack.numPackets; i++)
+ {
+ MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+ packPtr += pack.packetSizes[i];
+
+ unsigned char id[8];
+
+ vin.read(id,7);
+ id[7]=0;
+
+ switch (id[0] & 0xff)
+ {
+ case 128: // info
+ LOG_CHANNEL("OGG Theora Header: Info (%d bytes)",vin.len);
+ readInfo(vin,ch->info);
+ break;
+ default:
+ LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len);
+ break;
+ }
+
+
+
+ }
+
+}
+
+// -----------------------------------
+double OggVorbisSubStream::getTime(OggPage &ogg)
+{
+ return (double)ogg.granPos / (double)samplerate;
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info)
+{
+ int ver = in.readLong();
+ int chans = in.readChar();
+ samplerate = in.readLong();
+ int brMax = in.readLong();
+ int brNom = in.readLong();
+ int brLow = in.readLong();
+
+
+ in.readChar(); // skip blocksize 0+1
+
+ LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d",
+ ver,chans,samplerate,brMax,brNom,brLow);
+
+
+ bitrate = brNom/1000;
+
+ char frame = in.readChar(); // framing bit
+ if (!frame)
+ throw StreamException("Bad Indent frame");
+
+}
+
+
+// -----------------------------------
+void OggVorbisSubStream::readSetup(Stream &in)
+{
+ // skip everything in packet
+ int cnt=0;
+ while (!in.eof())
+ {
+ cnt++;
+ in.readChar();
+ }
+
+ LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt);
+}
+// -----------------------------------
+void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info)
+{
+ int vLen = in.readLong(); // vendor len
+
+ in.skip(vLen);
+
+ char argBuf[8192];
+
+ info.track.clear();
+
+ int cLen = in.readLong(); // comment len
+ for(int i=0; i<cLen; i++)
+ {
+ int l = in.readLong();
+ if (l > sizeof(argBuf))
+ throw StreamException("Comment string too long");
+ in.read(argBuf,l);
+ argBuf[l] = 0;
+ LOG_CHANNEL("OGG Comment: %s",argBuf);
+
+ char *arg;
+ if ((arg=stristr(argBuf,"ARTIST=")))
+ {
+ info.track.artist.set(arg+7,String::T_ASCII);
+ info.track.artist.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"TITLE=")))
+ {
+ info.track.title.set(arg+6,String::T_ASCII);
+ info.track.title.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"GENRE=")))
+ {
+ info.track.genre.set(arg+6,String::T_ASCII);
+ info.track.genre.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"CONTACT=")))
+ {
+ info.track.contact.set(arg+8,String::T_ASCII);
+ info.track.contact.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"ALBUM=")))
+ {
+ info.track.album.set(arg+6,String::T_ASCII);
+ info.track.album.convertTo(String::T_UNICODE);
+ }
+ }
+
+ char frame = in.readChar(); // framing bit
+ if (!frame)
+ throw StreamException("Bad Comment frame");
+
+// updateMeta();
+
+}
+
+// -----------------------------------
+bool OggPage::isBOS()
+{
+ return (data[5] & 0x02) != 0;
+}
+// -----------------------------------
+bool OggPage::isEOS()
+{
+ return (data[5] & 0x04) != 0;
+}
+// -----------------------------------
+bool OggPage::isNewPacket()
+{
+ return (data[5] & 0x01) == 0;
+}
+// -----------------------------------
+bool OggPage::isHeader()
+{
+ return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0;
+}
+// -----------------------------------
+unsigned int OggPage::getSerialNo()
+{
+ return *(unsigned int *)&data[14];
+}
+
+// -----------------------------------
+void OggPage::read(Stream &in)
+{
+ // skip until we get OGG capture pattern
+ bool gotOgg=false;
+ while (!gotOgg)
+ {
+ if (in.readChar() == 'O')
+ if (in.readChar() == 'g')
+ if (in.readChar() == 'g')
+ if (in.readChar() == 'S')
+ gotOgg = true;
+ if (!gotOgg)
+ LOG_CHANNEL("Skipping OGG packet");
+ }
+
+
+
+ memcpy(&data[0],"OggS",4);
+
+ in.read(&data[4],27-4);
+
+ int numSegs = data[26];
+ bodyLen = 0;
+
+ // read segment table
+ in.read(&data[27],numSegs);
+ for(int i=0; i<numSegs; i++)
+ bodyLen += data[27+i];
+
+ if (bodyLen >= MAX_BODYLEN)
+ throw StreamException("OGG body too big");
+
+ headLen = 27+numSegs;
+
+ if (headLen > MAX_HEADERLEN)
+ throw StreamException("OGG header too big");
+
+ in.read(&data[headLen],bodyLen);
+
+ granPos = *(unsigned int *)&data[10];
+ granPos <<= 32;
+ granPos |= *(unsigned int *)&data[6];
+
+
+ #if 0
+ LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes",
+ *(unsigned int *)&data[18],
+ *(unsigned int *)&data[14],
+ data[5]&0x1?"cont":"new",
+ data[5]&0x2?"bos":"",
+ data[5]&0x4?"eos":"",
+ (unsigned int)(granPos>>32),
+ (unsigned int)(granPos&0xffffffff),
+ numSegs,
+ headLen+bodyLen);
+
+ #endif
+
+}
+// -----------------------------------
+bool OggPage::detectVorbis()
+{
+ return memcmp(&data[headLen+1],"vorbis",6) == 0;
+}
+// -----------------------------------
+bool OggPage::detectTheora()
+{
+ return memcmp(&data[headLen+1],"theora",6) == 0;
+}
+
+// -----------------------------------
+void OggPacket::addLacing(OggPage &ogg)
+{
+
+ int numSegs = ogg.data[26];
+ for(int i=0; i<numSegs; i++)
+ {
+ int seg = ogg.data[27+i];
+
+ packetSizes[numPackets]+=seg;
+
+ if (seg < 255)
+ {
+ numPackets++;
+ if (numPackets >= MAX_PACKETS)
+ throw StreamException("Too many OGG packets");
+ packetSizes[numPackets]=0;
+ }
+ }
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : ogg.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _OGG_H
+#define _OGG_H
+
+
+#include "channel.h"
+// ----------------------------------------------
+class OggPage;
+
+// ----------------------------------
+class OggPacket
+{
+public:
+ enum
+ {
+ MAX_BODYLEN = 65536, // probably too small
+ MAX_PACKETS = 256 // prolly too small too, but realloc?!?!?!
+ };
+
+ void addLacing(OggPage &);
+
+ int bodyLen;
+ unsigned char body[MAX_BODYLEN];
+
+
+ int numPackets;
+ unsigned int packetSizes[MAX_PACKETS];
+};
+
+// ----------------------------------------------
+class OggSubStream
+{
+public:
+ OggSubStream()
+ :maxHeaders(0),serialNo(0),bitrate(0)
+ {}
+
+ bool needHeader()
+ {
+ return maxHeaders && (pack.numPackets < maxHeaders);
+ }
+
+ void eos()
+ {
+ maxHeaders=0;
+ serialNo=0;
+ }
+
+ void bos(unsigned int ser)
+ {
+ maxHeaders = 3;
+ pack.numPackets=0;
+ pack.packetSizes[0]=0;
+ pack.bodyLen = 0;
+ serialNo = ser;
+ bitrate = 0;
+ }
+
+ bool isActive() {return serialNo!=0;}
+
+ void readHeader(Channel *,OggPage &);
+
+ virtual void procHeaders(Channel *) = 0;
+
+ int bitrate;
+
+ OggPacket pack;
+ int maxHeaders;
+ unsigned int serialNo;
+};
+// ----------------------------------------------
+class OggVorbisSubStream : public OggSubStream
+{
+public:
+ OggVorbisSubStream()
+ :samplerate(0)
+ {}
+
+ virtual void procHeaders(Channel *);
+
+ void readIdent(Stream &, ChanInfo &);
+ void readSetup(Stream &);
+ void readComment(Stream &, ChanInfo &);
+
+ double getTime(OggPage &);
+
+ int samplerate;
+
+};
+// ----------------------------------------------
+class OggTheoraSubStream : public OggSubStream
+{
+public:
+ OggTheoraSubStream() : granposShift(0), frameTime(0) {}
+
+ virtual void procHeaders(Channel *);
+
+ void readInfo(Stream &, ChanInfo &);
+
+ double getTime(OggPage &);
+
+ int granposShift;
+ double frameTime;
+};
+
+// ----------------------------------------------
+class OGGStream : public ChannelStream
+{
+public:
+ OGGStream()
+ {}
+
+
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+
+ void readHeaders(Stream &,Channel *, OggPage &);
+
+ OggVorbisSubStream vorbis;
+ OggTheoraSubStream theora;
+};
+
+// ----------------------------------
+class OggPage
+{
+public:
+ enum
+ {
+ MAX_BODYLEN = 65536,
+ MAX_HEADERLEN = 27+256
+ };
+
+ void read(Stream &);
+ bool isBOS();
+ bool isEOS();
+ bool isNewPacket();
+ bool isHeader();
+ unsigned int getSerialNo();
+
+ bool detectVorbis();
+ bool detectTheora();
+
+
+ int64_t granPos;
+ int headLen,bodyLen;
+ unsigned char data[MAX_HEADERLEN+MAX_BODYLEN];
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : pcp.cpp
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "atom.h"
+#include "pcp.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void PCPStream::init(GnuID &rid)
+{
+ remoteID = rid;
+ routeList.clear();
+
+ lastPacketTime = 0;
+ nextRootPacket = 0; // 0 seconds (never)
+
+ inData.init();
+ inData.accept = ChanPacket::T_PCP;
+
+ outData.init();
+ outData.accept = ChanPacket::T_PCP;
+}
+// ------------------------------------------
+void PCPStream::readVersion(Stream &in)
+{
+ int len = in.readInt();
+
+ if (len != 4)
+ throw StreamException("Invalid PCP");
+
+ int ver = in.readInt();
+
+ LOG_DEBUG("PCP ver: %d",ver);
+}
+// ------------------------------------------
+void PCPStream::readHeader(Stream &in,Channel *)
+{
+// AtomStream atom(in);
+
+// if (in.readInt() != PCP_CONNECT)
+// throw StreamException("Not PCP");
+
+// readVersion(in);
+}
+// ------------------------------------------
+bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID)
+{
+ if (destID.isSet())
+ if (!destID.isSame(remoteID))
+ if (!routeList.contains(destID))
+ return false;
+
+ return outData.writePacket(pack);
+}
+// ------------------------------------------
+void PCPStream::flush(Stream &in)
+{
+ ChanPacket pack;
+ // send outward packets
+ while (outData.numPending())
+ {
+ outData.readPacket(pack);
+ pack.writeRaw(in);
+ }
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,Channel *)
+{
+ BroadcastState bcs;
+ return readPacket(in,bcs);
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,BroadcastState &bcs)
+{
+ int error = PCP_ERROR_GENERAL;
+ try
+ {
+ AtomStream atom(in);
+
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream patom(mem);
+
+
+ // send outward packets
+ error = PCP_ERROR_WRITE;
+ if (outData.numPending())
+ {
+ outData.readPacket(pack);
+ pack.writeRaw(in);
+ }
+ error = PCP_ERROR_GENERAL;
+
+ if (outData.willSkip())
+ {
+ error = PCP_ERROR_WRITE+PCP_ERROR_SKIP;
+ throw StreamException("Send too slow");
+ }
+
+
+ error = PCP_ERROR_READ;
+ // poll for new downward packet
+ if (in.readReady())
+ {
+ int numc,numd;
+ ID4 id;
+
+ id = atom.read(numc,numd);
+
+ mem.rewind();
+ pack.len = patom.writeAtoms(id, in, numc, numd);
+ pack.type = ChanPacket::T_PCP;
+
+ //inData.writePacket(pack);
+ //}
+ error = PCP_ERROR_GENERAL;
+
+ // process downward packets
+ //if (inData.numPending())
+ //{
+ //inData.readPacket(pack);
+
+ mem.rewind();
+
+ //int numc,numd;
+ id = patom.read(numc,numd);
+
+ error = PCPStream::procAtom(patom,id,numc,numd,bcs);
+
+ if (error)
+ throw StreamException("PCP exception");
+ }
+
+ error = 0;
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error);
+ }
+
+ return error;
+}
+
+// ------------------------------------------
+void PCPStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+// ------------------------------------------
+void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+ Host host;
+ GnuID chanID;
+
+ chanID.clear();
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_PUSH_IP)
+ host.ip = atom.readInt();
+ else if (id == PCP_PUSH_PORT)
+ host.port = atom.readShort();
+ else if (id == PCP_PUSH_CHANID)
+ atom.readBytes(chanID.id,16);
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+
+ if (bcs.forMe)
+ {
+ char ipstr[64];
+ host.toStr(ipstr);
+
+ Servent *s = NULL;
+
+ if (chanID.isSet())
+ {
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (ch)
+ if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID))
+ s = servMgr->allocServent();
+ }else{
+ s = servMgr->allocServent();
+ }
+
+ if (s)
+ {
+ LOG_DEBUG("GIVing to %s",ipstr);
+ s->initGIV(host,chanID);
+ }
+ }
+
+}
+// ------------------------------------------
+void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+ String url;
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_ROOT_UPDINT)
+ {
+ int si = atom.readInt();
+
+ chanMgr->setUpdateInterval(si);
+ LOG_DEBUG("PCP got new host update interval: %ds",si);
+ }else if (id == PCP_ROOT_URL)
+ {
+ url = "http://www.peercast.org/";
+ String loc;
+ atom.readString(loc.data,sizeof(loc.data),d);
+ url.append(loc);
+
+ }else if (id == PCP_ROOT_CHECKVER)
+ {
+ unsigned int newVer = atom.readInt();
+ if (newVer > PCP_CLIENT_VERSION)
+ {
+ strcpy(servMgr->downloadURL,url.cstr());
+ peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client.");
+ }
+ LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION);
+
+ }else if (id == PCP_ROOT_NEXT)
+ {
+ unsigned int time = atom.readInt();
+
+ if (time)
+ {
+ unsigned int ctime = sys->getTime();
+ nextRootPacket = ctime+time;
+ LOG_DEBUG("PCP expecting next root packet in %ds",time);
+ }else
+ {
+ nextRootPacket = 0;
+ }
+
+ }else if (id == PCP_ROOT_UPDATE)
+ {
+ atom.skip(c,d);
+
+ chanMgr->broadcastTrackerUpdate(remoteID,true);
+
+ }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
+ {
+ String newMsg;
+
+ atom.readString(newMsg.data,sizeof(newMsg.data),d);
+ if (!newMsg.isSame(servMgr->rootMsg.cstr()))
+ {
+ servMgr->rootMsg = newMsg;
+ LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr());
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr());
+ }
+ }else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+}
+
+// ------------------------------------------
+void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs)
+{
+ ChanPacket pack;
+ ID4 type;
+
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_CHAN_PKT_TYPE)
+ {
+ type = atom.readID4();
+
+ if (type == PCP_CHAN_PKT_HEAD)
+ pack.type = ChanPacket::T_HEAD;
+ else if (type == PCP_CHAN_PKT_DATA)
+ pack.type = ChanPacket::T_DATA;
+ else
+ pack.type = ChanPacket::T_UNKNOWN;
+
+ }else if (id == PCP_CHAN_PKT_POS)
+ {
+ pack.pos = atom.readInt();
+
+
+ }else if (id == PCP_CHAN_PKT_DATA)
+ {
+ pack.len = d;
+ atom.readBytes(pack.data,pack.len);
+ }
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ if (ch)
+ {
+
+ int diff = pack.pos - ch->streamPos;
+ if (diff)
+ {
+ LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount);
+ if (ch->lastSkipTime + 120 < sys->getTime()){
+ ch->skipCount = 0;
+ }
+ ch->lastSkipTime = sys->getTime();
+ ch->skipCount++; //JP-EX
+ pack.skip = true;
+ }
+
+ if (servMgr->autoBumpSkipCount) //JP-EX
+ {
+ if (ch->skipCount > servMgr->autoBumpSkipCount)
+ {
+ LOG_DEBUG("Auto bump");
+ ch->bump = true;
+ }
+ }
+
+ if (pack.type == ChanPacket::T_HEAD)
+ {
+ LOG_DEBUG("New head packet at %d",pack.pos);
+ bool renewhead;
+ if (servMgr->keepDownstreams)
+ renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0);
+ else
+ renewhead = true;
+
+ /*
+ // check for stream restart
+ if (pack.pos == 0)
+ {
+ LOG_CHANNEL("PCP resetting stream");
+ ch->streamIndex++;
+ ch->rawData.init();
+ }
+ */
+ if (renewhead || ch->lastStopTime + 30 < sys->getTime()) {
+ // check for stream restart
+ if (pack.pos == 0)
+ {
+ LOG_CHANNEL("PCP resetting stream");
+ ch->streamIndex++;
+ ch->rawData.init();
+ }
+
+ ch->headPack = pack;
+
+ ch->rawData.writePacket(pack,true);
+ ch->streamPos = pack.pos+pack.len;
+ }
+
+ }else if (pack.type == ChanPacket::T_DATA)
+ {
+ ch->rawData.writePacket(pack,true);
+ ch->streamPos = pack.pos+pack.len;
+ }
+
+ }
+
+ // update this parent packet stream position
+ if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos)))
+ bcs.streamPos = pack.pos;
+
+}
+// -----------------------------------
+void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg)
+{
+// ChanHit hit;
+ hit.init();
+ GnuID chanID = bcs.chanID; //use default
+
+ bool busy=false;
+
+ unsigned int ipNum=0;
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_HOST_IP)
+ {
+ unsigned int ip = atom.readInt();
+ hit.rhost[ipNum].ip = ip;
+ }else if (id == PCP_HOST_PORT)
+ {
+ int port = atom.readShort();
+ hit.rhost[ipNum++].port = port;
+
+ if (ipNum > 1)
+ ipNum = 1;
+ }
+ else if (id == PCP_HOST_NUML)
+ hit.numListeners = atom.readInt();
+ else if (id == PCP_HOST_NUMR)
+ hit.numRelays = atom.readInt();
+ else if (id == PCP_HOST_UPTIME)
+ hit.upTime = atom.readInt();
+ else if (id == PCP_HOST_OLDPOS)
+ hit.oldestPos = atom.readInt();
+ else if (id == PCP_HOST_NEWPOS)
+ hit.newestPos = atom.readInt();
+ else if (id == PCP_HOST_VERSION)
+ hit.version = atom.readInt();
+ else if (id == PCP_HOST_VERSION_VP)
+ hit.version_vp = atom.readInt();
+ else if (id == PCP_HOST_VERSION_EX_PREFIX)
+ atom.readBytes(hit.version_ex_prefix,2);
+ else if (id == PCP_HOST_VERSION_EX_NUMBER){
+ hit.version_ex_number = atom.readShort();
+ }
+ else if (id == PCP_HOST_FLAGS1)
+ {
+ int fl1 = atom.readChar();
+
+ hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0;
+ hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0;
+ hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0;
+ hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0;
+ hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0;
+ hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0;
+
+
+ }else if (id == PCP_HOST_ID)
+ atom.readBytes(hit.sessionID.id,16);
+ else if (id == PCP_HOST_CHANID)
+ atom.readBytes(chanID.id,16);
+ else if (id == PCP_HOST_UPHOST_IP)
+ hit.uphost.ip = atom.readInt();
+ else if (id == PCP_HOST_UPHOST_PORT)
+ hit.uphost.port = atom.readInt();
+ else if (id == PCP_HOST_UPHOST_HOPS)
+ hit.uphostHops = atom.readInt();
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ hit.host = hit.rhost[0];
+ hit.chanID = chanID;
+
+ hit.numHops = bcs.numHops;
+
+ hit.servent_id = bcs.servent_id;
+
+ if (flg){
+// LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ if (hit.recv)
+ chanMgr->addHit(hit);
+ else
+ chanMgr->delHit(hit);
+// LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+ }
+
+ if (hit.numHops == 1){
+ Servent *sv = servMgr->findServentByServentID(hit.servent_id);
+ if (sv){
+// LOG_DEBUG("set servent's waitPort = %d", hit.host.port);
+ sv->waitPort = hit.host.port;
+ }
+ }
+}
+
+// ------------------------------------------
+void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+/* Channel *ch=NULL;
+ ChanHitList *chl=NULL;
+ ChanInfo newInfo;
+
+ ch = chanMgr->findChannelByID(bcs.chanID);
+ chl = chanMgr->findHitListByID(bcs.chanID);
+
+ if (ch)
+ newInfo = ch->info;
+ else if (chl)
+ newInfo = chl->info;*/
+
+ Channel *ch=NULL;
+ ChanHitList *chl=NULL;
+ ChanInfo newInfo, chaInfo;
+
+ ch = this->parent;
+ if (ch){
+ newInfo = ch->info;
+ chaInfo = ch->info;
+ }
+
+ for(int i=0; i<numc; i++)
+ {
+
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if ((id == PCP_CHAN_PKT) && (ch))
+ {
+ readPktAtoms(ch,atom,c,bcs);
+ }else if (id == PCP_CHAN_INFO)
+ {
+ newInfo.readInfoAtoms(atom,c);
+
+ }else if (id == PCP_CHAN_TRACK)
+ {
+ newInfo.readTrackAtoms(atom,c);
+
+ }else if (id == PCP_CHAN_BCID)
+ {
+ atom.readBytes(newInfo.bcID.id,16);
+
+ }else if (id == PCP_CHAN_KEY) // depreciated
+ {
+ atom.readBytes(newInfo.bcID.id,16);
+ newInfo.bcID.id[0] = 0; // clear flags
+
+ }else if (id == PCP_CHAN_ID)
+ {
+ atom.readBytes(newInfo.id.id,16);
+
+ ch = chanMgr->findChannelByID(newInfo.id);
+ chl = chanMgr->findHitListByID(newInfo.id);
+
+ }else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ chl = chanMgr->findHitList(newInfo);
+
+ if (!chl)
+ chl = chanMgr->addHitList(newInfo);
+
+ if (chl)
+ {
+ chl->info.update(newInfo);
+
+ if (!servMgr->chanLog.isEmpty())
+ {
+ //if (chl->numListeners())
+ {
+ try
+ {
+ FileStream file;
+ file.openWriteAppend(servMgr->chanLog.cstr());
+
+ XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime());
+ XML::Node *n = chl->info.createChannelXML();
+ n->add(chl->createXML(false));
+ n->add(chl->info.createTrackXML());
+ rn->add(n);
+
+ rn->write(file,0);
+ delete rn;
+ file.close();
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to update channel log: %s",e.msg);
+ }
+ }
+ }
+
+ }
+
+ if (ch && !ch->isBroadcasting())
+ ch->updateInfo(newInfo);
+
+
+}
+// ------------------------------------------
+int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+ ChanPacket pack;
+ int ttl=0;
+ int ver=0;
+ int ver_vp=0;
+ GnuID fromID,destID;
+ int r=0;
+ char ver_ex_prefix[2];
+ int ver_ex_number = 0;
+
+ fromID.clear();
+ destID.clear();
+
+ bcs.initPacketSettings();
+
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream patom(pmem);
+
+ patom.writeParent(PCP_BCST,numc);
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_BCST_TTL)
+ {
+ ttl = atom.readChar()-1;
+ patom.writeChar(id,ttl);
+
+ }else if (id == PCP_BCST_HOPS)
+ {
+ bcs.numHops = atom.readChar()+1;
+ patom.writeChar(id,bcs.numHops);
+
+ }else if (id == PCP_BCST_FROM)
+ {
+ atom.readBytes(fromID.id,16);
+ patom.writeBytes(id,fromID.id,16);
+
+ routeList.add(fromID);
+ }else if (id == PCP_BCST_GROUP)
+ {
+ bcs.group = atom.readChar();
+ patom.writeChar(id,bcs.group);
+ }else if (id == PCP_BCST_DEST)
+ {
+ atom.readBytes(destID.id,16);
+ patom.writeBytes(id,destID.id,16);
+ bcs.forMe = destID.isSame(servMgr->sessionID);
+
+ char idstr1[64];
+ char idstr2[64];
+
+ destID.toStr(idstr1);
+ servMgr->sessionID.toStr(idstr2);
+
+ }else if (id == PCP_BCST_CHANID)
+ {
+ atom.readBytes(bcs.chanID.id,16);
+ patom.writeBytes(id,bcs.chanID.id,16);
+ }else if (id == PCP_BCST_VERSION)
+ {
+ ver = atom.readInt();
+ patom.writeInt(id,ver);
+ }else if (id == PCP_BCST_VERSION_VP)
+ {
+ ver_vp = atom.readInt();
+ patom.writeInt(id,ver_vp);
+ }else if (id == PCP_BCST_VERSION_EX_PREFIX)
+ {
+ atom.readBytes(ver_ex_prefix,2);
+ patom.writeBytes(id,ver_ex_prefix,2);
+ }else if (id == PCP_BCST_VERSION_EX_NUMBER)
+ {
+ ver_ex_number = atom.readShort();
+ patom.writeShort(id,ver_ex_number);
+ }else if (id == PCP_HOST)
+ {
+ ChanHit hit;
+ readHostAtoms(atom,c,bcs,hit,false);
+ if (hit.uphost.ip == 0){
+// LOG_DEBUG("bcs servent_id = %d", bcs.servent_id);
+ if (bcs.numHops == 1){
+ hit.uphost.ip = servMgr->serverHost.ip;
+ hit.uphost.port = servMgr->serverHost.port;
+ hit.uphostHops = 1;
+ } else {
+ Servent *sv = servMgr->findServentByServentID(bcs.servent_id);
+ if (sv){
+ hit.uphost.ip = sv->getHost().ip;
+ hit.uphost.port = sv->waitPort;
+ hit.uphostHops = bcs.numHops - 1;
+ }
+ }
+ }
+ int oldPos = pmem.pos;
+ hit.writeAtoms(patom, hit.chanID);
+ pmem.pos = oldPos;
+ r = readAtom(patom,bcs);
+ } else {
+ // copy and process atoms
+ int oldPos = pmem.pos;
+ patom.writeAtoms(id,atom.io,c,d);
+ pmem.pos = oldPos;
+ r = readAtom(patom,bcs);
+ }
+ }
+
+ char fromStr[64];
+ fromStr[0] = 0;
+ if (fromID.isSet())
+ fromID.toStr(fromStr);
+ char destStr[64];
+ destStr[0] = 0;
+ if (destID.isSet())
+ destID.toStr(destStr);
+ char tmp[64];
+ bcs.chanID.toStr(tmp);
+
+// LOG_DEBUG(tmp);
+
+ if (ver_ex_number){
+ LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d",
+ bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl);
+ } else if (ver_vp){
+ 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);
+ } else {
+ LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl);
+ }
+
+ if (fromID.isSet())
+ if (fromID.isSame(servMgr->sessionID))
+ {
+ LOG_ERROR("BCST loopback");
+ return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK;
+ }
+
+ // broadcast back out if ttl > 0
+ if ((ttl>0) && (!bcs.forMe))
+ {
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+ if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+ {
+ chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID);
+ }
+
+ if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT);
+ }
+
+ if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN);
+ }
+
+ if (bcs.group & (PCP_BCST_GROUP_RELAYS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY);
+ }
+
+
+// LOG_DEBUG("ttl=%d",ttl);
+
+ } else {
+// LOG_DEBUG("ttl=%d",ttl);
+ }
+ return r;
+}
+
+
+// ------------------------------------------
+int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs)
+{
+ int r=0;
+ ChanHit hit;
+ int rBan = 0;
+
+ if (id == PCP_CHAN)
+ {
+ readChanAtoms(atom,numc,bcs);
+ }else if (id == PCP_ROOT)
+ {
+ if (servMgr->isRoot)
+ throw StreamException("Unauthorized root message");
+ else
+ readRootAtoms(atom,numc,bcs);
+
+ }else if (id == PCP_HOST)
+ {
+ readHostAtoms(atom,numc,bcs,hit);
+ Channel *ch = chanMgr->findChannelByID(hit.chanID);
+ if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){
+ if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){
+ char tmp[32];
+ hit.host.IPtoStr(tmp);
+ LOG_DEBUG("host that can't relay is disconnect: %s", tmp);
+ rBan = PCP_ERROR_BANNED;
+ }
+ if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){
+ char tmp[32];
+ hit.host.IPtoStr(tmp);
+ LOG_DEBUG("host that is not VP is disconnect: %s", tmp);
+ rBan = PCP_ERROR_BANNED;
+ }
+ }
+
+ }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
+ {
+ String msg;
+ atom.readString(msg.data,sizeof(msg.data),dlen);
+ LOG_DEBUG("PCP got text: %s",msg.cstr());
+ }else if (id == PCP_BCST)
+ {
+ r = readBroadcastAtoms(atom,numc,bcs);
+ }else if (id == PCP_HELO)
+ {
+ atom.skip(numc,dlen);
+ atom.writeParent(PCP_OLEH,1);
+ atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ }else if (id == PCP_PUSH)
+ {
+
+ readPushAtoms(atom,numc,bcs);
+ }else if (id == PCP_OK)
+ {
+ atom.readInt();
+
+ }else if (id == PCP_QUIT)
+ {
+ r = atom.readInt();
+ if (!r)
+ r = PCP_ERROR_QUIT;
+
+ }else if (id == PCP_ATOM)
+ {
+ for(int i=0; i<numc; i++)
+ {
+ int nc,nd;
+ ID4 aid = atom.read(nc,nd);
+ int ar = procAtom(atom,aid,nc,nd,bcs);
+ if (ar)
+ r = ar;
+ }
+
+ }else
+ {
+ LOG_CHANNEL("PCP skip: %s",id.getString().str());
+ atom.skip(numc,dlen);
+ }
+
+ if (!r)
+ r = rBan;
+
+ return r;
+
+}
+
+// ------------------------------------------
+int PCPStream::readAtom(AtomStream &atom,BroadcastState &bcs)
+{
+ int numc,dlen;
+ ID4 id = atom.read(numc,dlen);
+
+ return procAtom(atom,id,numc,dlen,bcs);
+}
+
+
--- /dev/null
+// ------------------------------------------------
+// File : pcp.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _PCP_H
+#define _PCP_H
+
+// ------------------------------------------------
+
+
+#include "id.h"
+#include "cstream.h"
+#include "channel.h"
+
+// ------------------------------------------------
+
+class Servent;
+
+
+// ------------------------------------------------
+
+static const ID4 PCP_CONNECT = "pcp\n";
+
+static const ID4 PCP_OK = "ok";
+
+static const ID4 PCP_HELO = "helo";
+static const ID4 PCP_HELO_AGENT = "agnt";
+static const ID4 PCP_HELO_OSTYPE = "ostp";
+static const ID4 PCP_HELO_SESSIONID = "sid";
+static const ID4 PCP_HELO_PORT = "port";
+static const ID4 PCP_HELO_PING = "ping";
+static const ID4 PCP_HELO_PONG = "pong";
+static const ID4 PCP_HELO_REMOTEIP = "rip";
+static const ID4 PCP_HELO_VERSION = "ver";
+static const ID4 PCP_HELO_BCID = "bcid";
+static const ID4 PCP_HELO_DISABLE = "dis";
+
+static const ID4 PCP_OLEH = "oleh";
+
+static const ID4 PCP_MODE = "mode";
+static const ID4 PCP_MODE_GNUT06 = "gn06";
+
+static const ID4 PCP_ROOT = "root";
+static const ID4 PCP_ROOT_UPDINT = "uint";
+static const ID4 PCP_ROOT_CHECKVER = "chkv";
+static const ID4 PCP_ROOT_URL = "url";
+static const ID4 PCP_ROOT_UPDATE = "upd";
+static const ID4 PCP_ROOT_NEXT = "next";
+
+
+static const ID4 PCP_OS_LINUX = "lnux";
+static const ID4 PCP_OS_WINDOWS = "w32";
+static const ID4 PCP_OS_OSX = "osx";
+static const ID4 PCP_OS_WINAMP = "wamp";
+static const ID4 PCP_OS_ZAURUS = "zaur";
+
+static const ID4 PCP_GET = "get";
+static const ID4 PCP_GET_ID = "id";
+static const ID4 PCP_GET_NAME = "name";
+
+static const ID4 PCP_HOST = "host";
+static const ID4 PCP_HOST_ID = "id";
+static const ID4 PCP_HOST_IP = "ip";
+static const ID4 PCP_HOST_PORT = "port";
+static const ID4 PCP_HOST_NUML = "numl";
+static const ID4 PCP_HOST_NUMR = "numr";
+static const ID4 PCP_HOST_UPTIME = "uptm";
+static const ID4 PCP_HOST_TRACKER = "trkr";
+static const ID4 PCP_HOST_CHANID = "cid";
+static const ID4 PCP_HOST_VERSION = "ver";
+static const ID4 PCP_HOST_VERSION_VP = "vevp";
+static const ID4 PCP_HOST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_HOST_VERSION_EX_NUMBER = "vexn";
+static const ID4 PCP_HOST_FLAGS1 = "flg1";
+static const ID4 PCP_HOST_OLDPOS = "oldp";
+static const ID4 PCP_HOST_NEWPOS = "newp";
+static const ID4 PCP_HOST_UPHOST_IP = "upip";
+static const ID4 PCP_HOST_UPHOST_PORT = "uppt";
+static const ID4 PCP_HOST_UPHOST_HOPS = "uphp";
+
+static const ID4 PCP_QUIT = "quit";
+
+static const ID4 PCP_CHAN = "chan";
+static const ID4 PCP_CHAN_ID = "id";
+static const ID4 PCP_CHAN_BCID = "bcid";
+static const ID4 PCP_CHAN_KEY = "key";
+
+static const ID4 PCP_CHAN_PKT = "pkt";
+static const ID4 PCP_CHAN_PKT_TYPE = "type";
+static const ID4 PCP_CHAN_PKT_POS = "pos";
+static const ID4 PCP_CHAN_PKT_HEAD = "head";
+static const ID4 PCP_CHAN_PKT_DATA = "data";
+static const ID4 PCP_CHAN_PKT_META = "meta";
+
+static const ID4 PCP_CHAN_INFO = "info";
+static const ID4 PCP_CHAN_INFO_TYPE = "type";
+static const ID4 PCP_CHAN_INFO_BITRATE = "bitr";
+static const ID4 PCP_CHAN_INFO_GENRE = "gnre";
+static const ID4 PCP_CHAN_INFO_NAME = "name";
+static const ID4 PCP_CHAN_INFO_URL = "url";
+static const ID4 PCP_CHAN_INFO_DESC = "desc";
+static const ID4 PCP_CHAN_INFO_COMMENT = "cmnt";
+
+static const ID4 PCP_CHAN_TRACK = "trck";
+static const ID4 PCP_CHAN_TRACK_TITLE = "titl";
+static const ID4 PCP_CHAN_TRACK_CREATOR = "crea";
+static const ID4 PCP_CHAN_TRACK_URL = "url";
+static const ID4 PCP_CHAN_TRACK_ALBUM = "albm";
+
+static const ID4 PCP_MESG = "mesg";
+static const ID4 PCP_MESG_ASCII = "asci"; // ascii/sjis to be depreciated.. utf8/unicode is the only supported format from now.
+static const ID4 PCP_MESG_SJIS = "sjis";
+
+static const ID4 PCP_BCST = "bcst";
+static const ID4 PCP_BCST_TTL = "ttl";
+static const ID4 PCP_BCST_HOPS = "hops";
+static const ID4 PCP_BCST_FROM = "from";
+static const ID4 PCP_BCST_DEST = "dest";
+static const ID4 PCP_BCST_GROUP = "grp";
+static const ID4 PCP_BCST_CHANID = "cid";
+static const ID4 PCP_BCST_VERSION = "vers";
+static const ID4 PCP_BCST_VERSION_VP = "vrvp";
+static const ID4 PCP_BCST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_BCST_VERSION_EX_NUMBER = "vexn";
+
+static const ID4 PCP_PUSH = "push";
+static const ID4 PCP_PUSH_IP = "ip";
+static const ID4 PCP_PUSH_PORT = "port";
+static const ID4 PCP_PUSH_CHANID = "cid";
+
+static const ID4 PCP_SPKT = "spkt";
+
+static const ID4 PCP_ATOM = "atom";
+
+static const ID4 PCP_SESSIONID = "sid";
+
+static const int PCP_BCST_GROUP_ALL = (char)0xff;
+static const int PCP_BCST_GROUP_ROOT = 1;
+static const int PCP_BCST_GROUP_TRACKERS = 2;
+static const int PCP_BCST_GROUP_RELAYS = 4;
+
+
+static const int PCP_ERROR_QUIT = 1000;
+static const int PCP_ERROR_BCST = 2000;
+static const int PCP_ERROR_READ = 3000;
+static const int PCP_ERROR_WRITE = 4000;
+static const int PCP_ERROR_GENERAL = 5000;
+
+static const int PCP_ERROR_SKIP = 1;
+static const int PCP_ERROR_ALREADYCONNECTED = 2;
+static const int PCP_ERROR_UNAVAILABLE = 3;
+static const int PCP_ERROR_LOOPBACK = 4;
+static const int PCP_ERROR_NOTIDENTIFIED = 5;
+static const int PCP_ERROR_BADRESPONSE = 6;
+static const int PCP_ERROR_BADAGENT = 7;
+static const int PCP_ERROR_OFFAIR = 8;
+static const int PCP_ERROR_SHUTDOWN = 9;
+static const int PCP_ERROR_NOROOT = 10;
+static const int PCP_ERROR_BANNED = 11;
+
+static const int PCP_HOST_FLAGS1_TRACKER = 0x01;
+static const int PCP_HOST_FLAGS1_RELAY = 0x02;
+static const int PCP_HOST_FLAGS1_DIRECT = 0x04;
+static const int PCP_HOST_FLAGS1_PUSH = 0x08;
+static const int PCP_HOST_FLAGS1_RECV = 0x10;
+static const int PCP_HOST_FLAGS1_CIN = 0x20;
+static const int PCP_HOST_FLAGS1_PRIVATE = 0x40;
+
+
+// ----------------------------------------------
+class BroadcastState
+{
+public:
+ BroadcastState()
+ :numHops(0)
+ ,forMe(false)
+ ,streamPos(0)
+ ,group(0)
+ ,servent_id(0)
+ {
+ chanID.clear();
+ bcID.clear();
+ }
+
+
+ void initPacketSettings()
+ {
+ forMe = false;
+ group = 0;
+ numHops = 0;
+ bcID.clear();
+ chanID.clear();
+ }
+
+
+ GnuID chanID,bcID;
+ int numHops;
+ bool forMe;
+ unsigned int streamPos;
+ int group;
+ int servent_id;
+};
+
+// ----------------------------------------------
+class PCPStream : public ChannelStream
+{
+public:
+ PCPStream(GnuID &rid)
+ :routeList(1000)
+ {
+ init(rid);
+ }
+
+ void init(GnuID &);
+
+ virtual void kill()
+ {
+ inData.lock.on();
+ outData.lock.on();
+ }
+
+ virtual bool sendPacket(ChanPacket &,GnuID &);
+ virtual void flush(Stream &);
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+ int readPacket(Stream &,BroadcastState &);
+ void flushOutput(Stream &in,BroadcastState &);
+ static void readVersion(Stream &);
+
+ int procAtom(AtomStream &,ID4,int,int,BroadcastState &);
+ int readAtom(AtomStream &,BroadcastState &);
+ void readChanAtoms(AtomStream &,int,BroadcastState &);
+// void readHostAtoms(AtomStream &, int, BroadcastState &);
+ void readHostAtoms(AtomStream &, int, BroadcastState &, ChanHit &, bool flg=true);
+ void readPushAtoms(AtomStream &, int,BroadcastState &);
+
+ void readPktAtoms(Channel *,AtomStream &,int,BroadcastState &);
+ void readRootAtoms(AtomStream &, int,BroadcastState &);
+
+ int readBroadcastAtoms(AtomStream &,int,BroadcastState &);
+
+ ChanPacketBuffer inData,outData;
+ unsigned int lastPacketTime;
+ unsigned int nextRootPacket;
+
+ //int error;
+ GnuIDList routeList;
+ GnuID remoteID;
+
+};
+
+#endif
--- /dev/null
+#include "sys.h"
+#include "peercast.h"
+#include "channel.h"
+#include "servmgr.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+
+// ---------------------------------
+// globals
+
+Sys *sys=NULL;
+ChanMgr *chanMgr;
+ServMgr *servMgr;
+
+PeercastInstance *peercastInst=NULL;
+PeercastApplication *peercastApp=NULL;
+
+
+// ---------------------------------
+void APICALL PeercastInstance::init()
+{
+ sys = createSys();
+ servMgr = new ServMgr();
+ chanMgr = new ChanMgr();
+
+ if (peercastApp->getIniFilename())
+ servMgr->loadSettings(peercastApp->getIniFilename());
+
+ servMgr->start();
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setNotifyMask(int mask)
+{
+ if (servMgr)
+ servMgr->notifyMask = mask;
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getNotifyMask()
+{
+ if (servMgr)
+ return servMgr->notifyMask;
+ else
+ return 0;
+}
+
+// --------------------------------------------------
+void APICALL PeercastInstance::setAutoConnect(bool on)
+{
+ if (servMgr)
+ servMgr->autoConnect = on;
+}
+// --------------------------------------------------
+bool APICALL PeercastInstance::getAutoConnect()
+{
+ if (servMgr)
+ return servMgr->autoConnect;
+ else
+ return false;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setMaxOutput(int kbps)
+{
+ if (servMgr)
+ servMgr->maxBitrateOut = kbps;
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getMaxOutput()
+{
+ if (servMgr)
+ return servMgr->maxBitrateOut;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setMaxRelays(int max)
+{
+ if (servMgr)
+ servMgr->setMaxRelays(max);
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getMaxRelays()
+{
+ if (servMgr)
+ return servMgr->maxRelays;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setActive(bool on)
+{
+ if (servMgr)
+ {
+ servMgr->autoConnect = on;
+ servMgr->autoServe = on;
+ }
+}
+// --------------------------------------------------
+bool APICALL PeercastInstance::getActive()
+{
+ if (servMgr)
+ return servMgr->autoConnect&&servMgr->autoServe;
+ else
+ return false;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::saveSettings()
+{
+ if (servMgr)
+ servMgr->saveSettings(peercastApp->getIniFilename());
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::quit()
+{
+ isQuitting = true;
+ if (chanMgr)
+ chanMgr->quit();
+ if (servMgr)
+ servMgr->quit();
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setServerPort(int port)
+{
+ if (servMgr)
+ {
+ servMgr->serverHost.port = port;
+ servMgr->restartServer = true;
+ }
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getServerPort()
+{
+ if (servMgr)
+ return servMgr->serverHost.port;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setServerPassword(const char *pwd)
+{
+ if (servMgr)
+ strcpy(servMgr->password,pwd);
+}
+// --------------------------------------------------
+const char *APICALL PeercastInstance::getServerPassword()
+{
+ return servMgr->password;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::callLocalURL(const char *url)
+{
+ if (sys && servMgr)
+ sys->callLocalURL(url,servMgr->serverHost.port);
+}
+
+
+// --------------------------------------------------
+void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type)
+{
+ if(sys)
+ {
+ const int MAX_LINELEN = 1024;
+
+ char str[MAX_LINELEN+1];
+ vsnprintf(str,MAX_LINELEN-1,fmt,ap);
+ str[MAX_LINELEN-1]=0;
+
+ if (type != LogBuffer::T_NONE)
+ sys->logBuf->write(str,type);
+
+ peercastApp->printLog(type,str);
+ }
+}
+// --------------------------------------------------
+void LOG(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+ va_end(ap);
+}
+
+// --------------------------------------------------
+void LOG_ERROR(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_ERROR)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_ERROR);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_DEBUG(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_DEBUG)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_NETWORK(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_NETWORK)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_NETWORK);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_CHANNEL(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_CHANNEL)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_CHANNEL);
+ va_end(ap);
+ }
+ }
+}
--- /dev/null
+#ifndef _PEERCAST_H
+#define _PEERCAST_H
+
+
+//#define APICALL _stdcall
+#ifdef WIN32
+#define APICALL _cdecl
+#else
+#define APICALL
+#endif
+
+
+class ChanInfo;
+class Sys;
+
+#include "servmgr.h"
+
+
+// ------------------------------------------------------------
+// This is the interface from the application to the core.
+class PeercastInstance
+{
+public:
+ PeercastInstance()
+ :isQuitting(false)
+ {}
+
+ virtual void APICALL init();
+
+ virtual void APICALL setAutoConnect(bool);
+ virtual bool APICALL getAutoConnect();
+
+ virtual void APICALL setActive(bool);
+ virtual bool APICALL getActive();
+
+ virtual int APICALL getMaxOutput();
+ virtual void APICALL setMaxOutput(int);
+
+ virtual int APICALL getMaxRelays();
+ virtual void APICALL setMaxRelays(int);
+
+ virtual void APICALL setServerPort(int);
+ virtual int APICALL getServerPort();
+ virtual void APICALL setServerPassword(const char *);
+ virtual const char *APICALL getServerPassword();
+
+ virtual void APICALL saveSettings();
+
+ virtual void APICALL callLocalURL(const char *);
+
+ virtual void APICALL setNotifyMask(int);
+ virtual int APICALL getNotifyMask();
+
+ virtual void APICALL quit();
+
+ virtual Sys * APICALL createSys()=0;
+
+ bool isQuitting;
+
+};
+// ------------------------------------------------------------
+// This is the interface from the core to the application.
+class PeercastApplication
+{
+public:
+
+ virtual const char * APICALL getPath() {return "./";}
+ virtual const char * APICALL getIniFilename() {return "peercast.ini";}
+ virtual bool APICALL clearTemp() { return false; } //JP-EX
+ virtual void APICALL openLogFile() {} //JP-EX
+ virtual void APICALL getDirectory() {} //JP-EX
+ virtual void APICALL printLog(LogBuffer::TYPE, const char *) {}
+ virtual void APICALL addChannel(ChanInfo *) {}
+ virtual void APICALL delChannel(ChanInfo *) {}
+ virtual void APICALL resetChannels() {}
+ virtual void APICALL test(char *) {}
+ virtual const char *APICALL getClientTypeOS() = 0;
+ virtual void APICALL updateSettings() {}
+
+ virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {}
+ virtual void APICALL channelStart(ChanInfo *) {}
+ virtual void APICALL channelStop(ChanInfo *) {}
+ virtual void APICALL channelUpdate(ChanInfo *) {}
+};
+
+
+// ----------------------------------
+extern PeercastInstance *peercastInst;
+extern PeercastApplication *peercastApp;
+
+// ----------------------------------
+#ifdef WIN32
+extern "C"
+{
+__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *);
+};
+#endif
+
+// ----------------------------------
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : rtsp.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// RTSP protocol handling (experimental)
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "rtsp.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : rtsp.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _RTSP_H
+#define _RTSP_H
+
+#include "http.h"
+
+// ---------------------------------------------
+class RTSP : public HTTP
+{
+public:
+ RTSP(Stream &s):HTTP(s){}
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : servent.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Servents are the actual connections between clients. They do the handshaking,
+// transfering of data and processing of GnuPackets. Each servent has one socket allocated
+// to it on connect, it uses this to transfer all of its data.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+// todo: make lan->yp not check firewall
+
+#include <stdlib.h>
+#include "servent.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "html.h"
+#include "http.h"
+#include "stats.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+const int DIRECT_WRITE_TIMEOUT = 60;
+
+// -----------------------------------
+char *Servent::statusMsgs[]=
+{
+ "NONE",
+ "CONNECTING",
+ "PROTOCOL",
+ "HANDSHAKE",
+ "CONNECTED",
+ "CLOSING",
+ "LISTENING",
+ "TIMEOUT",
+ "REFUSED",
+ "VERIFIED",
+ "ERROR",
+ "WAIT",
+ "FREE"
+};
+
+// -----------------------------------
+char *Servent::typeMsgs[]=
+{
+ "NONE",
+ "INCOMING",
+ "SERVER",
+ "RELAY",
+ "DIRECT",
+ "COUT",
+ "CIN",
+ "PGNU"
+};
+// -----------------------------------
+bool Servent::isPrivate()
+{
+ Host h = getHost();
+ return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost();
+}
+// -----------------------------------
+bool Servent::isAllowed(int a)
+{
+ Host h = getHost();
+
+ if (servMgr->isFiltered(ServFilter::F_BAN,h))
+ return false;
+
+ return (allow&a)!=0;
+}
+
+// -----------------------------------
+bool Servent::isFiltered(int f)
+{
+ Host h = getHost();
+ return servMgr->isFiltered(f,h);
+}
+
+int servent_count = 1;
+// -----------------------------------
+Servent::Servent(int index)
+:outPacketsPri(MAX_OUTPACKETS)
+,outPacketsNorm(MAX_OUTPACKETS)
+,seenIDs(MAX_HASH)
+,serventIndex(index)
+,sock(NULL)
+,next(NULL)
+{
+ reset();
+ servent_id = servent_count++;
+ lastSkipTime = 0;
+ lastSkipCount = 0;
+ waitPort = 0;
+}
+
+// -----------------------------------
+Servent::~Servent()
+{
+
+}
+// -----------------------------------
+void Servent::kill()
+{
+ thread.active = false;
+
+ setStatus(S_CLOSING);
+
+ if (pcpStream)
+ {
+ PCPStream *pcp = pcpStream;
+ pcpStream = NULL;
+ pcp->kill();
+ delete pcp;
+ }
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = chanMgr->findHitListByID(chanID);
+ if (chl) {
+ ChanHit *chh = chl->hit;
+ ChanHit *prev = NULL;
+ while (chh) {
+ if (chh->servent_id == this->servent_id){
+ if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){
+ chh->numHops = 0;
+ chh->numListeners = 0;
+ chh->numRelays = 0;
+ prev = chh;
+ chh = chh->next;
+ } else {
+ ChanHit *next = chh->next;
+ if (prev)
+ prev->next = next;
+ else
+ chl->hit = next;
+
+ char ip0str[64],ip1str[64];
+ chh->rhost[0].toStr(ip0str);
+ chh->rhost[1].toStr(ip1str);
+ LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s",
+ chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str);
+
+ delete chh;
+ chh = next;
+ }
+ } else {
+ prev = chh;
+ chh = chh->next;
+ }
+ }
+ }
+ chanMgr->hitlistlock.off();
+
+ if (sock)
+ {
+ sock->close();
+ delete sock;
+ sock = NULL;
+ }
+
+ if (pushSock)
+ {
+ pushSock->close();
+ delete pushSock;
+ pushSock = NULL;
+ }
+
+// thread.unlock();
+
+ if (type != T_SERVER)
+ {
+ reset();
+ setStatus(S_FREE);
+ }
+
+}
+// -----------------------------------
+void Servent::abort()
+{
+ thread.active = false;
+ if (sock)
+ {
+ sock->close();
+ }
+
+}
+
+// -----------------------------------
+void Servent::reset()
+{
+
+ remoteID.clear();
+
+ servPort = 0;
+
+ pcpStream = NULL;
+
+ flowControl = false;
+ networkID.clear();
+
+ chanID.clear();
+
+ outputProtocol = ChanInfo::SP_UNKNOWN;
+
+ agent.clear();
+ sock = NULL;
+ allow = ALLOW_ALL;
+ syncPos = 0;
+ addMetadata = false;
+ nsSwitchNum = 0;
+ pack.func = 255;
+ lastConnect = lastPing = lastPacket = 0;
+ loginPassword[0] = 0;
+ loginMount[0] = 0;
+ bytesPerSecond = 0;
+ priorityConnect = false;
+ pushSock = NULL;
+ sendHeader = true;
+
+ outPacketsNorm.reset();
+ outPacketsPri.reset();
+
+ seenIDs.clear();
+
+ status = S_NONE;
+ type = T_NONE;
+
+ channel_id = 0;
+}
+// -----------------------------------
+bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t)
+{
+
+ if ( (type == t)
+ && (isConnected())
+ && (!cid.isSet() || chanID.isSame(cid))
+ && (!sid.isSet() || !sid.isSame(remoteID))
+ && (pcpStream != NULL)
+ )
+ {
+ return pcpStream->sendPacket(pack,did);
+ }
+ return false;
+}
+
+
+// -----------------------------------
+bool Servent::acceptGIV(ClientSocket *givSock)
+{
+ if (!pushSock)
+ {
+ pushSock = givSock;
+ return true;
+ }else
+ return false;
+}
+
+// -----------------------------------
+Host Servent::getHost()
+{
+ Host h(0,0);
+
+ if (sock)
+ h = sock->host;
+
+ return h;
+}
+
+// -----------------------------------
+bool Servent::outputPacket(GnuPacket &p, bool pri)
+{
+ lock.on();
+
+ bool r=false;
+ if (pri)
+ r = outPacketsPri.write(p);
+ else
+ {
+ if (servMgr->useFlowControl)
+ {
+ int per = outPacketsNorm.percentFull();
+ if (per > 50)
+ flowControl = true;
+ else if (per < 25)
+ flowControl = false;
+ }
+
+
+ bool send=true;
+ if (flowControl)
+ {
+ // if in flowcontrol, only allow packets with less of a hop count than already in queue
+ if (p.hops >= outPacketsNorm.findMinHop())
+ send = false;
+ }
+
+ if (send)
+ r = outPacketsNorm.write(p);
+ }
+
+ lock.off();
+ return r;
+}
+
+// -----------------------------------
+bool Servent::initServer(Host &h)
+{
+ try
+ {
+ checkFree();
+
+ status = S_WAIT;
+
+ createSocket();
+
+ sock->bind(h);
+
+ thread.data = this;
+
+ thread.func = serverProc;
+
+ type = T_SERVER;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Bad server: %s",e.msg);
+ kill();
+ return false;
+ }
+
+ return true;
+}
+// -----------------------------------
+void Servent::checkFree()
+{
+ if (sock)
+ throw StreamException("Socket already set");
+ if (thread.active)
+ throw StreamException("Thread already active");
+}
+// -----------------------------------
+void Servent::initIncoming(ClientSocket *s, unsigned int a)
+{
+
+ try{
+
+ checkFree();
+
+ type = T_INCOMING;
+ sock = s;
+ allow = a;
+ thread.data = this;
+ thread.func = incomingProc;
+
+ setStatus(S_PROTOCOL);
+
+ char ipStr[64];
+ sock->host.toStr(ipStr);
+ LOG_DEBUG("Incoming from %s",ipStr);
+
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+ }catch(StreamException &e)
+ {
+ //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg);
+ //servMgr->shutdownTimer = 1;
+ kill();
+
+ LOG_ERROR("INCOMING FAILED: %s",e.msg);
+
+ }
+}
+
+// -----------------------------------
+void Servent::initOutgoing(TYPE ty)
+{
+ try
+ {
+ checkFree();
+
+
+ type = ty;
+
+ thread.data = this;
+ thread.func = outgoingProc;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to start outgoing: %s",e.msg);
+ kill();
+ }
+}
+
+// -----------------------------------
+void Servent::initPCP(Host &rh)
+{
+ char ipStr[64];
+ rh.toStr(ipStr);
+ try
+ {
+ checkFree();
+
+ createSocket();
+
+ type = T_COUT;
+
+ sock->open(rh);
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw StreamException("Servent not allowed");
+
+ thread.data = this;
+ thread.func = outgoingProc;
+
+ LOG_DEBUG("Outgoing to %s",ipStr);
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg);
+ kill();
+ }
+}
+
+#if 0
+// -----------------------------------
+void Servent::initChannelFetch(Host &host)
+{
+ type = T_STREAM;
+
+ char ipStr[64];
+ host.toStr(ipStr);
+
+ checkFree();
+
+ createSocket();
+
+ sock->open(host);
+
+
+ if (!isAllowed(ALLOW_DATA))
+ throw StreamException("Servent not allowed");
+
+ sock->connect();
+}
+#endif
+
+// -----------------------------------
+void Servent::initGIV(Host &h, GnuID &id)
+{
+ char ipStr[64];
+ h.toStr(ipStr);
+ try
+ {
+ checkFree();
+
+ givID = id;
+
+ createSocket();
+
+ sock->open(h);
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw StreamException("Servent not allowed");
+
+ sock->connect();
+
+ thread.data = this;
+ thread.func = givProc;
+
+ type = T_RELAY;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("GIV error to %s: %s",ipStr,e.msg);
+ kill();
+ }
+}
+// -----------------------------------
+void Servent::createSocket()
+{
+ if (sock)
+ LOG_ERROR("Servent::createSocket attempt made while active");
+
+ sock = sys->createSocket();
+}
+// -----------------------------------
+void Servent::setStatus(STATUS s)
+{
+ if (s != status)
+ {
+ status = s;
+
+ if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING))
+ lastConnect = sys->getTime();
+ }
+
+}
+
+// -----------------------------------
+void Servent::handshakeOut()
+{
+ sock->writeLine(GNU_PEERCONN);
+
+ char str[64];
+
+ sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+ sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+ if (priorityConnect)
+ sock->writeLineF("%s %d",PCX_HS_PRIORITY,1);
+
+ if (networkID.isSet())
+ {
+ networkID.toStr(str);
+ sock->writeLineF("%s %s",PCX_HS_NETWORKID,str);
+ }
+
+ servMgr->sessionID.toStr(str);
+ sock->writeLineF("%s %s",PCX_HS_ID,str);
+
+
+ sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS());
+
+ sock->writeLine("");
+
+ HTTP http(*sock);
+
+ int r = http.readResponse();
+
+ if (r != 200)
+ {
+ LOG_ERROR("Expected 200, got %d",r);
+ throw StreamException("Unexpected HTTP response");
+ }
+
+
+ bool versionValid = false;
+
+ GnuID clientID;
+ clientID.clear();
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG(http.cmdLine);
+
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(HTTP_HS_AGENT))
+ {
+ agent.set(arg);
+
+ if (strnicmp(arg,"PeerCast/",9)==0)
+ versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+ }else if (http.isHeader(PCX_HS_NETWORKID))
+ clientID.fromStr(arg);
+ }
+
+ if (!clientID.isSame(networkID))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (!versionValid)
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+ sock->writeLine(GNU_OK);
+ sock->writeLine("");
+
+}
+
+
+// -----------------------------------
+void Servent::processOutChannel()
+{
+}
+
+
+// -----------------------------------
+void Servent::handshakeIn()
+{
+
+ int osType=0;
+
+ HTTP http(*sock);
+
+
+ bool versionValid = false;
+ bool diffRootVer = false;
+
+ GnuID clientID;
+ clientID.clear();
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG("%s",http.cmdLine);
+
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(HTTP_HS_AGENT))
+ {
+ agent.set(arg);
+
+ if (strnicmp(arg,"PeerCast/",9)==0)
+ {
+ versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+ diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0;
+ }
+ }else if (http.isHeader(PCX_HS_NETWORKID))
+ {
+ clientID.fromStr(arg);
+
+ }else if (http.isHeader(PCX_HS_PRIORITY))
+ {
+ priorityConnect = atoi(arg)!=0;
+
+ }else if (http.isHeader(PCX_HS_ID))
+ {
+ GnuID id;
+ id.fromStr(arg);
+ if (id.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else if (http.isHeader(PCX_HS_OS))
+ {
+ if (stricmp(arg,PCX_OS_LINUX)==0)
+ osType = 1;
+ else if (stricmp(arg,PCX_OS_WIN32)==0)
+ osType = 2;
+ else if (stricmp(arg,PCX_OS_MACOSX)==0)
+ osType = 3;
+ else if (stricmp(arg,PCX_OS_WINAMP2)==0)
+ osType = 4;
+ }
+
+ }
+
+ if (!clientID.isSame(networkID))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ // if this is a priority connection and all incoming connections
+ // are full then kill an old connection to make room. Otherwise reject connection.
+ //if (!priorityConnect)
+ {
+ if (!isPrivate())
+ if (servMgr->pubInFull())
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+ }
+
+ if (!versionValid)
+ throw HTTPException(HTTP_SC_FORBIDDEN,403);
+
+ sock->writeLine(GNU_OK);
+
+ sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT);
+
+ if (networkID.isSet())
+ {
+ char idStr[64];
+ networkID.toStr(idStr);
+ sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr);
+ }
+
+ if (servMgr->isRoot)
+ {
+ sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0);
+ sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL);
+ sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL);
+ sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast);
+ //sock->writeLine("%s %d",PCX_HS_FULLHIT,2);
+
+
+ if (diffRootVer)
+ {
+ sock->writeString(PCX_HS_DL);
+ sock->writeLine(PCX_DL_URL);
+ }
+
+ sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr());
+ }
+
+
+ char hostIP[64];
+ Host h = sock->host;
+ h.IPtoStr(hostIP);
+ sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP);
+
+
+ sock->writeLine("");
+
+
+ while (http.nextHeader());
+}
+
+// -----------------------------------
+bool Servent::pingHost(Host &rhost,GnuID &rsid)
+{
+ char ipstr[64];
+ rhost.toStr(ipstr);
+ LOG_DEBUG("Ping host %s: trying..",ipstr);
+ ClientSocket *s=NULL;
+ bool hostOK=false;
+ try
+ {
+ s = sys->createSocket();
+ if (!s)
+ return false;
+ else
+ {
+
+ s->setReadTimeout(15000);
+ s->setWriteTimeout(15000);
+ s->open(rhost);
+ s->connect();
+
+ AtomStream atom(*s);
+
+ atom.writeInt(PCP_CONNECT,1);
+ atom.writeParent(PCP_HELO,1);
+ atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+
+ GnuID sid;
+ sid.clear();
+
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+ if (id == PCP_OLEH)
+ {
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 pid = atom.read(c,d);
+ if (pid == PCP_SESSIONID)
+ atom.readBytes(sid.id,16,d);
+ else
+ atom.skip(c,d);
+ }
+ }else
+ {
+ LOG_DEBUG("Ping response: %s",id.getString().str());
+ throw StreamException("Bad ping response");
+ }
+
+ if (!sid.isSame(rsid))
+ throw StreamException("SIDs don`t match");
+
+ hostOK = true;
+ LOG_DEBUG("Ping host %s: OK",ipstr);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_DEBUG("Ping host %s: %s",ipstr,e.msg);
+ }
+ if (s)
+ {
+ s->close();
+ delete s;
+ }
+
+ if (!hostOK)
+ rhost.port = 0;
+
+ return true;
+}
+
+WLock canStreamLock;
+
+// -----------------------------------
+bool Servent::handshakeStream(ChanInfo &chanInfo)
+{
+
+ HTTP http(*sock);
+
+
+ bool gotPCP=false;
+ unsigned int reqPos=0;
+
+ nsSwitchNum=0;
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(PCX_HS_PCP))
+ gotPCP = atoi(arg)!=0;
+ else if (http.isHeader(PCX_HS_POS))
+ reqPos = atoi(arg);
+ else if (http.isHeader("icy-metadata"))
+ addMetadata = atoi(arg) > 0;
+ else if (http.isHeader(HTTP_HS_AGENT))
+ agent = arg;
+ else if (http.isHeader("Pragma"))
+ {
+ char *ssc = stristr(arg,"stream-switch-count=");
+ char *so = stristr(arg,"stream-offset");
+
+ if (ssc || so)
+ {
+ nsSwitchNum=1;
+ //nsSwitchNum = atoi(ssc+20);
+ }
+ }
+
+ LOG_DEBUG("Stream: %s",http.cmdLine);
+ }
+
+
+ if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP))
+ outputProtocol = ChanInfo::SP_PEERCAST;
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ if ( (chanInfo.srcProtocol == ChanInfo::SP_MMS)
+ || (chanInfo.contentType == ChanInfo::T_WMA)
+ || (chanInfo.contentType == ChanInfo::T_WMV)
+ || (chanInfo.contentType == ChanInfo::T_ASX)
+ )
+ outputProtocol = ChanInfo::SP_MMS;
+ }
+
+
+ bool chanFound=false;
+ bool chanReady=false;
+
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ {
+ sendHeader = true;
+// if (reqPos)
+// {
+// streamPos = ch->rawData.findOldestPos(reqPos);
+// }else
+// {
+ streamPos = ch->rawData.getLatestPos();
+// }
+
+ chanID = chanInfo.id;
+ canStreamLock.on();
+ chanReady = canStream(ch);
+ if (!chanReady) type = T_INCOMING;
+ thread.active = chanReady;
+ setStatus(S_CONNECTED);
+ canStreamLock.off();
+ channel_id = ch->channel_id;
+
+ //JP-Patch add-s
+ if (servMgr->isCheckPushStream())
+ {
+ if (chanReady == true)
+ {
+ Host h = getHost();
+
+ if (!h.isLocalhost())
+ {
+ do
+ {
+ if (strstr(agent.cstr(),"PeerCast/0.119") != NULL)
+ {
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr());
+ chanReady = false;
+ break;
+ }
+
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+ bool isfw = false;
+ int numRelay = 0;
+ for(int i=0; i<numHits; i++)
+ {
+ ChanHitList *chl = hits[i];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++)
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ if (hit->firewalled)
+ isfw = true;
+ numRelay = hit->numRelays;
+ }
+ }
+ }
+ }
+ if ((isfw == true) && (numRelay == 0))
+ {
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block firewalled Servent : %s",strip);
+ chanReady = false;
+ }*/
+
+ ChanHitList *chl = chanMgr->findHitList(chanInfo);
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ if ((hit->firewalled) && (hit->numRelays == 0)){
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block firewalled Servent : %s",strip);
+ chanReady = false;
+ }
+ }
+ hit = hit->next;
+ }
+ }while (0);
+ }
+ }
+ }
+ //JP-Patch add-e
+ }
+
+// LockBlock lockblock(chanMgr->hitlistlock);
+
+// lockblock.lockon();
+ ChanHitList *chl = chanMgr->findHitList(chanInfo);
+
+ if (chl)
+ {
+ chanFound = true;
+ }
+
+
+ bool result = false;
+
+ char idStr[64];
+ chanInfo.id.toStr(idStr);
+
+ char sidStr[64];
+ servMgr->sessionID.toStr(sidStr);
+
+ Host rhost = sock->host;
+
+
+
+
+ AtomStream atom(*sock);
+
+
+
+ if (!chanFound)
+ {
+ sock->writeLine(HTTP_SC_NOTFOUND);
+ sock->writeLine("");
+ LOG_DEBUG("Sending channel not found");
+ return false;
+ }
+
+
+ if (!chanReady)
+ {
+ if (outputProtocol == ChanInfo::SP_PCP)
+ {
+
+ char tbuf[8196];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ mem.writeLine(HTTP_SC_UNAVAILABLE);
+ mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+ mem.writeLine("");
+ sock->write(tbuf, mem.getPosition());
+
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+ char ripStr[64];
+ rhost.toStr(ripStr);
+
+ LOG_DEBUG("Sending channel unavailable");
+
+ ChanHitSearch chs;
+
+ mem.rewind();
+ AtomStream atom2(mem);
+
+ int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+
+ chanMgr->hitlistlock.on();
+
+ chl = chanMgr->findHitList(chanInfo);
+
+ if (chl)
+ {
+ ChanHit best;
+
+ // search for up to 8 other hits
+ int cnt=0;
+ for(int i=0; i<8; i++)
+ {
+ best.init();
+
+
+ // find best hit this network if local IP
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit this network if local IP");
+ }
+ }
+
+ // find best hit on same network
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit on same network");
+ }
+
+ }
+
+ // find best hit on other networks
+/* if (!best.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit on other networks");
+ }
+
+ }*/
+
+ if (!best.host.ip)
+ break;
+
+ best.writeAtoms(atom2,chanInfo.id);
+ cnt++;
+ }
+
+ if (!best.host.ip){
+ char tmp[50];
+// chanMgr->hitlistlock.on();
+ int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl);
+// chanMgr->hitlistlock.off();
+ for (int i = 0; i < cnt; i++){
+ chs.best[i].writeAtoms(atom2, chanInfo.id);
+ chs.best[i].host.toStr(tmp);
+ LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops);
+ best.host.ip = chs.best[i].host.ip;
+ }
+ }
+
+ if (cnt)
+ {
+ LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr);
+
+ }
+ else if (rhost.port)
+ {
+ // find firewalled host
+ chs.init();
+ chs.waitDelay = 30;
+ chs.useFirewalled = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ {
+ best = chs.best[0];
+ int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY);
+ LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr);
+ }
+ }
+
+ // if all else fails, use tracker
+ if (!best.host.ip)
+ {
+ // find best tracker on this network if local IP
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+
+ }
+
+ // find local tracker
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // find global tracker
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ if (best.host.ip)
+ {
+ best.writeAtoms(atom2,chanInfo.id);
+ LOG_DEBUG("Sent 1 tracker hit to %s",ripStr);
+ }else if (rhost.port)
+ {
+ // find firewalled tracker
+ chs.init();
+ chs.useFirewalled = true;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ chs.waitDelay = 30;
+ if (chl->pickHits(chs))
+ {
+ best = chs.best[0];
+ int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN);
+ LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr);
+ }
+ }
+
+ }
+
+
+ }
+
+ chanMgr->hitlistlock.off();
+
+ // return not available yet code
+ atom2.writeInt(PCP_QUIT,error);
+ sock->write(tbuf, mem.getPosition());
+ result = false;
+
+ /*
+ char c[512];
+ // wait disconnect from other host
+ try{
+ while(sock->read(c, sizeof(c))){
+ sys->sleep(10);
+ }
+ }catch(StreamException &e){
+ LOG_DEBUG("RelayInfoWait: %s",e.msg);
+ }
+ */
+ }else
+ {
+ LOG_DEBUG("Sending channel unavailable");
+ sock->writeLine(HTTP_SC_UNAVAILABLE);
+ sock->writeLine("");
+ result = false;
+ }
+
+ } else {
+
+ if (chanInfo.contentType != ChanInfo::T_MP3)
+ addMetadata=false;
+
+ if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP)) // winamp mp3 metadata check
+ {
+
+ sock->writeLine(ICY_OK);
+
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("icy-name:%s",chanInfo.name.cstr());
+ sock->writeLineF("icy-br:%d",chanInfo.bitrate);
+ sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr());
+ sock->writeLineF("icy-url:%s",chanInfo.url.cstr());
+ sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval);
+ sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+
+ }else
+ {
+
+ sock->writeLine(HTTP_SC_OK);
+
+ if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA))
+ {
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+ sock->writeLine("Accept-Ranges: none");
+
+ sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr());
+ sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate);
+ sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr());
+ sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr());
+ sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr());
+ sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+ }
+
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ switch (chanInfo.contentType)
+ {
+ case ChanInfo::T_OGG:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG);
+ break;
+ case ChanInfo::T_MP3:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+ break;
+ case ChanInfo::T_MOV:
+ sock->writeLine("Connection: close");
+ sock->writeLine("Content-Length: 10000000");
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV);
+ break;
+ case ChanInfo::T_MPG:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG);
+ break;
+ case ChanInfo::T_NSV:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV);
+ break;
+ case ChanInfo::T_ASX:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX);
+ break;
+ case ChanInfo::T_WMA:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA);
+ break;
+ case ChanInfo::T_WMV:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV);
+ break;
+ }
+ } else if (outputProtocol == ChanInfo::SP_MMS)
+ {
+ sock->writeLine("Server: Rex/9.0.0.2980");
+ sock->writeLine("Cache-Control: no-cache");
+ sock->writeLine("Pragma: no-cache");
+ sock->writeLine("Pragma: client-id=3587303426");
+ sock->writeLine("Pragma: features=\"broadcast,playlist\"");
+
+ if (nsSwitchNum)
+ {
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS);
+ }else
+ {
+ sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1");
+ if (ch)
+ sock->writeLineF("Content-Length: %d",ch->headPack.len);
+ sock->writeLine("Connection: Keep-Alive");
+ }
+
+ } else if (outputProtocol == ChanInfo::SP_PCP)
+ {
+ sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+
+ }else if (outputProtocol == ChanInfo::SP_PEERCAST)
+ {
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST);
+ }
+ }
+ sock->writeLine("");
+ result = true;
+
+ if (gotPCP)
+ {
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+ atom.writeInt(PCP_OK,0);
+ }
+
+ }
+
+
+
+ return result;
+}
+
+// -----------------------------------
+void Servent::handshakeGiv(GnuID &id)
+{
+ if (id.isSet())
+ {
+ char idstr[64];
+ id.toStr(idstr);
+ sock->writeLineF("GIV /%s",idstr);
+ }else
+ sock->writeLine("GIV");
+
+ sock->writeLine("");
+}
+
+
+// -----------------------------------
+void Servent::processGnutella()
+{
+ type = T_PGNU;
+
+ //if (servMgr->isRoot && !servMgr->needConnections())
+ if (servMgr->isRoot)
+ {
+ processRoot();
+ return;
+ }
+
+
+
+ gnuStream.init(sock);
+ setStatus(S_CONNECTED);
+
+ if (!servMgr->isRoot)
+ {
+ chanMgr->broadcastRelays(this, 1, 1);
+ GnuPacket *p;
+
+ if ((p=outPacketsNorm.curr()))
+ gnuStream.sendPacket(*p);
+ return;
+ }
+
+ gnuStream.ping(2);
+
+// if (type != T_LOOKUP)
+// chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2);
+
+ lastPacket = lastPing = sys->getTime();
+ bool doneBigPing=false;
+
+ const unsigned int abortTimeoutSecs = 60; // abort connection after 60 secs of no activitiy
+ const unsigned int packetTimeoutSecs = 30; // ping connection after 30 secs of no activity
+
+ unsigned int currBytes=0;
+ unsigned int lastWait=0;
+
+ unsigned int lastTotalIn=0,lastTotalOut=0;
+
+ while (thread.active && sock->active())
+ {
+
+ if (sock->readReady())
+ {
+ lastPacket = sys->getTime();
+
+ if (gnuStream.readPacket(pack))
+ {
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ GnuID routeID;
+ GnuStream::R_TYPE ret = GnuStream::R_PROCESS;
+
+ if (pack.func != GNU_FUNC_PONG)
+ if (servMgr->seenPacket(pack))
+ ret = GnuStream::R_DUPLICATE;
+
+ seenIDs.add(pack.id);
+
+
+ if (ret == GnuStream::R_PROCESS)
+ {
+ GnuID routeID;
+ ret = gnuStream.processPacket(pack,this,routeID);
+
+ if (flowControl && (ret == GnuStream::R_BROADCAST))
+ ret = GnuStream::R_DROP;
+
+ }
+
+ switch(ret)
+ {
+ case GnuStream::R_BROADCAST:
+ if (servMgr->broadcast(pack,this))
+ stats.add(Stats::NUMBROADCASTED);
+ else
+ stats.add(Stats::NUMDROPPED);
+ break;
+ case GnuStream::R_ROUTE:
+ if (servMgr->route(pack,routeID,NULL))
+ stats.add(Stats::NUMROUTED);
+ else
+ stats.add(Stats::NUMDROPPED);
+ break;
+ case GnuStream::R_ACCEPTED:
+ stats.add(Stats::NUMACCEPTED);
+ break;
+ case GnuStream::R_DUPLICATE:
+ stats.add(Stats::NUMDUP);
+ break;
+ case GnuStream::R_DEAD:
+ stats.add(Stats::NUMDEAD);
+ break;
+ case GnuStream::R_DISCARD:
+ stats.add(Stats::NUMDISCARDED);
+ break;
+ case GnuStream::R_BADVERSION:
+ stats.add(Stats::NUMOLD);
+ break;
+ case GnuStream::R_DROP:
+ stats.add(Stats::NUMDROPPED);
+ break;
+ }
+
+
+ LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr);
+
+
+
+ }else{
+ LOG_ERROR("Bad packet");
+ }
+ }
+
+
+ GnuPacket *p;
+
+ if ((p=outPacketsPri.curr())) // priority packet
+ {
+ gnuStream.sendPacket(*p);
+ seenIDs.add(p->id);
+ outPacketsPri.next();
+ } else if ((p=outPacketsNorm.curr())) // or.. normal packet
+ {
+ gnuStream.sendPacket(*p);
+ seenIDs.add(p->id);
+ outPacketsNorm.next();
+ }
+
+ int lpt = sys->getTime()-lastPacket;
+
+ if (!doneBigPing)
+ {
+ if ((sys->getTime()-lastPing) > 15)
+ {
+ gnuStream.ping(7);
+ lastPing = sys->getTime();
+ doneBigPing = true;
+ }
+ }else{
+ if (lpt > packetTimeoutSecs)
+ {
+
+ if ((sys->getTime()-lastPing) > packetTimeoutSecs)
+ {
+ gnuStream.ping(1);
+ lastPing = sys->getTime();
+ }
+
+ }
+ }
+ if (lpt > abortTimeoutSecs)
+ throw TimeoutException();
+
+
+ unsigned int totIn = sock->totalBytesIn-lastTotalIn;
+ unsigned int totOut = sock->totalBytesOut-lastTotalOut;
+
+ unsigned int bytes = totIn+totOut;
+
+ lastTotalIn = sock->totalBytesIn;
+ lastTotalOut = sock->totalBytesOut;
+
+ const int serventBandwidth = 1000;
+
+ int delay = sys->idleSleepTime;
+ if ((bytes) && (serventBandwidth >= 8))
+ delay = (bytes*1000)/(serventBandwidth/8); // set delay relative packetsize
+
+ if (delay < (int)sys->idleSleepTime)
+ delay = sys->idleSleepTime;
+ //LOG("delay %d, in %d, out %d",delay,totIn,totOut);
+
+ sys->sleep(delay);
+ }
+
+}
+
+
+// -----------------------------------
+void Servent::processRoot()
+{
+ try
+ {
+
+ gnuStream.init(sock);
+ setStatus(S_CONNECTED);
+
+ gnuStream.ping(2);
+
+ unsigned int lastConnect = sys->getTime();
+
+ while (thread.active && sock->active())
+ {
+ if (gnuStream.readPacket(pack))
+ {
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ LOG_NETWORK("packet in: %d from %s",pack.func,ipstr);
+
+
+ if (pack.func == GNU_FUNC_PING) // if ping then pong back some hosts and close
+ {
+
+ Host hl[32];
+ int cnt = servMgr->getNewestServents(hl,32,sock->host);
+ if (cnt)
+ {
+ int start = sys->rnd() % cnt;
+ int max = cnt>8?8:cnt;
+
+ for(int i=0; i<max; i++)
+ {
+ GnuPacket pong;
+ pack.hops = 1;
+ pong.initPong(hl[start],false,pack);
+ gnuStream.sendPacket(pong);
+
+ char ipstr[64];
+ hl[start].toStr(ipstr);
+
+ //LOG_NETWORK("Pong %d: %s",start+1,ipstr);
+ start = (start+1) % cnt;
+ }
+ char str[64];
+ sock->host.toStr(str);
+ LOG_NETWORK("Sent %d pong(s) to %s",max,str);
+ }else
+ {
+ LOG_NETWORK("No Pongs to send");
+ //return;
+ }
+ }else if (pack.func == GNU_FUNC_PONG) // pong?
+ {
+ MemoryStream pong(pack.data,pack.len);
+
+ int ip,port;
+ port = pong.readShort();
+ ip = pong.readLong();
+ ip = SWAP4(ip);
+
+
+ Host h(ip,port);
+ if ((ip) && (port) && (h.globalIP()))
+ {
+
+ LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port);
+ servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+ }
+ //return;
+ } else if (pack.func == GNU_FUNC_HIT)
+ {
+ MemoryStream data(pack.data,pack.len);
+ ChanHit hit;
+ gnuStream.readHit(data,hit,pack.hops,pack.id);
+ }
+
+ //if (gnuStream.packetsIn > 5) // die if we get too many packets
+ // return;
+ }
+
+ if((sys->getTime()-lastConnect > 60))
+ break;
+ }
+
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Relay: %s",e.msg);
+ }
+
+
+}
+
+// -----------------------------------
+int Servent::givProc(ThreadInfo *thread)
+{
+// thread->lock();
+ Servent *sv = (Servent*)thread->data;
+ try
+ {
+ sv->handshakeGiv(sv->givID);
+ sv->handshakeIncoming();
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("GIV: %s",e.msg);
+ }
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+
+// -----------------------------------
+void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted)
+{
+
+ bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON);
+ bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN);
+
+ bool sendBCID = isTrusted && chanMgr->isBroadcasting();
+
+ char tbuf[1024];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ AtomStream atom2(mem);
+ atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0));
+ atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+ atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+ atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ if (nonFW)
+ atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port);
+ if (testFW)
+ atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port);
+ if (sendBCID)
+ atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16);
+ atom.io.write(tbuf, mem.getPosition());
+
+
+ LOG_DEBUG("PCP outgoing waiting for OLEH..");
+
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+ if (id != PCP_OLEH)
+ {
+ LOG_DEBUG("PCP outgoing reply: %s",id.getString().str());
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+ throw StreamException("Got unexpected PCP response");
+ }
+
+
+
+ char arg[64];
+
+ GnuID clientID;
+ clientID.clear();
+ rid.clear();
+ int version=0;
+ int disable=0;
+
+ Host thisHost;
+
+ // read OLEH response
+ for(int i=0; i<numc; i++)
+ {
+ int c,dlen;
+ ID4 id = atom.read(c,dlen);
+
+ if (id == PCP_HELO_AGENT)
+ {
+ atom.readString(arg,sizeof(arg),dlen);
+ agent.set(arg);
+
+ }else if (id == PCP_HELO_REMOTEIP)
+ {
+ thisHost.ip = atom.readInt();
+
+ }else if (id == PCP_HELO_PORT)
+ {
+ thisHost.port = atom.readShort();
+
+ }else if (id == PCP_HELO_VERSION)
+ {
+ version = atom.readInt();
+
+ }else if (id == PCP_HELO_DISABLE)
+ {
+ disable = atom.readInt();
+
+ }else if (id == PCP_HELO_SESSIONID)
+ {
+ atom.readBytes(rid.id,16);
+ if (rid.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else
+ {
+ LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+ atom.skip(c,dlen);
+ }
+
+ }
+
+
+ // update server ip/firewall status
+ if (isTrusted)
+ {
+ if (thisHost.isValid())
+ {
+ if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty()))
+ {
+ char ipstr[64];
+ thisHost.toStr(ipstr);
+ LOG_DEBUG("Got new ip: %s",ipstr);
+ servMgr->serverHost.ip = thisHost.ip;
+ }
+
+ if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN)
+ {
+ if (thisHost.port && thisHost.globalIP())
+ servMgr->setFirewall(ServMgr::FW_OFF);
+ else
+ servMgr->setFirewall(ServMgr::FW_ON);
+ }
+ }
+
+ if (disable == 1)
+ {
+ LOG_ERROR("client disabled: %d",disable);
+ servMgr->isDisabled = true;
+ }else
+ {
+ servMgr->isDisabled = false;
+ }
+ }
+
+
+
+ if (!rid.isSet())
+ {
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+ throw StreamException("Remote host not identified");
+ }
+
+ LOG_DEBUG("PCP Outgoing handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent)
+{
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+
+
+ if (id != PCP_HELO)
+ {
+ LOG_DEBUG("PCP incoming reply: %s",id.getString().str());
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+ throw StreamException("Got unexpected PCP response");
+ }
+
+ char arg[64];
+
+ ID4 osType;
+
+ int version=0;
+
+ int pingPort=0;
+
+ GnuID bcID;
+ GnuID clientID;
+
+ bcID.clear();
+ clientID.clear();
+
+ rhost.port = 0;
+
+ for(int i=0; i<numc; i++)
+ {
+
+ int c,dlen;
+ ID4 id = atom.read(c,dlen);
+
+ if (id == PCP_HELO_AGENT)
+ {
+ atom.readString(arg,sizeof(arg),dlen);
+ agent.set(arg);
+
+ }else if (id == PCP_HELO_VERSION)
+ {
+ version = atom.readInt();
+
+ }else if (id == PCP_HELO_SESSIONID)
+ {
+ atom.readBytes(rid.id,16);
+ if (rid.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else if (id == PCP_HELO_BCID)
+ {
+ atom.readBytes(bcID.id,16);
+
+ }else if (id == PCP_HELO_OSTYPE)
+ {
+ osType = atom.readInt();
+ }else if (id == PCP_HELO_PORT)
+ {
+ rhost.port = atom.readShort();
+ }else if (id == PCP_HELO_PING)
+ {
+ pingPort = atom.readShort();
+ }else
+ {
+ LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+ atom.skip(c,dlen);
+ }
+
+ }
+
+ if (version)
+ LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version);
+
+
+ if (!rhost.globalIP() && servMgr->serverHost.globalIP())
+ rhost.ip = servMgr->serverHost.ip;
+
+ if (pingPort)
+ {
+ char ripStr[64];
+ rhost.toStr(ripStr);
+ LOG_DEBUG("Incoming firewalled test request: %s ", ripStr);
+ rhost.port = pingPort;
+ if (!rhost.globalIP() || !pingHost(rhost,rid))
+ rhost.port = 0;
+ }
+
+ if (servMgr->isRoot)
+ {
+ if (bcID.isSet())
+ {
+ if (bcID.getFlags() & 1) // private
+ {
+ BCID *bcid = servMgr->findValidBCID(bcID);
+ if (!bcid || (bcid && !bcid->valid))
+ {
+ atom.writeParent(PCP_OLEH,1);
+ atom.writeInt(PCP_HELO_DISABLE,1);
+ throw StreamException("Client is banned");
+ }
+ }
+ }
+ }
+
+
+ char tbuf[1024];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ AtomStream atom2(mem);
+ atom2.writeParent(PCP_OLEH,5);
+ atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+ atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+ atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip);
+ atom2.writeShort(PCP_HELO_PORT,rhost.port);
+
+ if (version)
+ {
+ if (version < PCP_CLIENT_MINVERSION)
+ {
+ atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT);
+ atom.io.write(tbuf, mem.getPosition());
+ throw StreamException("Agent is not valid");
+ }
+ }
+
+ if (!rid.isSet())
+ {
+ atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+ atom.io.write(tbuf, mem.getPosition());
+ throw StreamException("Remote host not identified");
+ }
+
+
+
+ if (servMgr->isRoot)
+ {
+ servMgr->writeRootAtoms(atom2,false);
+ }
+
+ atom.io.write(tbuf, mem.getPosition());
+
+ LOG_DEBUG("PCP Incoming handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::processIncomingPCP(bool suggestOthers)
+{
+ PCPStream::readVersion(*sock);
+
+
+ AtomStream atom(*sock);
+ Host rhost = sock->host;
+
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+
+ bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL)
+ || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL);
+ bool unavailable = servMgr->controlInFull();
+ bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting();
+
+ char rstr[64];
+ rhost.toStr(rstr);
+
+ if (unavailable || alreadyConnected || offair)
+ {
+ int error;
+
+ if (alreadyConnected)
+ error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED;
+ else if (unavailable)
+ error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+ else if (offair)
+ error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR;
+ else
+ error = PCP_ERROR_QUIT;
+
+
+ if (suggestOthers)
+ {
+
+ ChanHit best;
+ ChanHitSearch chs;
+
+ int cnt=0;
+ for(int i=0; i<8; i++)
+ {
+ best.init();
+
+ // find best hit on this network
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // find best hit on same network
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // else find best hit on other networks
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ if (!best.host.ip)
+ break;
+
+ GnuID noID;
+ noID.clear();
+ best.writeAtoms(atom,noID);
+ cnt++;
+ }
+ if (cnt)
+ {
+ LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr);
+ }
+ else if (rhost.port)
+ {
+ // send push request to best firewalled tracker on other network
+ chs.init();
+ chs.waitDelay = 30;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useFirewalled = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ {
+ best = chs.best[0];
+ GnuID noID;
+ noID.clear();
+ int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN);
+ LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr);
+ }
+ }else
+ {
+ LOG_DEBUG("No available trackers");
+ }
+ }
+
+
+ LOG_ERROR("Sending QUIT to incoming: %d",error);
+
+ atom.writeInt(PCP_QUIT,error);
+ return;
+ }
+
+
+ type = T_CIN;
+ setStatus(S_CONNECTED);
+
+ atom.writeInt(PCP_OK,0);
+
+ // ask for update
+ atom.writeParent(PCP_ROOT,1);
+ atom.writeParent(PCP_ROOT_UPDATE,0);
+
+ pcpStream = new PCPStream(remoteID);
+
+ int error = 0;
+ BroadcastState bcs;
+ while (!error && thread.active && !sock->eof())
+ {
+ error = pcpStream->readPacket(*sock,bcs);
+ sys->sleepIdle();
+
+ if (!servMgr->isRoot && !chanMgr->isBroadcasting())
+ error = PCP_ERROR_OFFAIR;
+ if (peercastInst->isQuitting)
+ error = PCP_ERROR_SHUTDOWN;
+ }
+
+ pcpStream->flush(*sock);
+
+ error += PCP_ERROR_QUIT;
+ atom.writeInt(PCP_QUIT,error);
+
+ LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error);
+
+}
+
+// -----------------------------------
+int Servent::outgoingProc(ThreadInfo *thread)
+{
+// thread->lock();
+ LOG_DEBUG("COUT started");
+
+ Servent *sv = (Servent*)thread->data;
+
+ GnuID noID;
+ noID.clear();
+ sv->pcpStream = new PCPStream(noID);
+
+ while (sv->thread.active)
+ {
+ sv->setStatus(S_WAIT);
+
+ if (chanMgr->isBroadcasting() && servMgr->autoServe)
+ {
+ ChanHit bestHit;
+ ChanHitSearch chs;
+ char ipStr[64];
+
+ do
+ {
+ bestHit.init();
+
+ if (servMgr->rootHost.isEmpty())
+ break;
+
+ if (sv->pushSock)
+ {
+ sv->sock = sv->pushSock;
+ sv->pushSock = NULL;
+ bestHit.host = sv->sock->host;
+ break;
+ }
+
+ GnuID noID;
+ noID.clear();
+ ChanHitList *chl = chanMgr->findHitListByID(noID);
+ if (chl)
+ {
+ // find local tracker
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (!chl->pickHits(chs))
+ {
+ // else find global tracker
+ chs.init();
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ chl->pickHits(chs);
+ }
+
+ if (chs.numResults)
+ {
+ bestHit = chs.best[0];
+ }
+ }
+
+
+ unsigned int ctime = sys->getTime();
+
+ if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY))
+ {
+ bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+ bestHit.yp = true;
+ chanMgr->lastYPConnect = ctime;
+ }
+ sys->sleepIdle();
+
+ }while (!bestHit.host.ip && (sv->thread.active));
+
+
+ if (!bestHit.host.ip) // give up
+ {
+ LOG_ERROR("COUT giving up");
+ break;
+ }
+
+
+ bestHit.host.toStr(ipStr);
+
+ int error=0;
+ try
+ {
+
+ LOG_DEBUG("COUT to %s: Connecting..",ipStr);
+
+ if (!sv->sock)
+ {
+ sv->setStatus(S_CONNECTING);
+ sv->sock = sys->createSocket();
+ if (!sv->sock)
+ throw StreamException("Unable to create socket");
+ sv->sock->open(bestHit.host);
+ sv->sock->connect();
+
+ }
+
+ sv->sock->setReadTimeout(30000);
+ AtomStream atom(*sv->sock);
+
+ sv->setStatus(S_HANDSHAKE);
+
+ Host rhost = sv->sock->host;
+ atom.writeInt(PCP_CONNECT,1);
+ handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp);
+
+ sv->setStatus(S_CONNECTED);
+
+ LOG_DEBUG("COUT to %s: OK",ipStr);
+
+ sv->pcpStream->init(sv->remoteID);
+
+ BroadcastState bcs;
+ bcs.servent_id = sv->servent_id;
+ error = 0;
+ while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe)
+ {
+ error = sv->pcpStream->readPacket(*sv->sock,bcs);
+
+ sys->sleepIdle();
+
+ if (!chanMgr->isBroadcasting())
+ error = PCP_ERROR_OFFAIR;
+ if (peercastInst->isQuitting)
+ error = PCP_ERROR_SHUTDOWN;
+
+ if (sv->pcpStream->nextRootPacket)
+ if (sys->getTime() > (sv->pcpStream->nextRootPacket+30))
+ error = PCP_ERROR_NOROOT;
+ }
+ sv->setStatus(S_CLOSING);
+
+ sv->pcpStream->flush(*sv->sock);
+
+ error += PCP_ERROR_QUIT;
+ atom.writeInt(PCP_QUIT,error);
+
+ LOG_ERROR("COUT to %s closed: %d",ipStr,error);
+
+ }catch(TimeoutException &e)
+ {
+ LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg);
+ sv->setStatus(S_TIMEOUT);
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("COUT to %s: %s",ipStr,e.msg);
+ sv->setStatus(S_ERROR);
+ }
+
+ try
+ {
+ if (sv->sock)
+ {
+ sv->sock->close();
+ delete sv->sock;
+ sv->sock = NULL;
+ }
+
+ }catch(StreamException &) {}
+
+ // don`t discard this hit if we caused the disconnect (stopped broadcasting)
+ if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR))
+ chanMgr->deadHit(bestHit);
+
+ }
+
+ sys->sleepIdle();
+ }
+
+ sv->kill();
+ sys->endThread(thread);
+ LOG_DEBUG("COUT ended");
+ return 0;
+}
+// -----------------------------------
+int Servent::incomingProc(ThreadInfo *thread)
+{
+// thread->lock();
+
+ Servent *sv = (Servent*)thread->data;
+
+ char ipStr[64];
+ sv->sock->host.toStr(ipStr);
+
+ try
+ {
+ sv->handshakeIncoming();
+ }catch(HTTPException &e)
+ {
+ try
+ {
+ sv->sock->writeLine(e.msg);
+ if (e.code == 401)
+ sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\"");
+ sv->sock->writeLine("");
+ }catch(StreamException &){}
+ LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+ }
+
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+// -----------------------------------
+void Servent::processServent()
+{
+ setStatus(S_HANDSHAKE);
+
+ handshakeIn();
+
+ if (!sock)
+ throw StreamException("Servent has no socket");
+
+ processGnutella();
+}
+
+// -----------------------------------
+void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo)
+{
+ if (!doneHandshake)
+ {
+ setStatus(S_HANDSHAKE);
+
+ if (!handshakeStream(chanInfo))
+ return;
+ }
+
+ if (chanInfo.id.isSet())
+ {
+
+ chanID = chanInfo.id;
+
+ LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol));
+
+ if (!waitForChannelHeader(chanInfo))
+ throw StreamException("Channel not ready");
+
+ servMgr->totalStreams++;
+
+ Host host = sock->host;
+ host.port = 0; // force to 0 so we ignore the incoming port
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ if ((addMetadata) && (chanMgr->icyMetaInterval))
+ sendRawMetaChannel(chanMgr->icyMetaInterval);
+ else
+ sendRawChannel(true,true);
+
+ }else if (outputProtocol == ChanInfo::SP_MMS)
+ {
+ if (nsSwitchNum)
+ {
+ sendRawChannel(true,true);
+ }else
+ {
+ sendRawChannel(true,false);
+ }
+
+ }else if (outputProtocol == ChanInfo::SP_PCP)
+ {
+ sendPCPChannel();
+
+ } else if (outputProtocol == ChanInfo::SP_PEERCAST)
+ {
+ sendPeercastChannel();
+ }
+ }
+
+ setStatus(S_CLOSING);
+}
+
+// -----------------------------------------
+#if 0
+// debug
+ FileStream file;
+ file.openReadOnly("c://test.mp3");
+
+ LOG_DEBUG("raw file read");
+ char buf[4000];
+ int cnt=0;
+ while (!file.eof())
+ {
+ LOG_DEBUG("send %d",cnt++);
+ file.read(buf,sizeof(buf));
+ sock->write(buf,sizeof(buf));
+
+ }
+ file.close();
+ LOG_DEBUG("raw file sent");
+
+ return;
+// debug
+#endif
+// -----------------------------------
+bool Servent::waitForChannelHeader(ChanInfo &info)
+{
+ for(int i=0; i<30*10; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(info.id);
+ if (!ch)
+ return false;
+
+ if (ch->isPlaying() && (ch->rawData.writePos>0))
+ return true;
+
+ if (!thread.active || !sock->active())
+ break;
+ sys->sleep(100);
+ }
+ return false;
+}
+// -----------------------------------
+void Servent::sendRawChannel(bool sendHead, bool sendData)
+{
+ try
+ {
+
+ sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ setStatus(S_CONNECTED);
+
+ LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos);
+
+ if (sendHead)
+ {
+ ch->headPack.writeRaw(*sock);
+ streamPos = ch->headPack.pos + ch->headPack.len;
+ LOG_DEBUG("Sent %d bytes header ",ch->headPack.len);
+ }
+
+ if (sendData)
+ {
+
+ unsigned int streamIndex = ch->streamIndex;
+ unsigned int connectTime = sys->getTime();
+ unsigned int lastWriteTime = connectTime;
+
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ if (streamIndex != ch->streamIndex)
+ {
+ streamIndex = ch->streamIndex;
+ streamPos = ch->headPack.pos;
+ LOG_DEBUG("sendRaw got new stream index");
+ }
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if (syncPos != rawPack.sync)
+ LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+ syncPos = rawPack.sync+1;
+
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ {
+ rawPack.writeRaw(*sock);
+ lastWriteTime = sys->getTime();
+ }
+
+ if (rawPack.pos < streamPos)
+ LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos);
+ streamPos = rawPack.pos+rawPack.len;
+ } else if (sock->readReady()) {
+ char c;
+ int error = sock->readUpto(&c, 1);
+ if (error == 0) sock->close();
+ }
+ }
+
+ if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+ throw TimeoutException();
+
+ sys->sleepIdle();
+ }
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+
+#if 0
+// -----------------------------------
+void Servent::sendRawMultiChannel(bool sendHead, bool sendData)
+{
+ try
+ {
+ unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS];
+ unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS];
+ GnuID chanIDs[ChanMgr::MAX_CHANNELS];
+ int numChanIDs=0;
+ for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+ {
+ Channel *ch = &chanMgr->channels[i];
+ if (ch->isPlaying())
+ chanIDs[numChanIDs++]=ch->info.id;
+ }
+
+
+
+ setStatus(S_CONNECTED);
+
+
+ if (sendHead)
+ {
+ for(int i=0; i<numChanIDs; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+ if (ch)
+ {
+ LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr());
+ ch->headPack.writeRaw(*sock);
+ chanStreamPos[i] = ch->headPack.pos + ch->headPack.len;
+ chanStreamIndex[i] = ch->streamIndex;
+ LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+
+ }
+ }
+ }
+
+ if (sendData)
+ {
+
+ unsigned int connectTime=sys->getTime();
+
+ while ((thread.active) && sock->active())
+ {
+
+ for(int i=1; i<numChanIDs; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+ if (ch)
+ {
+ if (chanStreamIndex[i] != ch->streamIndex)
+ {
+ chanStreamIndex[i] = ch->streamIndex;
+ chanStreamPos[i] = ch->headPack.pos;
+ LOG_DEBUG("sendRawMulti got new stream index for chan %d",i);
+ }
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(chanStreamPos[i],rawPack))
+ {
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ rawPack.writeRaw(*sock);
+
+
+ if (rawPack.pos < chanStreamPos[i])
+ LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]);
+ chanStreamPos[i] = rawPack.pos+rawPack.len;
+
+
+ //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos));
+ }
+ }
+ break;
+ }
+
+
+ sys->sleepIdle();
+ }
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+#endif
+
+// -----------------------------------
+void Servent::sendRawMetaChannel(int interval)
+{
+
+ try
+ {
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+ setStatus(S_CONNECTED);
+
+ LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos);
+
+
+ String lastTitle,lastURL;
+
+ int lastMsgTime=sys->getTime();
+ bool showMsg=true;
+
+ char buf[16384];
+ int bufPos=0;
+
+ if ((interval > sizeof(buf)) || (interval < 1))
+ throw StreamException("Bad ICY Meta Interval value");
+
+ unsigned int connectTime = sys->getTime();
+ unsigned int lastWriteTime = connectTime;
+
+ streamPos = 0; // raw meta channel has no header (its MP3)
+
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+
+ if (syncPos != rawPack.sync)
+ LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+ syncPos = rawPack.sync+1;
+
+ MemoryStream mem(rawPack.data,rawPack.len);
+
+ if (rawPack.type == ChanPacket::T_DATA)
+ {
+
+ int len = rawPack.len;
+ char *p = rawPack.data;
+ while (len)
+ {
+ int rl = len;
+ if ((bufPos+rl) > interval)
+ rl = interval-bufPos;
+ memcpy(&buf[bufPos],p,rl);
+ bufPos+=rl;
+ p+=rl;
+ len-=rl;
+
+ if (bufPos >= interval)
+ {
+ bufPos = 0;
+ sock->write(buf,interval);
+ lastWriteTime = sys->getTime();
+
+ if (chanMgr->broadcastMsgInterval)
+ if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval)
+ {
+ showMsg ^= true;
+ lastMsgTime = sys->getTime();
+ }
+
+ String *metaTitle = &ch->info.track.title;
+ if (!ch->info.comment.isEmpty() && (showMsg))
+ metaTitle = &ch->info.comment;
+
+
+ if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL))
+ {
+
+ char tmp[1024];
+ String title,url;
+
+ title = *metaTitle;
+ url = ch->info.url;
+
+ title.convertTo(String::T_META);
+ url.convertTo(String::T_META);
+
+ sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr());
+ int len = ((strlen(tmp) + 15+1) / 16);
+ sock->writeChar(len);
+ sock->write(tmp,len*16);
+
+ lastTitle = *metaTitle;
+ lastURL = ch->info.url;
+
+ LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr());
+
+ }else
+ {
+ sock->writeChar(0);
+ }
+
+ }
+ }
+ }
+ streamPos = rawPack.pos + rawPack.len;
+ }
+ }
+ if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+ throw TimeoutException();
+
+ sys->sleepIdle();
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+// -----------------------------------
+void Servent::sendPeercastChannel()
+{
+ try
+ {
+ setStatus(S_CONNECTED);
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr());
+
+ sock->writeTag("PCST");
+
+ ChanPacket pack;
+
+ ch->headPack.writePeercast(*sock);
+
+ pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos);
+ pack.writePeercast(*sock);
+
+ streamPos = 0;
+ unsigned int syncPos=0;
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+ if (ch)
+ {
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ {
+ sock->writeTag("SYNC");
+ sock->writeShort(4);
+ sock->writeShort(0);
+ sock->write(&syncPos,4);
+ syncPos++;
+
+ rawPack.writePeercast(*sock);
+ }
+ streamPos = rawPack.pos + rawPack.len;
+ }
+ }
+ sys->sleepIdle();
+ }
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+
+//WLock canStreamLock;
+
+// -----------------------------------
+void Servent::sendPCPChannel()
+{
+ bool skipCheck = false;
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ AtomStream atom(*sock);
+
+ pcpStream = new PCPStream(remoteID);
+ int error=0;
+
+ try
+ {
+
+ LOG_DEBUG("Starting PCP stream of channel at %d",streamPos);
+
+
+// setStatus(S_CONNECTED);
+
+ //canStreamLock.on();
+ //thread.active = canStream(ch);
+ //setStatus(S_CONNECTED);
+ //canStreamLock.off();
+
+ lastSkipTime = 0;
+ lastSkipCount = 0;
+ waitPort = 0;
+
+ if (thread.active){
+ atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0));
+ atom.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ ch->info.writeInfoAtoms(atom);
+ ch->info.writeTrackAtoms(atom);
+ if (sendHeader)
+ {
+ atom.writeParent(PCP_CHAN_PKT,3);
+ atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+ atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos);
+ atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len);
+
+ streamPos = ch->headPack.pos+ch->headPack.len;
+ LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+ }
+ }
+
+ unsigned int streamIndex = ch->streamIndex;
+
+ ChanPacket rawPack;
+ char pbuf[ChanPacket::MAX_DATALEN*3];
+ MemoryStream mems(pbuf,sizeof(pbuf));
+ AtomStream atom2(mems);
+
+ while (thread.active)
+ {
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ if (streamIndex != ch->streamIndex)
+ {
+ streamIndex = ch->streamIndex;
+ streamPos = ch->headPack.pos;
+ LOG_DEBUG("sendPCPStream got new stream index");
+ }
+
+ mems.rewind();
+
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if ((streamPos < rawPack.pos) && !rawPack.skip){
+ if (skipCheck){
+ char tmp[32];
+ getHost().IPtoStr(tmp);
+ LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp);
+
+ if (sys->getTime() == lastSkipTime) {
+ LOG_DEBUG("##### skip all buffer");
+ streamPos = ch->rawData.getLatestPos();
+ continue;
+ }
+
+ lastSkipTime = sys->getTime();
+ lastSkipCount++;
+ } else {
+ skipCheck = true;
+ }
+ }
+
+ if (rawPack.type == ChanPacket::T_HEAD)
+ {
+ atom2.writeParent(PCP_CHAN,2);
+ atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ atom2.writeParent(PCP_CHAN_PKT,3);
+ atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+ atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+ atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+ sock->write(pbuf, mems.getPosition());
+ }else if (rawPack.type == ChanPacket::T_DATA)
+ {
+ atom2.writeParent(PCP_CHAN,2);
+ atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ atom2.writeParent(PCP_CHAN_PKT,3);
+ atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA);
+ atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+ atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+#ifdef WIN32
+ sock->bufferingWrite(pbuf, mems.getPosition());
+ lastSkipTime = sock->bufList.lastSkipTime;
+ lastSkipCount = sock->bufList.skipCount;
+#else
+ sock->write(pbuf, mems.getPosition());
+#endif
+ }
+
+ if (rawPack.pos < streamPos)
+ LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos);
+
+ //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos());
+
+ streamPos = rawPack.pos+rawPack.len;
+ }
+ } else {
+ pcpStream->flush(*sock);
+ throw StreamException("Channel not found");
+ }
+
+#ifdef WIN32
+ sock->bufferingWrite(NULL, 0);
+ lastSkipTime = sock->bufList.lastSkipTime;
+ lastSkipCount = sock->bufList.skipCount;
+#endif
+ BroadcastState bcs;
+ bcs.servent_id = servent_id;
+// error = pcpStream->readPacket(*sock,bcs);
+ do {
+ error = pcpStream->readPacket(*sock,bcs);
+ if (error)
+ throw StreamException("PCP exception");
+ } while (sock->readReady() || pcpStream->outData.numPending());
+
+ sys->sleepIdle();
+
+ }
+
+ LOG_DEBUG("PCP channel stream closed normally.");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+
+ try
+ {
+ atom.writeInt(PCP_QUIT,error);
+ }catch(StreamException &) {}
+
+}
+
+// -----------------------------------
+int Servent::serverProc(ThreadInfo *thread)
+{
+// thread->lock();
+
+
+ Servent *sv = (Servent*)thread->data;
+
+ try
+ {
+ if (!sv->sock)
+ throw StreamException("Server has no socket");
+
+ sv->setStatus(S_LISTENING);
+
+
+ char servIP[64];
+ sv->sock->host.toStr(servIP);
+
+ if (servMgr->isRoot)
+ LOG_DEBUG("Root Server started: %s",servIP);
+ else
+ LOG_DEBUG("Server started: %s",servIP);
+
+
+ while ((thread->active) && (sv->sock->active()))
+ {
+ if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn)
+ {
+ ClientSocket *cs = sv->sock->accept();
+ if (cs)
+ {
+ LOG_DEBUG("accepted incoming");
+ Servent *ns = servMgr->allocServent();
+ if (ns)
+ {
+ servMgr->lastIncoming = sys->getTime();
+ ns->servPort = sv->sock->host.port;
+ ns->networkID = servMgr->networkID;
+ ns->initIncoming(cs,sv->allow);
+ }else
+ LOG_ERROR("Out of servents");
+ }
+ }
+ sys->sleep(100);
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Server Error: %s:%d",e.msg,e.err);
+ }
+
+
+ LOG_DEBUG("Server stopped");
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+
+// -----------------------------------
+bool Servent::writeVariable(Stream &s, const String &var)
+{
+ char buf[1024];
+
+ if (var == "type")
+ strcpy(buf,getTypeStr());
+ else if (var == "status")
+ strcpy(buf,getStatusStr());
+ else if (var == "address")
+ {
+ if (servMgr->enableGetName) //JP-EX s
+ {
+ getHost().toStr(buf);
+ char h_ip[64];
+ Host h = getHost();
+ h.toStr(h_ip);
+
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+ bool ishit,isfw;
+ ishit = isfw = false;
+ int numRelay = 0;
+ if (numHits)
+ {
+ for(int k=0; k<numHits; k++)
+ {
+ ChanHitList *chl = hits[k];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++)
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ ishit = true;
+ if (hit->firewalled)
+ isfw = true;
+ numRelay += hit->numRelays;
+ }
+ }
+ }
+ }
+ }
+ strcpy(buf,"");
+ if (ishit == true)
+ {
+ if (isfw == true)
+ {
+ if (numRelay== 0)
+ strcat(buf,"<font color=red>");
+ else
+ strcat(buf,"<font color=orange>");
+ }
+ else
+ strcat(buf,"<font color=green>");
+ }
+ strcat(buf,h_ip);
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,h.ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ if (ishit == true)
+ {
+ strcat(buf,"</font>");
+ }
+ } //JP-EX e*/
+
+
+ bool isfw = false;
+ bool isRelay = true;
+ int numRelay = 0;
+ ChanHitList *chl = chanMgr->findHitListByID(chanID);
+ if (chl){
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if (hit->host.isValid() && (h.ip == hit->host.ip)){
+ isfw = hit->firewalled;
+ isRelay = hit->relay;
+ numRelay = hit->numRelays;
+ break;
+ }
+ hit = hit->next;
+ }
+ }
+ strcpy(buf, "");
+ if (isfw){
+ if (numRelay == 0){
+ strcat(buf,"<font color=red>");
+ } else {
+ strcat(buf,"<font color=orange>");
+ }
+ } else {
+ if (!isRelay){
+ if (numRelay==0){
+ strcpy(buf,"<font color=purple>");
+ } else {
+ strcpy(buf,"<font color=blue>");
+ }
+ } else {
+ strcpy(buf,"<font color=green>");
+ }
+ }
+ strcat(buf,h_ip);
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,h.ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ strcat(buf,"</font>");
+ }
+ else
+ getHost().toStr(buf);
+ }
+ else if (var == "agent")
+ strcpy(buf,agent.cstr());
+ else if (var == "bitrate")
+ {
+ if (sock)
+ {
+ unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec;
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+ }else
+ strcpy(buf,"0");
+ }else if (var == "uptime")
+ {
+ String uptime;
+ if (lastConnect)
+ uptime.setFromStopwatch(sys->getTime()-lastConnect);
+ else
+ uptime.set("-");
+ strcpy(buf,uptime.cstr());
+ }else if (var.startsWith("gnet."))
+ {
+
+ float ctime = (float)(sys->getTime()-lastConnect);
+ if (var == "gnet.packetsIn")
+ sprintf(buf,"%d",gnuStream.packetsIn);
+ else if (var == "gnet.packetsInPerSec")
+ sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0);
+ else if (var == "gnet.packetsOut")
+ sprintf(buf,"%d",gnuStream.packetsOut);
+ else if (var == "gnet.packetsOutPerSec")
+ sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0);
+ else if (var == "gnet.normQueue")
+ sprintf(buf,"%d",outPacketsNorm.numPending());
+ else if (var == "gnet.priQueue")
+ sprintf(buf,"%d",outPacketsPri.numPending());
+ else if (var == "gnet.flowControl")
+ sprintf(buf,"%d",flowControl?1:0);
+ else if (var == "gnet.routeTime")
+ {
+ int nr = seenIDs.numUsed();
+ unsigned int tim = sys->getTime()-seenIDs.getOldest();
+
+ String tstr;
+ tstr.setFromStopwatch(tim);
+
+ if (nr)
+ strcpy(buf,tstr.cstr());
+ else
+ strcpy(buf,"-");
+ }
+ else
+ return false;
+
+ }else
+ return false;
+
+ s.writeString(buf);
+
+ return true;
+}
--- /dev/null
+// ------------------------------------------------
+// File : servent.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#ifndef _SERVENT_H
+#define _SERVENT_H
+
+// ----------------------------------
+#include "socket.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "channel.h"
+#include "http.h"
+#include "rtsp.h"
+#include "pcp.h"
+
+class HTML;
+
+class AtomStream;
+
+// ----------------------------------
+// Servent handles the actual connection between clients
+class Servent
+{
+public:
+
+ enum
+ {
+ MAX_HASH = 500, // max. amount of packet hashes Servents can store
+ MAX_OUTPACKETS = 32 // max. output packets per queue (normal/priority)
+ };
+
+ enum TYPE
+ {
+ T_NONE, // Not allocated
+ T_INCOMING, // Unknown incoming
+ T_SERVER, // The main server
+ T_RELAY, // Outgoing relay
+ T_DIRECT, // Outgoing direct connection
+ T_COUT, // PCP out connection
+ T_CIN, // PCP in connection
+ T_PGNU // old protocol connection
+ };
+
+ enum STATUS
+ {
+ S_NONE,
+ S_CONNECTING,
+ S_PROTOCOL,
+ S_HANDSHAKE,
+ S_CONNECTED,
+ S_CLOSING,
+ S_LISTENING,
+ S_TIMEOUT,
+ S_REFUSED,
+ S_VERIFIED,
+ S_ERROR,
+ S_WAIT,
+ S_FREE
+ };
+
+ enum PROTOCOL
+ {
+ P_UNKNOWN,
+ P_GNUTELLA06,
+ P_PCP
+ };
+
+
+ enum SORT
+ {
+ SORT_NAME = 0,
+ SORT_BITRATE,
+ SORT_LISTENERS,
+ SORT_HOSTS,
+ SORT_TYPE,
+ SORT_GENRE
+ };
+
+ enum ALLOW
+ {
+ ALLOW_HTML = 0x01,
+ ALLOW_BROADCAST = 0x02,
+ ALLOW_NETWORK = 0x04,
+ ALLOW_DIRECT = 0x08,
+ ALLOW_ALL = 0xff
+ };
+
+ Servent(int);
+ ~Servent();
+
+ void reset();
+ bool initServer(Host &);
+ void initIncoming(ClientSocket *,unsigned int);
+ void initOutgoing(TYPE);
+ void initGIV(Host &, GnuID &);
+ void initPCP(Host &);
+
+ void checkFree();
+
+
+
+
+ // funcs for handling status/type
+ void setStatus(STATUS);
+ static char * getTypeStr(Servent::TYPE t) {return typeMsgs[t];}
+ char * getTypeStr() {return getTypeStr(type);}
+ char * getStatusStr() {return statusMsgs[status];}
+ int getOutput();
+ void addBytes(unsigned int);
+ bool isOlderThan(Servent *s)
+ {
+ if (s)
+ {
+ unsigned int t = sys->getTime();
+ return ((t-lastConnect) > (t-s->lastConnect));
+ }else
+ return true;
+ }
+
+
+
+ // static funcs that do the actual work in the servent thread
+ static THREAD_PROC serverProc(ThreadInfo *);
+ static THREAD_PROC outgoingProc(ThreadInfo *);
+ static THREAD_PROC incomingProc(ThreadInfo *);
+ static THREAD_PROC givProc(ThreadInfo *);
+ static THREAD_PROC pcpProc(ThreadInfo *);
+ static THREAD_PROC fetchProc(ThreadInfo *);
+
+ static bool pingHost(Host &,GnuID &);
+
+ bool getLocalURL(char *);
+ bool getLocalTypeURL(char *, ChanInfo::TYPE);
+
+ // various types of handshaking are needed
+ void handshakePLS(ChanHitList **, int, bool);
+ void handshakePLS(ChanInfo &, bool);
+
+ void handshakeHTML(char *);
+ void handshakeXML();
+ void handshakeCMD(char *);
+ bool handshakeAuth(HTTP &,const char *,bool);
+ void handshakeIn();
+ void handshakeOut();
+
+
+ void processOutPCP();
+ void processOutChannel();
+
+ bool handshakeStream(ChanInfo &);
+ void handshakeGiv(GnuID &);
+
+ void handshakeICY(Channel::SRC_TYPE,bool);
+ void handshakeIncoming();
+ void handshakePOST();
+ void handshakeRTSP(RTSP &);
+ void handshakeHTTP(HTTP &,bool);
+
+ void handshakeRemoteFile(const char *);
+ void handshakeLocalFile(const char *);
+
+ static void handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool);
+ static void handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &);
+
+ void processIncomingPCP(bool);
+
+ bool waitForChannelHeader(ChanInfo &);
+ ChanInfo findChannel(char *str,ChanInfo &);
+
+ bool writeVariable(Stream &, const String &);
+
+
+ // the "mainloop" of servents
+ void processGnutella();
+ void processRoot();
+ void processServent();
+ void processStream(bool,ChanInfo &);
+ void processPCP(bool,bool);
+
+ bool procAtoms(AtomStream &);
+ void procRootAtoms(AtomStream &,int);
+ void procHeloAtoms(AtomStream &,int,bool);
+ void procGetAtoms(AtomStream &,int);
+
+ void triggerChannel(char *,ChanInfo::PROTOCOL,bool);
+ void sendPeercastChannel();
+ void sendRawChannel(bool,bool);
+// void sendRawMultiChannel(bool,bool);
+ void sendRawMetaChannel(int);
+ void sendPCPChannel();
+ void checkPCPComms(Channel *, AtomStream &);
+
+ static void readICYHeader(HTTP &, ChanInfo &, char *);
+ bool canStream(Channel *);
+
+ bool isConnected() {return status == S_CONNECTED;}
+ bool isListening() {return status == S_LISTENING;}
+
+ bool isAllowed(int);
+ bool isFiltered(int);
+
+ // connection handling funcs
+ void createSocket();
+ void kill();
+ void abort();
+ bool isPrivate();
+ bool isLocal();
+
+
+ Host getHost();
+
+ bool outputPacket(GnuPacket &,bool);
+ bool hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);}
+ bool acceptGIV(ClientSocket *);
+ bool sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE);
+
+
+ TYPE type;
+ STATUS status;
+
+ static char *statusMsgs[],*typeMsgs[];
+ GnuStream gnuStream;
+ GnuPacket pack;
+ unsigned int lastConnect,lastPing,lastPacket;
+ String agent;
+
+ GnuIDList seenIDs;
+ GnuID networkID;
+ int serventIndex;
+
+ GnuID remoteID;
+
+ GnuID chanID;
+
+ GnuID givID;
+
+ ThreadInfo thread;
+
+
+ char loginPassword[64];
+ char loginMount[64];
+
+ bool priorityConnect;
+ bool addMetadata;
+ int nsSwitchNum;
+
+ unsigned int allow;
+
+ ClientSocket *sock,*pushSock;
+
+ WLock lock;
+
+ bool sendHeader;
+ unsigned int syncPos,streamPos;
+ int servPort;
+
+ ChanInfo::PROTOCOL outputProtocol;
+
+ GnuPacketBuffer outPacketsNorm,outPacketsPri;
+
+ unsigned int bytesPerSecond;
+ bool flowControl;
+
+ Servent *next;
+
+ PCPStream *pcpStream;
+ Cookie cookie;
+
+ int servent_id;
+ unsigned int lastSkipTime;
+ unsigned int lastSkipCount;
+ unsigned int waitPort;
+
+ int channel_id;
+};
+
+extern char *nextCGIarg(char *cp, char *cmd, char *arg);
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : servhs.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Servent handshaking, TODO: should be in its own class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "html.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+static void termArgs(char *str)
+{
+ if (str)
+ {
+ int slen = strlen(str);
+ for(int i=0; i<slen; i++)
+ if (str[i]=='&') str[i] = 0;
+ }
+}
+// -----------------------------------
+char *nextCGIarg(char *cp, char *cmd, char *arg)
+{
+ if (!*cp)
+ return NULL;
+
+ int cnt=0;
+
+ // fetch command
+ while (*cp)
+ {
+ char c = *cp++;
+ if (c == '=')
+ break;
+ else
+ *cmd++ = c;
+
+ cnt++;
+ if (cnt >= (MAX_CGI_LEN-1))
+ break;
+ }
+ *cmd = 0;
+
+ cnt=0;
+ // fetch arg
+ while (*cp)
+ {
+ char c = *cp++;
+ if (c == '&')
+ break;
+ else
+ *arg++ = c;
+
+ cnt++;
+ if (cnt >= (MAX_CGI_LEN-1))
+ break;
+ }
+ *arg = 0;
+
+ return cp;
+}
+// -----------------------------------
+bool getCGIargBOOL(char *a)
+{
+ return (strcmp(a,"1")==0);
+}
+// -----------------------------------
+int getCGIargINT(char *a)
+{
+ return atoi(a);
+}
+
+// -----------------------------------
+void Servent::handshakeHTTP(HTTP &http, bool isHTTP)
+{
+ char *in = http.cmdLine;
+
+ if (http.isRequest("GET /"))
+ {
+ char *fn = in+4;
+
+ char *pt = strstr(fn,HTTP_PROTO1);
+ if (pt)
+ pt[-1] = 0;
+
+ if (strncmp(fn,"/admin?",7)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Admin client");
+ handshakeCMD(fn+7);
+
+ }else if (strncmp(fn,"/http/",6)==0)
+ {
+ String dirName = fn+6;
+
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (!handshakeAuth(http,fn,false))
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+ handshakeRemoteFile(dirName);
+
+
+ }else if (strncmp(fn,"/html/",6)==0)
+ {
+ String dirName = fn+1;
+
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (handshakeAuth(http,fn,true))
+ handshakeLocalFile(dirName);
+
+
+ }else if (strncmp(fn,"/admin/?",8)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("Admin client");
+ handshakeCMD(fn+8);
+
+ }else if (strncmp(fn,"/admin.cgi",10)==0)
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ char *pwdArg = getCGIarg(fn,"pass=");
+ char *songArg = getCGIarg(fn,"song=");
+ char *mountArg = getCGIarg(fn,"mount=");
+ char *urlArg = getCGIarg(fn,"url=");
+
+ if (pwdArg && songArg)
+ {
+ int i;
+ int slen = strlen(fn);
+ for(i=0; i<slen; i++)
+ if (fn[i]=='&') fn[i] = 0;
+
+ Channel *c=chanMgr->channel;
+ while (c)
+ {
+ if ((c->status == Channel::S_BROADCASTING) &&
+ (c->info.contentType == ChanInfo::T_MP3) )
+ {
+ // if we have a mount point then check for it, otherwise update all channels.
+ bool match=true;
+
+ if (mountArg)
+ match = strcmp(c->mount,mountArg)==0;
+
+ if (match)
+ {
+ ChanInfo newInfo = c->info;
+ newInfo.track.title.set(songArg,String::T_ESC);
+ newInfo.track.title.convertTo(String::T_UNICODE);
+
+ if (urlArg)
+ if (urlArg[0])
+ newInfo.track.contact.set(urlArg,String::T_ESC);
+ LOG_CHANNEL("Channel Shoutcast update: %s",songArg);
+ c->updateInfo(newInfo);
+ }
+ }
+ c=c->next;
+ }
+ }
+
+ }else if (strncmp(fn,"/pls/",5)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ ChanInfo info;
+ if (servMgr->getChannel(fn+5,info,isPrivate()))
+ handshakePLS(info,false);
+ else
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ }else if (strncmp(fn,"/stream/",8)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+
+ }else if (strncmp(fn,"/channel/",9)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+9,ChanInfo::SP_PCP,false);
+
+ }else
+ {
+ while (http.nextHeader());
+ http.writeLine(HTTP_SC_FOUND);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+ }
+ }
+ else if (http.isRequest("POST /"))
+ {
+ char *fn = in+5;
+
+ char *pt = strstr(fn,HTTP_PROTO1);
+ if (pt)
+ pt[-1] = 0;
+
+ if (strncmp(fn,"/pls/",5)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ ChanInfo info;
+ if (servMgr->getChannel(fn+5,info,isPrivate()))
+ handshakePLS(info,false);
+ else
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ }else if (strncmp(fn,"/stream/",8)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+ }else if (strncmp(fn,"/admin",7)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Admin client");
+ while(http.nextHeader()){
+ LOG_DEBUG("%s",http.cmdLine);
+ }
+ char buf[8192];
+ if (sock->readLine(buf, sizeof(buf)) != 0){
+ handshakeCMD(buf);
+ }
+
+ }else
+ {
+ while (http.nextHeader());
+ http.writeLine(HTTP_SC_FOUND);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+ }
+ }else if (http.isRequest("GIV"))
+ {
+ HTTP http(*sock);
+
+ while (http.nextHeader()) ;
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ GnuID id;
+ id.clear();
+
+ char *idstr = strstr(in,"/");
+ if (idstr)
+ id.fromStr(idstr+1);
+
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ if (id.isSet())
+ {
+ // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting.
+ Channel *ch = chanMgr->findChannelByID(id);
+
+ if (!ch)
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ if (!ch->acceptGIV(sock))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr);
+
+ sock=NULL; // release this servent but dont close socket.
+ }else
+ {
+
+ if (!servMgr->acceptGIV(sock))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("Accepted GIV PCP from: %s",ipstr);
+ sock=NULL; // release this servent but dont close socket.
+ }
+
+ }else if (http.isRequest(PCX_PCP_CONNECT))
+ {
+
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ processIncomingPCP(true);
+
+ }else if (http.isRequest("PEERCAST CONNECT"))
+ {
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("PEERCAST client");
+ processServent();
+
+ }else if (http.isRequest("SOURCE"))
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ char *mount = NULL;
+
+ char *ps;
+ if (ps=strstr(in,"ICE/1.0"))
+ {
+ mount = in+7;
+ *ps = 0;
+ LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown");
+ }else{
+ mount = in+strlen(in);
+ while (*--mount)
+ if (*mount == '/')
+ {
+ mount[-1] = 0; // password preceeds
+ break;
+ }
+ strcpy(loginPassword,in+7);
+
+ LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown");
+ }
+
+ if (mount)
+ strcpy(loginMount,mount);
+
+ handshakeICY(Channel::SRC_ICECAST,isHTTP);
+ sock = NULL; // socket is taken over by channel, so don`t close it
+
+ }else if (http.isRequest(servMgr->password))
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ strcpy(loginPassword,servMgr->password); // pwd already checked
+
+ sock->writeLine("OK2");
+ sock->writeLine("icy-caps:11");
+ sock->writeLine("");
+ LOG_DEBUG("ShoutCast client");
+
+ handshakeICY(Channel::SRC_SHOUTCAST,isHTTP);
+ sock = NULL; // socket is taken over by channel, so don`t close it
+
+ }else
+ {
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+ }
+
+}
+// -----------------------------------
+bool Servent::canStream(Channel *ch)
+{
+ if (ch==NULL)
+ return false;
+
+ if (servMgr->isDisabled)
+ return false;
+
+ if (!isPrivate())
+ {
+ Channel *c = chanMgr->channel;
+ int noRelay = 0;
+ unsigned int needRate = 0;
+ unsigned int allRate = 0;
+ while(c){
+ if (c->isPlaying()){
+ allRate += c->info.bitrate * c->localRelays();
+ if ((c != ch) && (c->localRelays() == 0)){
+ if(!isIndexTxt(c)) // for PCRaw (relay)
+ noRelay++;
+ needRate+=c->info.bitrate;
+ }
+ }
+ c = c->next;
+ }
+ int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+ if (ch->localRelays()){
+ if (noRelay > diff){
+ noRelay = diff;
+ }
+ } else {
+ noRelay = 0;
+ needRate = 0;
+ }
+
+ // for PCRaw (relay) start.
+ bool force_off = true;
+
+ if(isIndexTxt(ch))
+ force_off = false;
+ // for PCRaw (relay) end.
+
+ LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d",
+ servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+ if ( !ch->isPlaying()
+ || ch->isFull()
+// || servMgr->bitrateFull(needRate+ch->getBitrate())
+ || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut)
+ || ((type == T_RELAY) && servMgr->relaysFull() && force_off) // for PCRaw (relay) (force_off)
+ || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off) // for PCRaw (relay) (force_off)
+ || ((type == T_DIRECT) && servMgr->directFull())
+ ){
+ LOG_DEBUG("Relay check: NG");
+ return false;
+ }
+ }
+
+ LOG_DEBUG("Relay check: OK");
+ return true;
+}
+// -----------------------------------
+void Servent::handshakeIncoming()
+{
+
+ setStatus(S_HANDSHAKE);
+
+ char buf[2048];
+ sock->readLine(buf,sizeof(buf));
+
+ char sb[64];
+ sock->host.toStr(sb);
+
+
+ if (stristr(buf,RTSP_PROTO1))
+ {
+ LOG_DEBUG("RTSP from %s '%s'",sb,buf);
+ RTSP rtsp(*sock);
+ rtsp.initRequest(buf);
+ handshakeRTSP(rtsp);
+ }else if (stristr(buf,HTTP_PROTO1))
+ {
+ LOG_DEBUG("HTTP from %s '%s'",sb,buf);
+ HTTP http(*sock);
+ http.initRequest(buf);
+ handshakeHTTP(http,true);
+ }else
+ {
+ LOG_DEBUG("Connect from %s '%s'",sb,buf);
+ HTTP http(*sock);
+ http.initRequest(buf);
+ handshakeHTTP(http,false);
+ }
+
+}
+// -----------------------------------
+void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay)
+{
+
+ ChanInfo info;
+// WLockBlock lb(&(chanMgr->channellock));
+
+// LOG_DEBUG("----------triggerChannel LOCK ON");
+// lb.on();
+ servMgr->getChannel(str,info,relay);
+// LOG_DEBUG("==========triggerChannel LOCK OFF");
+// lb.off();
+
+ if (proto == ChanInfo::SP_PCP)
+ type = T_RELAY;
+ else
+ type = T_DIRECT;
+
+ outputProtocol = proto;
+
+ processStream(false,info);
+
+}
+// -----------------------------------
+void writePLSHeader(Stream &s, PlayList::TYPE type)
+{
+ s.writeLine(HTTP_SC_OK);
+ s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+ const char *content;
+ switch(type)
+ {
+ case PlayList::T_PLS:
+ content = MIME_XM3U;
+ break;
+ case PlayList::T_ASX:
+ content = MIME_ASX;
+ break;
+ case PlayList::T_RAM:
+ content = MIME_RAM;
+ break;
+ default:
+ content = MIME_TEXT;
+ break;
+ }
+ s.writeLineF("%s %s",HTTP_HS_CONTENT,content);
+ s.writeLine("Content-Disposition: inline");
+ s.writeLine("Cache-Control: private" );
+ s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+
+ s.writeLine("");
+}
+
+// -----------------------------------
+void Servent::handshakePLS(ChanInfo &info, bool doneHandshake)
+{
+ char url[256];
+
+ char in[128];
+
+ if (!doneHandshake)
+ while (sock->readLine(in,128));
+
+
+ if (getLocalTypeURL(url,info.contentType))
+ {
+
+ PlayList::TYPE type;
+
+ if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+ type = PlayList::T_ASX;
+ else if (info.contentType == ChanInfo::T_OGM)
+ type = PlayList::T_RAM;
+ else
+ type = PlayList::T_PLS;
+
+ writePLSHeader(*sock,type);
+
+ PlayList *pls;
+
+ pls = new PlayList(type,1);
+
+ pls->addChannel(url,info);
+
+ pls->write(*sock);
+
+ delete pls;
+ }
+}
+// -----------------------------------
+void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake)
+{
+ char url[256];
+ char in[128];
+
+ if (!doneHandshake)
+ while (sock->readLine(in,128));
+
+ if (getLocalURL(url))
+ {
+ writePLSHeader(*sock,PlayList::T_SCPLS);
+
+ PlayList *pls;
+
+ pls = new PlayList(PlayList::T_SCPLS,num);
+
+ for(int i=0; i<num; i++)
+ pls->addChannel(url,cl[i]->info);
+
+ pls->write(*sock);
+
+ delete pls;
+ }
+}
+// -----------------------------------
+bool Servent::getLocalURL(char *str)
+{
+ if (!sock)
+ throw StreamException("Not connected");
+
+
+ char ipStr[64];
+
+ Host h;
+
+ if (sock->host.localIP())
+ h = sock->getLocalHost();
+ else
+ h = servMgr->serverHost;
+
+ h.port = servMgr->serverHost.port;
+
+ h.toStr(ipStr);
+
+ sprintf(str,"http://%s",ipStr);
+ return true;
+}
+
+// -----------------------------------
+bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type)
+{
+ if (!sock)
+ throw StreamException("Not connected");
+
+
+ char ipStr[64];
+
+ Host h;
+
+ if (sock->host.localIP())
+ h = sock->getLocalHost();
+ else
+ h = servMgr->serverHost;
+
+ h.port = servMgr->serverHost.port;
+
+ h.toStr(ipStr);
+ switch(type) {
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ sprintf(str,"mms://%s",ipStr);
+ break;
+ default:
+ sprintf(str,"http://%s",ipStr);
+ }
+ return true;
+}
+// -----------------------------------
+// Warning: testing RTSP/RTP stuff below.
+// .. moved over to seperate app now.
+// -----------------------------------
+void Servent::handshakePOST()
+{
+ char tmp[1024];
+ while (sock->readLine(tmp,sizeof(tmp)))
+ LOG_DEBUG("POST: %s",tmp);
+
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+
+
+// -----------------------------------
+void Servent::handshakeRTSP(RTSP &rtsp)
+{
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+// -----------------------------------
+bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
+{
+ char user[1024],pass[1024];
+ user[0] = pass[0] = 0;
+
+ char *pwd = getCGIarg(args, "pass=");
+
+ if ((pwd) && strlen(servMgr->password))
+ {
+ String tmp = pwd;
+ char *as = strstr(tmp.cstr(),"&");
+ if (as) *as = 0;
+ if (strcmp(tmp,servMgr->password)==0)
+ {
+ while (http.nextHeader());
+ return true;
+ }
+ }
+
+ Cookie gotCookie;
+ cookie.clear();
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ switch (servMgr->authType)
+ {
+ case ServMgr::AUTH_HTTPBASIC:
+ if (http.isHeader("Authorization"))
+ http.getAuthUserPass(user,pass);
+ break;
+ case ServMgr::AUTH_COOKIE:
+ if (http.isHeader("Cookie"))
+ {
+ LOG_DEBUG("Got cookie: %s",arg);
+ char *idp=arg;
+ while ((idp = strstr(idp,"id=")))
+ {
+ idp+=3;
+ gotCookie.set(idp,sock->host.ip);
+ if (servMgr->cookieList.contains(gotCookie))
+ {
+ LOG_DEBUG("Cookie found");
+ cookie = gotCookie;
+ break;
+ }
+
+ }
+ }
+ break;
+ }
+ }
+
+ if (sock->host.isLocalhost())
+ return true;
+
+
+ switch (servMgr->authType)
+ {
+ case ServMgr::AUTH_HTTPBASIC:
+
+ if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password))
+ return true;
+ break;
+ case ServMgr::AUTH_COOKIE:
+ if (servMgr->cookieList.contains(cookie))
+ return true;
+ break;
+ }
+
+
+
+ if (servMgr->authType == ServMgr::AUTH_HTTPBASIC)
+ {
+ http.writeLine(HTTP_SC_UNAUTHORIZED);
+ http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\"");
+ }else if (servMgr->authType == ServMgr::AUTH_COOKIE)
+ {
+ String file = servMgr->htmlPath;
+ file.append("/login.html");
+ if (local)
+ handshakeLocalFile(file);
+ else
+ handshakeRemoteFile(file);
+ }
+
+
+ return false;
+}
+
+// -----------------------------------
+void Servent::handshakeCMD(char *cmd)
+{
+ char result[MAX_CGI_LEN];
+ char arg[MAX_CGI_LEN];
+ char curr[MAX_CGI_LEN];
+
+ char jumpStr[128];
+ char *jumpArg=NULL;
+ bool retHTML=true;
+ strcpy(result,"OK");
+
+ HTTP http(*sock);
+ HTML html("",*sock);
+
+
+ if (!handshakeAuth(http,cmd,true))
+ return;
+
+ try
+ {
+ if (cmpCGIarg(cmd,"cmd=","redirect"))
+ {
+ char *j = getCGIarg(cmd,"url=");
+ if (j)
+ {
+ termArgs(cmd);
+ String url;
+ url.set(j,String::T_ESC);
+ url.convertTo(String::T_ASCII);
+
+ if (!url.contains("http://"))
+ url.prepend("http://");
+
+ html.setRefreshURL(url.cstr());
+ html.startHTML();
+ html.addHead();
+ html.startBody();
+ html.startTagEnd("h3","Please wait...");
+ html.end();
+ html.end();
+
+ }
+ }else{
+
+ if (cmpCGIarg(cmd,"cmd=","viewxml"))
+ {
+
+ handshakeXML();
+ retHTML = false;
+ }else if (cmpCGIarg(cmd,"cmd=","clearlog"))
+ {
+ sys->logBuf->clear();
+ sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","save"))
+ {
+
+ peercastInst->saveSettings();
+
+ sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }else if (cmpCGIarg(cmd,"cmd=","reg"))
+ {
+ char idstr[128];
+ chanMgr->broadcastID.toStr(idstr);
+ sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr);
+ jumpArg = jumpStr;
+ }else if (cmpCGIarg(cmd,"cmd=","edit_bcid"))
+ {
+ char *cp = cmd;
+ GnuID id;
+ BCID *bcid;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ else if (strcmp(curr,"del")==0)
+ servMgr->removeValidBCID(id);
+ else if (strcmp(curr,"valid")==0)
+ {
+ bcid = servMgr->findValidBCID(id);
+ if (bcid)
+ bcid->valid = getCGIargBOOL(arg);
+ }
+ }
+ peercastInst->saveSettings();
+ sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","add_bcid"))
+ {
+ BCID *bcid = new BCID();
+
+ char *cp = cmd;
+ bool result=false;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ bcid->id.fromStr(arg);
+ else if (strcmp(curr,"name")==0)
+ bcid->name.set(arg);
+ else if (strcmp(curr,"email")==0)
+ bcid->email.set(arg);
+ else if (strcmp(curr,"url")==0)
+ bcid->url.set(arg);
+ else if (strcmp(curr,"valid")==0)
+ bcid->valid = getCGIargBOOL(arg);
+ else if (strcmp(curr,"result")==0)
+ result = true;
+
+ }
+
+ LOG_DEBUG("Adding BCID : %s",bcid->name.cstr());
+ servMgr->addValidBCID(bcid);
+ peercastInst->saveSettings();
+ if (result)
+ {
+ http.writeLine(HTTP_SC_OK);
+ http.writeLine("");
+ http.writeString("OK");
+ }else
+ {
+ sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","apply"))
+ {
+ //servMgr->numFilters = 0;
+ ServFilter *currFilter=servMgr->filters;
+ bool beginfilt = false;
+
+ bool brRoot=false;
+ bool getUpd=false;
+ int showLog=0;
+ int allowServer1=0;
+ int allowServer2=0;
+ int newPort=servMgr->serverHost.port;
+ int enableGetName = 0;
+ int allowConnectPCST = 0;
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ // server
+ if (strcmp(curr,"serveractive")==0)
+ servMgr->autoServe = getCGIargBOOL(arg);
+ else if (strcmp(curr,"port")==0)
+ newPort = getCGIargINT(arg);
+ else if (strcmp(curr,"icymeta")==0)
+ {
+ int iv = getCGIargINT(arg);
+ if (iv < 0) iv = 0;
+ else if (iv > 16384) iv = 16384;
+
+ chanMgr->icyMetaInterval = iv;
+
+ }else if (strcmp(curr,"passnew")==0)
+ strcpy(servMgr->password,arg);
+ else if (strcmp(curr,"root")==0)
+ servMgr->isRoot = getCGIargBOOL(arg);
+ else if (strcmp(curr,"brroot")==0)
+ brRoot = getCGIargBOOL(arg);
+ else if (strcmp(curr,"getupd")==0)
+ getUpd = getCGIargBOOL(arg);
+ else if (strcmp(curr,"huint")==0)
+ chanMgr->setUpdateInterval(getCGIargINT(arg));
+ else if (strcmp(curr,"forceip")==0)
+ servMgr->forceIP = arg;
+ else if (strcmp(curr,"htmlPath")==0)
+ {
+ strcpy(servMgr->htmlPath,"html/");
+ strcat(servMgr->htmlPath,arg);
+ }else if (strcmp(curr,"djmsg")==0)
+ {
+ String msg;
+ msg.set(arg,String::T_ESC);
+ msg.convertTo(String::T_UNICODE);
+ chanMgr->setBroadcastMsg(msg);
+ }
+ else if (strcmp(curr,"pcmsg")==0)
+ {
+ servMgr->rootMsg.set(arg,String::T_ESC);
+ servMgr->rootMsg.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"minpgnu")==0)
+ servMgr->minGnuIncoming = atoi(arg);
+ else if (strcmp(curr,"maxpgnu")==0)
+ servMgr->maxGnuIncoming = atoi(arg);
+
+
+
+ // connections
+ else if (strcmp(curr,"maxcin")==0)
+ servMgr->maxControl = getCGIargINT(arg);
+
+ else if (strcmp(curr,"maxup")==0)
+ servMgr->maxBitrateOut = getCGIargINT(arg);
+ else if (strcmp(curr,"maxrelays")==0)
+ servMgr->setMaxRelays(getCGIargINT(arg));
+ else if (strcmp(curr,"maxdirect")==0)
+ servMgr->maxDirect = getCGIargINT(arg);
+ else if (strcmp(curr,"maxrelaypc")==0)
+ chanMgr->maxRelaysPerChannel = getCGIargINT(arg);
+ else if (strncmp(curr,"filt_",5)==0)
+ {
+ if (!beginfilt) {
+ servMgr->numFilters = 0;
+ beginfilt = true;
+ }
+ char *fs = curr+5;
+ {
+ if (strncmp(fs,"ip",2)==0) // ip must be first
+ {
+ currFilter = &servMgr->filters[servMgr->numFilters];
+ currFilter->init();
+ currFilter->host.fromStrIP(arg,DEFAULT_PORT);
+ if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1)))
+ {
+ servMgr->numFilters++;
+ servMgr->filters[servMgr->numFilters].init(); // clear new entry
+ }
+
+ }else if (strncmp(fs,"bn",2)==0)
+ currFilter->flags |= ServFilter::F_BAN;
+ else if (strncmp(fs,"pr",2)==0)
+ currFilter->flags |= ServFilter::F_PRIVATE;
+ else if (strncmp(fs,"nw",2)==0)
+ currFilter->flags |= ServFilter::F_NETWORK;
+ else if (strncmp(fs,"di",2)==0)
+ currFilter->flags |= ServFilter::F_DIRECT;
+ }
+ }
+
+ // client
+ else if (strcmp(curr,"clientactive")==0)
+ servMgr->autoConnect = getCGIargBOOL(arg);
+ else if (strcmp(curr,"yp")==0)
+ {
+ if (!PCP_FORCE_YP)
+ {
+ String str(arg,String::T_ESC);
+ str.convertTo(String::T_ASCII);
+ servMgr->rootHost = str;
+ }
+ }
+ else if (strcmp(curr,"yp2")==0)
+ {
+ if (!PCP_FORCE_YP)
+ {
+ String str(arg,String::T_ESC);
+ str.convertTo(String::T_ASCII);
+ servMgr->rootHost2 = str;
+ }
+ }
+ else if (strcmp(curr,"deadhitage")==0)
+ chanMgr->deadHitAge = getCGIargINT(arg);
+ else if (strcmp(curr,"refresh")==0)
+ servMgr->refreshHTML = getCGIargINT(arg);
+ else if (strcmp(curr,"auth")==0)
+ {
+ if (strcmp(arg,"cookie")==0)
+ servMgr->authType = ServMgr::AUTH_COOKIE;
+ else if (strcmp(arg,"http")==0)
+ servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+
+ }else if (strcmp(curr,"expire")==0)
+ {
+ if (strcmp(arg,"session")==0)
+ servMgr->cookieList.neverExpire = false;
+ else if (strcmp(arg,"never")==0)
+ servMgr->cookieList.neverExpire = true;
+ }
+
+ else if (strcmp(curr,"logDebug")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_DEBUG):0;
+ else if (strcmp(curr,"logErrors")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_ERROR):0;
+ else if (strcmp(curr,"logNetwork")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_NETWORK):0;
+ else if (strcmp(curr,"logChannel")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_CHANNEL):0;
+
+ else if (strcmp(curr,"allowHTML1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_HTML):0;
+ else if (strcmp(curr,"allowNetwork1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_NETWORK):0;
+ else if (strcmp(curr,"allowBroadcast1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_BROADCAST):0;
+ else if (strcmp(curr,"allowDirect1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_DIRECT):0;
+
+ else if (strcmp(curr,"allowHTML2")==0)
+ allowServer2 |= atoi(arg)?(ALLOW_HTML):0;
+ else if (strcmp(curr,"allowBroadcast2")==0)
+ allowServer2 |= atoi(arg)?(ALLOW_BROADCAST):0;
+
+ // JP-EX
+ else if (strcmp(curr, "autoRelayKeep") ==0)
+ servMgr->autoRelayKeep = getCGIargINT(arg);
+ else if (strcmp(curr, "autoMaxRelaySetting") ==0)
+ servMgr->autoMaxRelaySetting = getCGIargINT(arg);
+ else if (strcmp(curr, "autoBumpSkipCount") ==0)
+ servMgr->autoBumpSkipCount = getCGIargINT(arg);
+ else if (strcmp(curr, "kickPushStartRelays") ==0)
+ servMgr->kickPushStartRelays = getCGIargINT(arg);
+ else if (strcmp(curr, "kickPushInterval") ==0)
+ servMgr->kickPushInterval = getCGIargINT(arg);
+ else if (strcmp(curr, "allowConnectPCST") ==0)
+ allowConnectPCST = atoi(arg) ? 1 : 0;
+ else if (strcmp(curr, "enableGetName") ==0)
+ enableGetName = atoi(arg)? 1 : 0;
+ else if (strcmp(curr, "autoPort0Kick") ==0)
+ servMgr->autoPort0Kick = getCGIargBOOL(arg);
+ else if (strcmp(curr, "allowOnlyVP") ==0)
+ servMgr->allowOnlyVP = getCGIargBOOL(arg);
+ else if (strcmp(curr, "kickKeepTime") ==0)
+ servMgr->kickKeepTime = getCGIargINT(arg);
+
+ else if (strcmp(curr, "maxRelaysIndexTxt") ==0) // for PCRaw (relay)
+ servMgr->maxRelaysIndexTxt = getCGIargINT(arg);
+ }
+
+
+
+ servMgr->showLog = showLog;
+ servMgr->allowServer1 = allowServer1;
+ servMgr->allowServer2 = allowServer2;
+ servMgr->enableGetName = enableGetName;
+ servMgr->allowConnectPCST = allowConnectPCST;
+ if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML))
+ servMgr->allowServer1 |= ALLOW_HTML;
+
+ if (servMgr->serverHost.port != newPort)
+ {
+ Host lh(ClientSocket::getIP(NULL),newPort);
+ char ipstr[64];
+ lh.toStr(ipstr);
+ sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath);
+
+ servMgr->serverHost.port = newPort;
+ servMgr->restartServer=true;
+ //html.setRefresh(3);
+ //html.setRefreshURL(jumpStr);
+ //html.startHTML();
+ //html.addHead();
+ // html.startBody();
+ // html.startTagEnd("h1","Please wait...");
+ // html.end();
+ //html.end();
+
+
+
+ //char ipstr[64];
+ //servMgr->serverHost.toStr(ipstr);
+ //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else
+ {
+ sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+
+ peercastInst->saveSettings();
+
+ peercastApp->updateSettings();
+
+ if ((servMgr->isRoot) && (brRoot))
+ servMgr->broadcastRootSettings(getUpd);
+
+
+
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","fetch"))
+ {
+
+ ChanInfo info;
+ String curl;
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"url")==0)
+ {
+ curl.set(arg,String::T_ESC);
+ curl.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"name")==0)
+ {
+ info.name.set(arg,String::T_ESC);
+ info.name.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"desc")==0)
+ {
+ info.desc.set(arg,String::T_ESC);
+ info.desc.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"genre")==0)
+ {
+ info.genre.set(arg,String::T_ESC);
+ info.genre.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"contact")==0)
+ {
+ info.url.set(arg,String::T_ESC);
+ info.url.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"bitrate")==0)
+ {
+ info.bitrate = atoi(arg);
+ }else if (strcmp(curr,"type")==0)
+ {
+ info.contentType = ChanInfo::getTypeFromStr(arg);
+ }
+
+ }
+
+ info.bcID = chanMgr->broadcastID;
+
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ c->startURL(curl.cstr());
+
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","stopserv"))
+ {
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"index")==0)
+ {
+ Servent *s = servMgr->findServentByIndex(atoi(arg));
+ if (s)
+ s->abort();
+ }
+ }
+ sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","hitlist"))
+ {
+
+ bool stayConnected=hasCGIarg(cmd,"relay");
+
+ int index = 0;
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ {
+ char tmp[64];
+ sprintf(tmp,"c%d=",index);
+ if (cmpCGIarg(cmd,tmp,"1"))
+ {
+ Channel *c;
+ if (!(c=chanMgr->findChannelByID(chl->info.id)))
+ {
+ c = chanMgr->createChannel(chl->info,NULL);
+ if (!c)
+ throw StreamException("out of channels");
+ c->stayConnected = stayConnected;
+ c->startGet();
+ }
+ }
+ }
+ chl = chl->next;
+ index++;
+ }
+
+ char *findArg = getCGIarg(cmd,"keywords=");
+
+ if (hasCGIarg(cmd,"relay"))
+ {
+ sys->sleep(500);
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+ }else if (cmpCGIarg(cmd,"cmd=","clear"))
+ {
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"hostcache")==0)
+ servMgr->clearHostCache(ServHost::T_SERVENT);
+ else if (strcmp(curr,"hitlists")==0)
+ chanMgr->clearHitLists();
+ else if (strcmp(curr,"packets")==0)
+ {
+ stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND);
+ servMgr->numVersions = 0;
+ }
+ }
+
+ sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","upgrade"))
+ {
+ if (servMgr->downloadURL[0])
+ {
+ sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL);
+ jumpArg = jumpStr;
+ }
+
+
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","connect"))
+ {
+
+
+ Servent *s = servMgr->servents;
+ {
+ char tmp[64];
+ sprintf(tmp,"c%d=",s->serventIndex);
+ if (cmpCGIarg(cmd,tmp,"1"))
+ {
+ if (hasCGIarg(cmd,"stop"))
+ s->thread.active = false;
+ }
+ s=s->next;
+ }
+ sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","shutdown"))
+ {
+ servMgr->shutdownTimer = 1;
+
+ }else if (cmpCGIarg(cmd,"cmd=","stop"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c){
+ c->thread.active = false;
+ c->thread.finish = true;
+ }
+
+ sys->sleep(500);
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","bump"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c)
+ c->bump = true;
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","keep"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c)
+ { //JP-Patch
+ //c->stayConnected = true;
+ if (!c->stayConnected)
+ {
+ //if (servMgr->getFirewall() == ServMgr::FW_OFF)
+ c->stayConnected = true;
+ }
+ else
+ c->stayConnected = false;
+ } //JP-Patch
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","relay"))
+ {
+ ChanInfo info;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ info.id.fromStr(arg);
+ }
+
+
+ if (!chanMgr->findChannelByID(info.id))
+ {
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+ if (!chl)
+ throw StreamException("channel not found");
+
+
+ Channel *c = chanMgr->createChannel(chl->info,NULL);
+ if (!c)
+ throw StreamException("out of channels");
+
+ c->stayConnected = true;
+ c->startGet();
+ }
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+
+ }else if (cmpCGIarg(cmd,"net=","add"))
+ {
+
+ GnuID id;
+ id.clear();
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ if (strcmp(curr,"ip")==0)
+ {
+ Host h;
+ h.fromStrIP(arg,DEFAULT_PORT);
+ if (servMgr->addOutgoing(h,id,true))
+ LOG_NETWORK("Added connection: %s",arg);
+
+ }else if (strcmp(curr,"id")==0)
+ {
+ id.fromStr(arg);
+ }
+
+ }
+
+ }else if (cmpCGIarg(cmd,"cmd=","logout"))
+ {
+ jumpArg = "/";
+ servMgr->cookieList.remove(cookie);
+
+ }else if (cmpCGIarg(cmd,"cmd=","login"))
+ {
+ GnuID id;
+ char idstr[64];
+ id.generate();
+ id.toStr(idstr);
+
+ cookie.set(idstr,sock->host.ip);
+ servMgr->cookieList.add(cookie);
+
+ http.writeLine(HTTP_SC_FOUND);
+ if (servMgr->cookieList.neverExpire)
+ http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr);
+ else
+ http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+
+ }else if (cmpCGIarg(cmd,"cmd=","setmeta"))
+ {
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"name")==0)
+ {
+/* String chname;
+ chname.set(arg,String::T_ESC);
+ chname.convertTo(String::T_ASCII);
+ for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+ {
+ Channel *c = &chanMgr->channels[i];
+ if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0))
+ {
+ ChanInfo newInfo = c->info;
+
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ String chmeta;
+ chmeta.set(arg,String::T_ESC);
+ chmeta.convertTo(String::T_ASCII);
+ if (strcmp(curr,"desc")==0)
+ newInfo.desc = chmeta.cstr();
+ else if (strcmp(curr,"url")==0)
+ newInfo.url = chmeta.cstr();
+ else if (strcmp(curr,"genre")==0)
+ newInfo.genre = chmeta.cstr();
+ else if (strcmp(curr,"comment")==0)
+ newInfo.comment = chmeta.cstr();
+ else if (strcmp(curr,"t_contact")==0)
+ newInfo.track.contact = chmeta.cstr();
+ else if (strcmp(curr,"t_title")==0)
+ newInfo.track.title = chmeta.cstr();
+ else if (strcmp(curr,"t_artist")==0)
+ newInfo.track.artist = chmeta.cstr();
+ else if (strcmp(curr,"t_album")==0)
+ newInfo.track.album = chmeta.cstr();
+ else if (strcmp(curr,"t_genre")==0)
+ newInfo.track.genre = chmeta.cstr();
+ }
+ c->updateInfo(newInfo);
+ char idstr[64];
+ newInfo.id.toStr(idstr);
+ sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+ jumpArg = jumpStr;
+ break;
+ }
+ }*/
+ String chname;
+ chname.set(arg,String::T_ESC);
+ chname.convertTo(String::T_ASCII);
+
+ Channel *c = chanMgr->findChannelByName(chname.cstr());
+ if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){
+ ChanInfo newInfo = c->info;
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ String chmeta;
+ chmeta.set(arg,String::T_ESC);
+ chmeta.convertTo(String::T_ASCII);
+ if (strcmp(curr,"desc")==0)
+ newInfo.desc = chmeta.cstr();
+ else if (strcmp(curr,"url")==0)
+ newInfo.url = chmeta.cstr();
+ else if (strcmp(curr,"genre")==0)
+ newInfo.genre = chmeta.cstr();
+ else if (strcmp(curr,"comment")==0)
+ newInfo.comment = chmeta.cstr();
+ else if (strcmp(curr,"t_contact")==0)
+ newInfo.track.contact = chmeta.cstr();
+ else if (strcmp(curr,"t_title")==0)
+ newInfo.track.title = chmeta.cstr();
+ else if (strcmp(curr,"t_artist")==0)
+ newInfo.track.artist = chmeta.cstr();
+ else if (strcmp(curr,"t_album")==0)
+ newInfo.track.album = chmeta.cstr();
+ else if (strcmp(curr,"t_genre")==0)
+ newInfo.track.genre = chmeta.cstr();
+ }
+ c->updateInfo(newInfo);
+ char idstr[64];
+ newInfo.id.toStr(idstr);
+ sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+ jumpArg = jumpStr;
+ }
+ }
+ }
+ if (!jumpArg)
+ {
+ jumpArg = "/";
+ }
+
+ }else{
+
+ sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+ }
+
+ }catch(StreamException &e)
+ {
+ html.startTagEnd("h1","ERROR - %s",e.msg);
+ LOG_ERROR("html: %s",e.msg);
+ }
+
+
+ if (retHTML)
+ {
+ if (jumpArg)
+ {
+ String jmp(jumpArg,String::T_HTML);
+ jmp.convertTo(String::T_ASCII);
+ html.locateTo(jmp.cstr());
+ }
+ }
+
+
+}
+// -----------------------------------
+static XML::Node *createChannelXML(Channel *c)
+{
+ XML::Node *n = c->info.createChannelXML();
+ n->add(c->createRelayXML(true));
+ n->add(c->info.createTrackXML());
+// n->add(c->info.createServentXML());
+ return n;
+}
+// -----------------------------------
+static XML::Node *createChannelXML(ChanHitList *chl)
+{
+ XML::Node *n = chl->info.createChannelXML();
+ n->add(chl->createXML());
+ n->add(chl->info.createTrackXML());
+// n->add(chl->info.createServentXML());
+ return n;
+}
+// -----------------------------------
+void Servent::handshakeXML()
+{
+ int i;
+
+
+
+ XML xml;
+
+ XML::Node *rn = new XML::Node("peercast");
+ xml.setRoot(rn);
+
+
+ rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime()));
+
+ rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"",
+ stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT),
+ stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)
+ ));
+
+ rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true)));
+
+ XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels());
+ rn->add(an);
+
+ Channel *c = chanMgr->channel;
+ while (c)
+ {
+ if (c->isActive())
+ an->add(createChannelXML(c));
+ c=c->next;
+ }
+
+
+ // add public channels
+ {
+ XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists());
+ rn->add(fn);
+
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ fn->add(createChannelXML(chl));
+ chl = chl->next;
+ }
+ }
+
+
+#if 0
+ if (servMgr->isRoot)
+ {
+ // add private channels
+ {
+ XML::Node *pn = new XML::Node("priv_channels");
+ rn->add(pn);
+
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.isPrivate())
+ pn->add(createChannelXML(chl));
+ chl = chl->next;
+ }
+ }
+ }
+#endif
+
+ XML::Node *hc = new XML::Node("host_cache");
+ for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+ {
+ ServHost *sh = &servMgr->hostCache[i];
+ if (sh->type != ServHost::T_NONE)
+ {
+ char ipstr[64];
+ sh->host.toStr(ipstr);
+
+ hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time));
+
+ }
+ }
+ rn->add(hc);
+
+
+ sock->writeLine(HTTP_SC_OK);
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML);
+ sock->writeLine("Connection: close");
+
+ sock->writeLine("");
+
+ xml.write(*sock);
+
+}
+// -----------------------------------
+void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd)
+{
+ char *arg = http.getArgStr();
+ if (!arg) return;
+
+ if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name"))
+ {
+ info.name.set(arg,String::T_ASCII);
+ info.name.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url"))
+ info.url.set(arg,String::T_ASCII);
+ else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate"))
+ info.bitrate = atoi(arg);
+ else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre"))
+ {
+ info.genre.set(arg,String::T_ASCII);
+ info.genre.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description"))
+ {
+ info.desc.set(arg,String::T_ASCII);
+ info.desc.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("Authorization"))
+ http.getAuthUserPass(NULL,pwd);
+ else if (http.isHeader(PCX_HS_CHANNELID))
+ info.id.fromStr(arg);
+ else if (http.isHeader("ice-password"))
+ {
+ if (pwd)
+ if (strlen(arg) < 64)
+ strcpy(pwd,arg);
+ }else if (http.isHeader("content-type"))
+ {
+ if (stristr(arg,MIME_OGG))
+ info.contentType = ChanInfo::T_OGG;
+ else if (stristr(arg,MIME_XOGG))
+ info.contentType = ChanInfo::T_OGG;
+
+ else if (stristr(arg,MIME_MP3))
+ info.contentType = ChanInfo::T_MP3;
+ else if (stristr(arg,MIME_XMP3))
+ info.contentType = ChanInfo::T_MP3;
+
+ else if (stristr(arg,MIME_WMA))
+ info.contentType = ChanInfo::T_WMA;
+ else if (stristr(arg,MIME_WMV))
+ info.contentType = ChanInfo::T_WMV;
+ else if (stristr(arg,MIME_ASX))
+ info.contentType = ChanInfo::T_ASX;
+
+ else if (stristr(arg,MIME_NSV))
+ info.contentType = ChanInfo::T_NSV;
+ else if (stristr(arg,MIME_RAW))
+ info.contentType = ChanInfo::T_RAW;
+
+ else if (stristr(arg,MIME_MMS))
+ info.srcProtocol = ChanInfo::SP_MMS;
+ else if (stristr(arg,MIME_XPCP))
+ info.srcProtocol = ChanInfo::SP_PCP;
+ else if (stristr(arg,MIME_XPEERCAST))
+ info.srcProtocol = ChanInfo::SP_PEERCAST;
+
+ else if (stristr(arg,MIME_XSCPLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_PLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_XPLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_M3U))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_MPEGURL))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_TEXT))
+ info.contentType = ChanInfo::T_PLS;
+
+
+ }
+
+}
+
+// -----------------------------------
+void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP)
+{
+ ChanInfo info;
+
+ HTTP http(*sock);
+
+ // default to mp3 for shoutcast DSP (doesn`t send content-type)
+ if (type == Channel::SRC_SHOUTCAST)
+ info.contentType = ChanInfo::T_MP3;
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG("ICY %s",http.cmdLine);
+ readICYHeader(http,info,loginPassword);
+ }
+
+
+
+ // check password before anything else, if needed
+ if (strcmp(servMgr->password,loginPassword)!=0)
+ {
+ if (!sock->host.isLocalhost() || strlen(loginPassword))
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+ }
+
+
+ // we need a valid IP address before we start
+ servMgr->checkFirewall();
+
+
+ // attach channel ID to name, channel ID is also encoded with IP address
+ // to help prevent channel hijacking.
+
+
+ info.id = chanMgr->broadcastID;
+ info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate);
+
+ LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType));
+
+
+ if (isHTTP)
+ sock->writeStringF("%s\n\n",HTTP_SC_OK);
+ else
+ sock->writeLine("OK");
+
+ Channel *c = chanMgr->findChannelByID(info.id);
+ if (c)
+ {
+ LOG_CHANNEL("ICY channel already active, closing old one");
+ c->thread.shutdown();
+ }
+
+
+ info.comment = chanMgr->broadcastMsg;
+ info.bcID = chanMgr->broadcastID;
+
+ c = chanMgr->createChannel(info,loginMount);
+ if (!c)
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ c->startICY(sock,type);
+}
+
+
+// -----------------------------------
+void Servent::handshakeLocalFile(const char *fn)
+{
+ HTTP http(*sock);
+ String fileName;
+
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ fileName = servMgr->modulePath;
+ }else
+ fileName = peercastApp->getPath();
+
+ fileName.append(fn);
+
+ LOG_DEBUG("Writing HTML file: %s",fileName.cstr());
+
+ HTML html("",*sock);
+
+ char *args = strstr(fileName.cstr(),"?");
+ if (args)
+ *args++=0;
+
+ if (fileName.contains(".htm"))
+ {
+ html.writeOK(MIME_HTML);
+ html.writeTemplate(fileName.cstr(),args);
+
+ }else if (fileName.contains(".css"))
+ {
+ html.writeOK(MIME_CSS);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".jpg"))
+ {
+ html.writeOK(MIME_JPEG);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".gif"))
+ {
+ html.writeOK(MIME_GIF);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".png"))
+ {
+ html.writeOK(MIME_PNG);
+ html.writeRawFile(fileName.cstr());
+ }
+}
+
+// -----------------------------------
+void Servent::handshakeRemoteFile(const char *dirName)
+{
+ ClientSocket *rsock = sys->createSocket();
+ if (!rsock)
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ const char *hostName = "www.peercast.org"; // hardwired for "security"
+
+ Host host;
+ host.fromStrName(hostName,80);
+
+
+ rsock->open(host);
+ rsock->connect();
+
+ HTTP rhttp(*rsock);
+
+ rhttp.writeLineF("GET /%s HTTP/1.0",dirName);
+ rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName);
+ rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+ rhttp.writeLine("");
+
+ String contentType;
+ bool isTemplate = false;
+ while (rhttp.nextHeader())
+ {
+ char *arg = rhttp.getArgStr();
+ if (arg)
+ {
+ if (rhttp.isHeader("content-type"))
+ contentType = arg;
+ }
+ }
+
+ MemoryStream mem(100*1024);
+ while (!rsock->eof())
+ {
+ int len=0;
+ char buf[4096];
+ len = rsock->readUpto(buf,sizeof(buf));
+ if (len==0)
+ break;
+ else
+ mem.write(buf,len);
+
+ }
+ rsock->close();
+
+ int fileLen = mem.getPosition();
+ mem.len = fileLen;
+ mem.rewind();
+
+
+ if (contentType.contains(MIME_HTML))
+ isTemplate = true;
+
+ sock->writeLine(HTTP_SC_OK);
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache");
+ sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr());
+
+ sock->writeLine("");
+
+ if (isTemplate)
+ {
+ HTML html("",*sock);
+ html.readTemplate(mem,sock,0);
+ }else
+ sock->write(mem.buf,fileLen);
+
+ mem.free2();
+}
--- /dev/null
+// ------------------------------------------------
+// File : servmgr.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Management class for handling multiple servent connections.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "inifile.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "atom.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo ServMgr::serverThread,ServMgr::idleThread;
+
+// -----------------------------------
+ServMgr::ServMgr()
+{
+ validBCID = NULL;
+
+ authType = AUTH_COOKIE;
+ cookieList.init();
+
+ serventNum = 0;
+
+ startTime = sys->getTime();
+
+ allowServer1 = Servent::ALLOW_ALL;
+ allowServer2 = Servent::ALLOW_BROADCAST;
+
+ clearHostCache(ServHost::T_NONE);
+ password[0]=0;
+
+ allowGnutella = false;
+ useFlowControl = true;
+
+ maxServIn = 50;
+ minGnuIncoming = 10;
+ maxGnuIncoming = 20;
+
+ lastIncoming = 0;
+
+ maxBitrateOut = 540; //JP-Patch 0-> 540
+ maxRelays = MIN_RELAYS;
+ maxDirect = 0;
+ refreshHTML = 1800;
+
+ networkID.clear();
+
+ notifyMask = 0xffff;
+
+ tryoutDelay = 10;
+ numVersions = 0;
+
+ sessionID.generate();
+
+ isDisabled = false;
+ isRoot = false;
+
+ forceIP.clear();
+
+ strcpy(connectHost,"connect1.peercast.org");
+ strcpy(htmlPath,"html/ja");
+
+ rootHost = "yp.peercast.org";
+ rootHost2 = "";
+
+ serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT);
+
+ firewalled = FW_UNKNOWN;
+ allowDirect = true;
+ autoConnect = true;
+ forceLookup = true;
+ autoServe = true;
+ forceNormal = false;
+
+ maxControl = 3;
+
+ queryTTL = 7;
+
+ totalStreams = 0;
+ firewallTimeout = 30;
+ pauseLog = false;
+ showLog = 0;
+
+ shutdownTimer = 0;
+
+ downloadURL[0] = 0;
+ rootMsg.clear();
+
+
+ restartServer=false;
+
+ setFilterDefaults();
+
+ servents = NULL;
+
+ modulePath[0] = 0; //JP-EX
+ kickPushStartRelays = 1; //JP-EX
+ kickPushInterval = 60; //JP-EX
+ kickPushTime = 0; //JP-EX
+ autoRelayKeep = 2; //JP-EX
+ autoMaxRelaySetting = 0; //JP-EX
+ autoBumpSkipCount = 50; //JP-EX
+ enableGetName = 1; //JP-EX
+ allowConnectPCST = 0; //JP-EX
+ getModulePath = true; //JP-EX
+ clearPLS = false; //JP-EX
+ writeLogFile = false; //JP-EX
+
+ autoPort0Kick = false;
+ allowOnlyVP = false;
+ kickKeepTime = 0;
+ vpDebug = false;
+ saveIniChannel = true;
+ saveGuiPos = false;
+ keepDownstreams = true;
+
+ chanLog="";
+
+ maxRelaysIndexTxt = 1; // for PCRaw (relay)
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(int index)
+{
+ int cnt = 0;
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ if (cnt == index)
+ return bcid;
+ cnt++;
+ bcid=bcid->next;
+ }
+ return 0;
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(GnuID &id)
+{
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ if (bcid->id.isSame(id))
+ return bcid;
+ bcid=bcid->next;
+ }
+ return 0;
+}
+// -----------------------------------
+void ServMgr::removeValidBCID(GnuID &id)
+{
+ BCID *bcid = validBCID,*prev=0;
+ while (bcid)
+ {
+ if (bcid->id.isSame(id))
+ {
+ if (prev)
+ prev->next = bcid->next;
+ else
+ validBCID = bcid->next;
+ return;
+ }
+ prev = bcid;
+ bcid=bcid->next;
+ }
+}
+// -----------------------------------
+void ServMgr::addValidBCID(BCID *bcid)
+{
+ removeValidBCID(bcid->id);
+
+ bcid->next = validBCID;
+ validBCID = bcid;
+}
+
+// -----------------------------------
+void ServMgr::connectBroadcaster()
+{
+ if (!rootHost.isEmpty())
+ {
+ if (!numUsed(Servent::T_COUT))
+ {
+ Servent *sv = allocServent();
+ if (sv)
+ {
+ sv->initOutgoing(Servent::T_COUT);
+ sys->sleep(3000);
+ }
+ }
+ }
+}
+// -----------------------------------
+void ServMgr::addVersion(unsigned int ver)
+{
+ for(int i=0; i<numVersions; i++)
+ if (clientVersions[i] == ver)
+ {
+ clientCounts[i]++;
+ return;
+ }
+
+ if (numVersions < MAX_VERSIONS)
+ {
+ clientVersions[numVersions] = ver;
+ clientCounts[numVersions] = 1;
+ numVersions++;
+ }
+}
+
+// -----------------------------------
+void ServMgr::setFilterDefaults()
+{
+ numFilters = 0;
+
+ filters[numFilters].host.fromStrIP("255.255.255.255",0);
+// filters[numFilters].flags = ServFilter::F_NETWORK|ServFilter::F_DIRECT;
+ filters[numFilters].flags = ServFilter::F_NETWORK;
+
+ numFilters++;
+
+}
+
+// -----------------------------------
+void ServMgr::setPassiveSearch(unsigned int t)
+{
+// if ((t > 0) && (t < 60))
+// t = 60;
+// passiveSearch = t;
+}
+// -----------------------------------
+bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time)
+{
+ time = sys->getTime()-time;
+
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == type)
+ if (hostCache[i].host.ip == h.ip)
+ if (hostCache[i].time >= time)
+ return true;
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time)
+{
+ int i;
+ if (!h.isValid())
+ return;
+
+ ServHost *sh=NULL;
+
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == type)
+ if (hostCache[i].host.isSame(h))
+ {
+ sh = &hostCache[i];
+ break;
+ }
+
+ char str[64];
+ h.toStr(str);
+
+ if (!sh)
+ LOG_DEBUG("New host: %s - %s",str,ServHost::getTypeStr(type));
+ else
+ LOG_DEBUG("Old host: %s - %s",str,ServHost::getTypeStr(type));
+
+ h.value = 0; // make sure dead count is zero
+ if (!sh)
+ {
+
+
+ // find empty slot
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == ServHost::T_NONE)
+ {
+ sh = &hostCache[i];
+ break;
+ }
+
+ // otherwise, find oldest host and replace
+ if (!sh)
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type != ServHost::T_NONE)
+ {
+ if (sh)
+ {
+ if (hostCache[i].time < sh->time)
+ sh = &hostCache[i];
+ }else{
+ sh = &hostCache[i];
+ }
+ }
+ }
+
+ if (sh)
+ sh->init(h,type,time);
+}
+
+// -----------------------------------
+void ServMgr::deadHost(Host &h,ServHost::TYPE t)
+{
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == t)
+ if (hostCache[i].host.ip == h.ip)
+ if (hostCache[i].host.port == h.port)
+ hostCache[i].init();
+}
+// -----------------------------------
+void ServMgr::clearHostCache(ServHost::TYPE type)
+{
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+ hostCache[i].init();
+}
+
+// -----------------------------------
+unsigned int ServMgr::numHosts(ServHost::TYPE type)
+{
+ unsigned int cnt = 0;
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+ cnt++;
+ return cnt;
+}
+// -----------------------------------
+int ServMgr::getNewestServents(Host *hl,int max,Host &rh)
+{
+ int cnt=0;
+ for(int i=0; i<max; i++)
+ {
+ // find newest host not in list
+ ServHost *sh=NULL;
+ for(int j=0; j<MAX_HOSTCACHE; j++)
+ {
+ // find newest servent
+ if (hostCache[j].type == ServHost::T_SERVENT)
+ if (!(rh.globalIP() && !hostCache[j].host.globalIP()))
+ {
+ // and not in list already
+ bool found=false;
+ for(int k=0; k<cnt; k++)
+ if (hl[k].isSame(hostCache[j].host))
+ {
+ found=true;
+ break;
+ }
+
+ if (!found)
+ {
+ if (!sh)
+ {
+ sh = &hostCache[j];
+ }else{
+ if (hostCache[j].time > sh->time)
+ sh = &hostCache[j];
+ }
+ }
+ }
+ }
+
+ // add to list
+ if (sh)
+ hl[cnt++]=sh->host;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+ServHost ServMgr::getOutgoingServent(GnuID &netid)
+{
+ ServHost host;
+
+ Host lh(ClientSocket::getIP(NULL),0);
+
+ // find newest host not in list
+ ServHost *sh=NULL;
+ for(int j=0; j<MAX_HOSTCACHE; j++)
+ {
+ ServHost *hc=&hostCache[j];
+ // find newest servent not already connected.
+ if (hc->type == ServHost::T_SERVENT)
+ {
+ if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host)))
+ {
+#if 0
+ if (!findServent(Servent::T_OUTGOING,hc->host,netid))
+ {
+ if (!sh)
+ {
+ sh = hc;
+ }else{
+ if (hc->time > sh->time)
+ sh = hc;
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ if (sh)
+ host = *sh;
+
+ return host;
+}
+// -----------------------------------
+Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv)
+{
+ Servent *oldest=NULL;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ if (s->thread.active)
+ if (s->isOlderThan(oldest))
+ if (s->isPrivate() == priv)
+ oldest = s;
+ s=s->next;
+ }
+ return oldest;
+}
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid)
+{
+ lock.on();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ {
+ Host h = s->getHost();
+ if (h.isSame(host) && s->networkID.isSame(netid))
+ {
+ lock.off();
+ return s;
+ }
+ }
+ s=s->next;
+ }
+ lock.off();
+ return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid)
+{
+ lock.on();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type != Servent::T_NONE)
+ {
+ Host h = s->getHost();
+ if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid)))
+ {
+ lock.off();
+ return s;
+ }
+ }
+ s=s->next;
+ }
+ lock.off();
+ return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE t)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == t)
+ return s;
+ s=s->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Servent *ServMgr::findServentByIndex(int id)
+{
+ Servent *s = servents;
+ int cnt=0;
+ while (s)
+ {
+ if (cnt == id)
+ return s;
+ cnt++;
+ s=s->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::findServentByServentID(int id)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (id == s->servent_id){
+ return s;
+ }
+ s=s->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::allocServent()
+{
+ lock.on();
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->status == Servent::S_FREE)
+ break;
+ s=s->next;
+ }
+
+ if (!s)
+ {
+ s = new Servent(++serventNum);
+ s->next = servents;
+ servents = s;
+
+ LOG_DEBUG("allocated servent %d",serventNum);
+ }else
+ LOG_DEBUG("reused servent %d",s->serventIndex);
+
+
+ s->reset();
+
+ lock.off();
+
+ return s;
+}
+// --------------------------------------------------
+void ServMgr::closeConnections(Servent::TYPE type)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == type)
+ sv->thread.active = false;
+ sv=sv->next;
+ }
+}
+
+// -----------------------------------
+unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime)
+{
+ unsigned int cnt=0;
+
+ unsigned int ctime=sys->getTime();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active)
+ if (s->isConnected())
+ if (s->type == type)
+ if (s->isPrivate()==priv)
+ if ((ctime-s->lastConnect) >= uptime)
+ cnt++;
+
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numConnected()
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active)
+ if (s->isConnected())
+ cnt++;
+
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numServents()
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numUsed(int type)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActiveOnPort(int port)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active && s->sock && (s->servPort == port))
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActive(Servent::TYPE tp)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active && s->sock && (s->type == tp))
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalOutput(bool all)
+{
+ unsigned int tot = 0;
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (all || !s->isPrivate())
+ if (s->sock)
+ tot += s->sock->bytesOutPerSec;
+ s=s->next;
+ }
+
+ return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalInput(bool all)
+{
+ unsigned int tot = 0;
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (all || !s->isPrivate())
+ if (s->sock)
+ tot += s->sock->bytesInPerSec;
+ s=s->next;
+ }
+
+ return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numOutgoing()
+{
+ int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+// if ((s->type == Servent::T_INCOMING) ||
+// (s->type == Servent::T_OUTGOING))
+// cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+bool ServMgr::seenPacket(GnuPacket &p)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (s->seenIDs.contains(p.id))
+ return true;
+ s=s->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::quit()
+{
+ LOG_DEBUG("ServMgr is quitting..");
+
+ serverThread.shutdown();
+
+ idleThread.shutdown();
+
+ Servent *s = servents;
+ while (s)
+ {
+ try
+ {
+ if (s->thread.active)
+ {
+ s->thread.shutdown();
+ }
+
+ }catch(StreamException &)
+ {
+ }
+ s=s->next;
+ }
+}
+
+// -----------------------------------
+int ServMgr::broadcast(GnuPacket &pack,Servent *src)
+{
+ int cnt=0;
+ if (pack.ttl)
+ {
+ Servent *s = servents;
+ while (s)
+ {
+
+ if (s != src)
+ if (s->isConnected())
+ if (s->type == Servent::T_PGNU)
+ if (!s->seenIDs.contains(pack.id))
+ {
+
+ if (src)
+ if (!src->networkID.isSame(s->networkID))
+ continue;
+
+ if (s->outputPacket(pack,false))
+ cnt++;
+ }
+ s=s->next;
+ }
+ }
+
+ LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+
+ return cnt;
+}
+// -----------------------------------
+int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src)
+{
+ int cnt=0;
+ if (pack.ttl)
+ {
+ Servent *s = servents;
+ while (s)
+ {
+ if (s != src)
+ if (s->isConnected())
+ if (s->type == Servent::T_PGNU)
+ if (!s->seenIDs.contains(pack.id))
+ if (s->seenIDs.contains(routeID))
+ {
+ if (src)
+ if (!src->networkID.isSame(s->networkID))
+ continue;
+
+ if (s->outputPacket(pack,true))
+ cnt++;
+ }
+ s=s->next;
+ }
+
+ }
+
+ LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+ return cnt;
+}
+// -----------------------------------
+bool ServMgr::checkForceIP()
+{
+ if (!forceIP.isEmpty())
+ {
+ unsigned int newIP = ClientSocket::getIP(forceIP.cstr());
+ if (serverHost.ip != newIP)
+ {
+ serverHost.ip = newIP;
+ char ipstr[64];
+ serverHost.IPtoStr(ipstr);
+ LOG_DEBUG("Server IP changed to %s",ipstr);
+ return true;
+ }
+ }
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::checkFirewall()
+{
+ if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty())
+ {
+
+ LOG_DEBUG("Checking firewall..");
+ Host host;
+ host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+
+ ClientSocket *sock = sys->createSocket();
+ if (!sock)
+ throw StreamException("Unable to create socket");
+ sock->setReadTimeout(30000);
+ sock->open(host);
+ sock->connect();
+
+ AtomStream atom(*sock);
+
+ atom.writeInt(PCP_CONNECT,1);
+
+ GnuID remoteID;
+ String agent;
+ Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true);
+
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+ sock->close();
+ delete sock;
+ }
+}
+
+// -----------------------------------
+void ServMgr::setFirewall(FW_STATE state)
+{
+ if (firewalled != state)
+ {
+ char *str;
+ switch (state)
+ {
+ case FW_ON:
+ str = "ON";
+ break;
+ case FW_OFF:
+ str = "OFF";
+ break;
+ case FW_UNKNOWN:
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+
+ LOG_DEBUG("Firewall is set to %s",str);
+ firewalled = state;
+ }
+}
+// -----------------------------------
+bool ServMgr::isFiltered(int fl, Host &h)
+{
+ for(int i=0; i<numFilters; i++)
+ if (filters[i].flags & fl)
+ if (h.isMemberOf(filters[i].host))
+ return true;
+
+ return false;
+}
+
+#if 0
+// -----------------------------------
+bool ServMgr::canServeHost(Host &h)
+{
+ if (server)
+ {
+ Host sh = server->getHost();
+
+ if (sh.globalIP() || (sh.localIP() && h.localIP()))
+ return true;
+ }
+ return false;
+}
+#endif
+
+// --------------------------------------------------
+void writeServerSettings(IniFile &iniFile, unsigned int a)
+{
+ iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML);
+ iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST);
+ iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK);
+ iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT);
+}
+// --------------------------------------------------
+void writeFilterSettings(IniFile &iniFile, ServFilter &f)
+{
+ char ipstr[64];
+ f.host.IPtoStr(ipstr);
+ iniFile.writeStrValue("ip",ipstr);
+ iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE);
+ iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN);
+ iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK);
+ iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT);
+}
+
+// --------------------------------------------------
+static void writeServHost(IniFile &iniFile, ServHost &sh)
+{
+ iniFile.writeSection("Host");
+
+ char ipStr[64];
+ sh.host.toStr(ipStr);
+ iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type));
+ iniFile.writeStrValue("address",ipStr);
+ iniFile.writeIntValue("time",sh.time);
+
+ iniFile.writeLine("[End]");
+}
+
+#ifdef WIN32
+extern bool guiFlg;
+extern WINDOWPLACEMENT winPlace;
+extern HWND guiWnd;
+#endif
+
+// --------------------------------------------------
+void ServMgr::saveSettings(const char *fn)
+{
+ IniFile iniFile;
+ if (!iniFile.openWriteReplace(fn))
+ {
+ LOG_ERROR("Unable to open ini file");
+ }else{
+ LOG_DEBUG("Saving settings to: %s",fn);
+
+ char idStr[64];
+
+ iniFile.writeSection("Server");
+ iniFile.writeIntValue("serverPort",servMgr->serverHost.port);
+ iniFile.writeBoolValue("autoServe",servMgr->autoServe);
+ iniFile.writeStrValue("forceIP",servMgr->forceIP);
+ iniFile.writeBoolValue("isRoot",servMgr->isRoot);
+ iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut);
+ iniFile.writeIntValue("maxRelays",servMgr->maxRelays);
+ iniFile.writeIntValue("maxDirect",servMgr->maxDirect);
+ iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel);
+ iniFile.writeIntValue("firewallTimeout",firewallTimeout);
+ iniFile.writeBoolValue("forceNormal",forceNormal);
+ iniFile.writeStrValue("rootMsg",rootMsg.cstr());
+ iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic");
+ iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session");
+ iniFile.writeStrValue("htmlPath",servMgr->htmlPath);
+ iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming);
+ iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming);
+ iniFile.writeIntValue("maxServIn",servMgr->maxServIn);
+ iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr());
+
+ networkID.toStr(idStr);
+ iniFile.writeStrValue("networkID",idStr);
+
+
+ iniFile.writeSection("Broadcast");
+ iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval);
+ iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr());
+ iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval);
+ chanMgr->broadcastID.toStr(idStr);
+ iniFile.writeStrValue("broadcastID",idStr);
+ iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval);
+ iniFile.writeIntValue("maxControlConnections",servMgr->maxControl);
+ iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr());
+
+ iniFile.writeSection("Client");
+ iniFile.writeIntValue("refreshHTML",refreshHTML);
+ iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast);
+ iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL);
+ iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL);
+ iniFile.writeIntValue("pushTries",chanMgr->pushTries);
+ iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout);
+ iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops);
+ iniFile.writeIntValue("autoQuery",chanMgr->autoQuery);
+ iniFile.writeIntValue("queryTTL",servMgr->queryTTL);
+
+
+ iniFile.writeSection("Privacy");
+ iniFile.writeStrValue("password",servMgr->password);
+ iniFile.writeIntValue("maxUptime",chanMgr->maxUptime);
+
+ //JP-EX
+ iniFile.writeSection("Extend");
+ iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep);
+ iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting);
+ iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount);
+ iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays);
+ iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval);
+ iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST);
+ iniFile.writeIntValue("enableGetName",servMgr->enableGetName);
+
+ iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay)
+
+ //JP-EX
+ iniFile.writeSection("Windows");
+ iniFile.writeBoolValue("getModulePath",servMgr->getModulePath);
+ iniFile.writeBoolValue("clearPLS",servMgr->clearPLS);
+ iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile);
+
+ //VP-EX
+ iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr());
+ iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick);
+ iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP);
+ iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime);
+ iniFile.writeBoolValue("vpDebug", servMgr->vpDebug);
+ iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel);
+#ifdef WIN32
+ iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos);
+ if (guiFlg){
+ GetWindowPlacement(guiWnd, &winPlace);
+ iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top);
+ iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom);
+ iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left);
+ iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right);
+ }
+#endif
+ int i;
+
+ for(i=0; i<servMgr->numFilters; i++)
+ {
+ iniFile.writeSection("Filter");
+ writeFilterSettings(iniFile,servMgr->filters[i]);
+ iniFile.writeLine("[End]");
+ }
+
+ iniFile.writeSection("Notify");
+ iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST);
+ iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS);
+ iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO);
+ iniFile.writeLine("[End]");
+
+
+ iniFile.writeSection("Server1");
+ writeServerSettings(iniFile,allowServer1);
+ iniFile.writeLine("[End]");
+
+ iniFile.writeSection("Server2");
+ writeServerSettings(iniFile,allowServer2);
+ iniFile.writeLine("[End]");
+
+
+
+ iniFile.writeSection("Debug");
+ iniFile.writeBoolValue("logDebug",(showLog&(1<<LogBuffer::T_DEBUG))!=0);
+ iniFile.writeBoolValue("logErrors",(showLog&(1<<LogBuffer::T_ERROR))!=0);
+ iniFile.writeBoolValue("logNetwork",(showLog&(1<<LogBuffer::T_NETWORK))!=0);
+ iniFile.writeBoolValue("logChannel",(showLog&(1<<LogBuffer::T_CHANNEL))!=0);
+ iniFile.writeBoolValue("pauseLog",pauseLog);
+ iniFile.writeIntValue("idleSleepTime",sys->idleSleepTime);
+
+
+ if (servMgr->validBCID)
+ {
+ BCID *bcid = servMgr->validBCID;
+ while (bcid)
+ {
+ iniFile.writeSection("ValidBCID");
+ char idstr[128];
+ bcid->id.toStr(idstr);
+ iniFile.writeStrValue("id",idstr);
+ iniFile.writeStrValue("name",bcid->name.cstr());
+ iniFile.writeStrValue("email",bcid->email.cstr());
+ iniFile.writeStrValue("url",bcid->url.cstr());
+ iniFile.writeBoolValue("valid",bcid->valid);
+ iniFile.writeLine("[End]");
+
+ bcid=bcid->next;
+ }
+ }
+
+ if (servMgr->saveIniChannel){
+ Channel *c = chanMgr->channel;
+ while (c)
+ {
+ char idstr[64];
+ if (c->isActive() && c->stayConnected)
+ {
+ c->getIDStr(idstr);
+
+ iniFile.writeSection("RelayChannel");
+ iniFile.writeStrValue("name",c->getName());
+ iniFile.writeStrValue("genre",c->info.genre.cstr());
+ if (!c->sourceURL.isEmpty())
+ iniFile.writeStrValue("sourceURL",c->sourceURL.cstr());
+ iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol));
+ iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType));
+ iniFile.writeIntValue("bitrate",c->info.bitrate);
+ iniFile.writeStrValue("contactURL",c->info.url.cstr());
+ iniFile.writeStrValue("id",idstr);
+ iniFile.writeBoolValue("stayConnected",c->stayConnected);
+
+ ChanHitList *chl = chanMgr->findHitListByID(c->info.id);
+ if (chl)
+ {
+
+ ChanHitSearch chs;
+ chs.trackersOnly = true;
+ if (chl->pickHits(chs))
+ {
+ char ipStr[64];
+ chs.best[0].host.toStr(ipStr);
+ iniFile.writeStrValue("tracker",ipStr);
+ }
+ }
+ iniFile.writeLine("[End]");
+ }
+ c=c->next;
+ }
+ }
+
+
+
+#if 0
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == Servent::T_OUTGOING)
+ if (s->isConnected())
+ {
+ ServHost sh;
+ Host h = s->getHost();
+ sh.init(h,ServHost::T_SERVENT,0,s->networkID);
+ writeServHost(iniFile,sh);
+ }
+ s=s->next;
+ }
+#endif
+
+ for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+ {
+ ServHost *sh = &servMgr->hostCache[i];
+ if (sh->type != ServHost::T_NONE)
+ writeServHost(iniFile,*sh);
+ }
+
+ iniFile.close();
+ }
+}
+// --------------------------------------------------
+unsigned int readServerSettings(IniFile &iniFile, unsigned int a)
+{
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("allowHTML"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML;
+ else if (iniFile.isName("allowDirect"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT;
+ else if (iniFile.isName("allowNetwork"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK;
+ else if (iniFile.isName("allowBroadcast"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST;
+ }
+ return a;
+}
+// --------------------------------------------------
+void readFilterSettings(IniFile &iniFile, ServFilter &sv)
+{
+ sv.host.init();
+
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("ip"))
+ sv.host.fromStrIP(iniFile.getStrValue(),0);
+ else if (iniFile.isName("private"))
+ sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0);
+ else if (iniFile.isName("ban"))
+ sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0);
+ else if (iniFile.isName("allow") || iniFile.isName("network"))
+ sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0);
+ else if (iniFile.isName("direct"))
+ sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0);
+ }
+
+}
+// --------------------------------------------------
+void ServMgr::loadSettings(const char *fn)
+{
+ IniFile iniFile;
+
+ if (!iniFile.openReadOnly(fn))
+ saveSettings(fn);
+
+
+ servMgr->numFilters = 0;
+ showLog = 0;
+
+ if (iniFile.openReadOnly(fn))
+ {
+ while (iniFile.readNext())
+ {
+ // server settings
+ if (iniFile.isName("serverPort"))
+ servMgr->serverHost.port = iniFile.getIntValue();
+ else if (iniFile.isName("autoServe"))
+ servMgr->autoServe = iniFile.getBoolValue();
+ else if (iniFile.isName("autoConnect"))
+ servMgr->autoConnect = iniFile.getBoolValue();
+ else if (iniFile.isName("icyPassword")) // depreciated
+ strcpy(servMgr->password,iniFile.getStrValue());
+ else if (iniFile.isName("forceIP"))
+ servMgr->forceIP = iniFile.getStrValue();
+ else if (iniFile.isName("isRoot"))
+ servMgr->isRoot = iniFile.getBoolValue();
+ else if (iniFile.isName("broadcastID"))
+ {
+ chanMgr->broadcastID.fromStr(iniFile.getStrValue());
+ chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS; // hacky, but we need to fix old clients
+
+ }else if (iniFile.isName("htmlPath"))
+ strcpy(servMgr->htmlPath,iniFile.getStrValue());
+ else if (iniFile.isName("maxPGNUIncoming"))
+ servMgr->maxGnuIncoming = iniFile.getIntValue();
+ else if (iniFile.isName("minPGNUIncoming"))
+ servMgr->minGnuIncoming = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxControlConnections"))
+ {
+ servMgr->maxControl = iniFile.getIntValue();
+
+ }
+ else if (iniFile.isName("maxBitrateOut"))
+ servMgr->maxBitrateOut = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxStreamsOut")) // depreciated
+ servMgr->setMaxRelays(iniFile.getIntValue());
+ else if (iniFile.isName("maxRelays"))
+ servMgr->setMaxRelays(iniFile.getIntValue());
+ else if (iniFile.isName("maxDirect"))
+ servMgr->maxDirect = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxStreamsPerChannel")) // depreciated
+ chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+ else if (iniFile.isName("maxRelaysPerChannel"))
+ chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+
+ else if (iniFile.isName("firewallTimeout"))
+ firewallTimeout = iniFile.getIntValue();
+ else if (iniFile.isName("forceNormal"))
+ forceNormal = iniFile.getBoolValue();
+ else if (iniFile.isName("broadcastMsgInterval"))
+ chanMgr->broadcastMsgInterval = iniFile.getIntValue();
+ else if (iniFile.isName("broadcastMsg"))
+ chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII);
+ else if (iniFile.isName("hostUpdateInterval"))
+ chanMgr->hostUpdateInterval = iniFile.getIntValue();
+ else if (iniFile.isName("icyMetaInterval"))
+ chanMgr->icyMetaInterval = iniFile.getIntValue();
+ else if (iniFile.isName("maxServIn"))
+ servMgr->maxServIn = iniFile.getIntValue();
+ else if (iniFile.isName("chanLog"))
+ servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII);
+
+ else if (iniFile.isName("rootMsg"))
+ rootMsg.set(iniFile.getStrValue());
+ else if (iniFile.isName("networkID"))
+ networkID.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("authType"))
+ {
+ char *t = iniFile.getStrValue();
+ if (stricmp(t,"cookie")==0)
+ servMgr->authType = ServMgr::AUTH_COOKIE;
+ else if (stricmp(t,"http-basic")==0)
+ servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+ }else if (iniFile.isName("cookiesExpire"))
+ {
+ char *t = iniFile.getStrValue();
+ if (stricmp(t,"never")==0)
+ servMgr->cookieList.neverExpire = true;
+ else if (stricmp(t,"session")==0)
+ servMgr->cookieList.neverExpire = false;
+
+
+ }
+
+ // privacy settings
+ else if (iniFile.isName("password"))
+ strcpy(servMgr->password,iniFile.getStrValue());
+ else if (iniFile.isName("maxUptime"))
+ chanMgr->maxUptime = iniFile.getIntValue();
+
+ // client settings
+
+ else if (iniFile.isName("rootHost"))
+ {
+ if (!PCP_FORCE_YP)
+ servMgr->rootHost = iniFile.getStrValue();
+
+ }else if (iniFile.isName("deadHitAge"))
+ chanMgr->deadHitAge = iniFile.getIntValue();
+ else if (iniFile.isName("tryoutDelay"))
+ servMgr->tryoutDelay = iniFile.getIntValue();
+ else if (iniFile.isName("refreshHTML"))
+ refreshHTML = iniFile.getIntValue();
+ else if (iniFile.isName("relayBroadcast"))
+ {
+ servMgr->relayBroadcast = iniFile.getIntValue();
+ if (servMgr->relayBroadcast < 30)
+ servMgr->relayBroadcast = 30;
+ }
+ else if (iniFile.isName("minBroadcastTTL"))
+ chanMgr->minBroadcastTTL = iniFile.getIntValue();
+ else if (iniFile.isName("maxBroadcastTTL"))
+ chanMgr->maxBroadcastTTL = iniFile.getIntValue();
+ else if (iniFile.isName("pushTimeout"))
+ chanMgr->pushTimeout = iniFile.getIntValue();
+ else if (iniFile.isName("pushTries"))
+ chanMgr->pushTries = iniFile.getIntValue();
+ else if (iniFile.isName("maxPushHops"))
+ chanMgr->maxPushHops = iniFile.getIntValue();
+ else if (iniFile.isName("autoQuery"))
+ {
+ chanMgr->autoQuery = iniFile.getIntValue();
+ if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0))
+ chanMgr->autoQuery = 300;
+ }
+ else if (iniFile.isName("queryTTL"))
+ {
+ servMgr->queryTTL = iniFile.getIntValue();
+ }
+
+ //JP-Extend
+ else if (iniFile.isName("autoRelayKeep"))
+ servMgr->autoRelayKeep = iniFile.getIntValue();
+ else if (iniFile.isName("autoMaxRelaySetting"))
+ servMgr->autoMaxRelaySetting = iniFile.getIntValue();
+ else if (iniFile.isName("autoBumpSkipCount"))
+ servMgr->autoBumpSkipCount = iniFile.getIntValue();
+ else if (iniFile.isName("kickPushStartRelays"))
+ servMgr->kickPushStartRelays = iniFile.getIntValue();
+ else if (iniFile.isName("kickPushInterval"))
+ {
+ servMgr->kickPushInterval = iniFile.getIntValue();
+ if (servMgr->kickPushInterval < 60)
+ servMgr->kickPushInterval = 0;
+ }
+ else if (iniFile.isName("allowConnectPCST"))
+ servMgr->allowConnectPCST = iniFile.getIntValue();
+ else if (iniFile.isName("enableGetName"))
+ servMgr->enableGetName = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxRelaysIndexTxt")) // for PCRaw (relay)
+ servMgr->maxRelaysIndexTxt = iniFile.getIntValue();
+
+ //JP-Windows
+ else if (iniFile.isName("getModulePath"))
+ servMgr->getModulePath = iniFile.getBoolValue();
+ else if (iniFile.isName("clearPLS"))
+ servMgr->clearPLS = iniFile.getBoolValue();
+ else if (iniFile.isName("writeLogFile"))
+ servMgr->writeLogFile = iniFile.getBoolValue();
+
+ //VP-EX
+ else if (iniFile.isName("rootHost2"))
+ {
+ if (!PCP_FORCE_YP)
+ servMgr->rootHost2 = iniFile.getStrValue();
+ }
+ else if (iniFile.isName("autoPort0Kick"))
+ servMgr->autoPort0Kick = iniFile.getBoolValue();
+ else if (iniFile.isName("allowOnlyVP"))
+ servMgr->allowOnlyVP = iniFile.getBoolValue();
+ else if (iniFile.isName("kickKeepTime"))
+ servMgr->kickKeepTime = iniFile.getIntValue();
+ else if (iniFile.isName("vpDebug"))
+ servMgr->vpDebug = iniFile.getBoolValue();
+ else if (iniFile.isName("saveIniChannel"))
+ servMgr->saveIniChannel = iniFile.getBoolValue();
+#ifdef WIN32
+ else if (iniFile.isName("saveGuiPos"))
+ servMgr->saveGuiPos = iniFile.getBoolValue();
+ else if (iniFile.isName("guiTop"))
+ winPlace.rcNormalPosition.top = iniFile.getIntValue();
+ else if (iniFile.isName("guiBottom"))
+ winPlace.rcNormalPosition.bottom = iniFile.getIntValue();
+ else if (iniFile.isName("guiLeft"))
+ winPlace.rcNormalPosition.left = iniFile.getIntValue();
+ else if (iniFile.isName("guiRight")){
+ winPlace.rcNormalPosition.right = iniFile.getIntValue();
+ winPlace.length = sizeof(winPlace);
+ winPlace.flags = 0;
+ winPlace.showCmd = 1;
+ winPlace.ptMinPosition.x = -1;
+ winPlace.ptMinPosition.y = -1;
+ winPlace.ptMaxPosition.x = -1;
+ winPlace.ptMaxPosition.y = -1;
+ if (servMgr->saveGuiPos){
+ guiFlg = true;
+ }
+ }
+#endif
+
+ // debug
+ else if (iniFile.isName("logDebug"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_DEBUG:0;
+ else if (iniFile.isName("logErrors"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_ERROR:0;
+ else if (iniFile.isName("logNetwork"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_NETWORK:0;
+ else if (iniFile.isName("logChannel"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_CHANNEL:0;
+ else if (iniFile.isName("pauseLog"))
+ pauseLog = iniFile.getBoolValue();
+ else if (iniFile.isName("idleSleepTime"))
+ sys->idleSleepTime = iniFile.getIntValue();
+ else if (iniFile.isName("[Server1]"))
+ allowServer1 = readServerSettings(iniFile,allowServer1);
+ else if (iniFile.isName("[Server2]"))
+ allowServer2 = readServerSettings(iniFile,allowServer2);
+ else if (iniFile.isName("[Filter]"))
+ {
+ readFilterSettings(iniFile,filters[numFilters]);
+
+ if (numFilters < (MAX_FILTERS-1))
+ numFilters++;
+ }
+ else if (iniFile.isName("[Notify]"))
+ {
+ notifyMask = NT_UPGRADE;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("PeerCast"))
+ notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0;
+ else if (iniFile.isName("Broadcasters"))
+ notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0;
+ else if (iniFile.isName("TrackInfo"))
+ notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0;
+ }
+
+ }
+ else if (iniFile.isName("[RelayChannel]"))
+ {
+ ChanInfo info;
+ bool stayConnected=false;
+ String sourceURL;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("name"))
+ info.name.set(iniFile.getStrValue());
+ else if (iniFile.isName("id"))
+ info.id.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("sourceType"))
+ info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("contentType"))
+ info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("stayConnected"))
+ stayConnected = iniFile.getBoolValue();
+ else if (iniFile.isName("sourceURL"))
+ sourceURL.set(iniFile.getStrValue());
+ else if (iniFile.isName("genre"))
+ info.genre.set(iniFile.getStrValue());
+ else if (iniFile.isName("contactURL"))
+ info.url.set(iniFile.getStrValue());
+ else if (iniFile.isName("bitrate"))
+ info.bitrate = atoi(iniFile.getStrValue());
+ else if (iniFile.isName("tracker"))
+ {
+ ChanHit hit;
+ hit.init();
+ hit.tracker = true;
+ hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT);
+ hit.rhost[0] = hit.host;
+ hit.rhost[1] = hit.host;
+ hit.chanID = info.id;
+ hit.recv = true;
+ chanMgr->addHit(hit);
+ }
+
+ }
+ if (sourceURL.isEmpty())
+ {
+ chanMgr->createRelay(info,stayConnected);
+ }else
+ {
+ info.bcID = chanMgr->broadcastID;
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ c->startURL(sourceURL.cstr());
+ }
+ } else if (iniFile.isName("[Host]"))
+ {
+ Host h;
+ ServHost::TYPE type=ServHost::T_NONE;
+ bool firewalled=false;
+ unsigned int time=0;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("address"))
+ h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT);
+ else if (iniFile.isName("type"))
+ type = ServHost::getTypeFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("time"))
+ time = iniFile.getIntValue();
+ }
+ servMgr->addHost(h,type,time);
+
+ } else if (iniFile.isName("[ValidBCID]"))
+ {
+ BCID *bcid = new BCID();
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("id"))
+ bcid->id.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("name"))
+ bcid->name.set(iniFile.getStrValue());
+ else if (iniFile.isName("email"))
+ bcid->email.set(iniFile.getStrValue());
+ else if (iniFile.isName("url"))
+ bcid->url.set(iniFile.getStrValue());
+ else if (iniFile.isName("valid"))
+ bcid->valid = iniFile.getBoolValue();
+ }
+ servMgr->addValidBCID(bcid);
+ }
+ }
+ }
+
+ if (!numFilters)
+ setFilterDefaults();
+
+}
+
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all)
+{
+ int cnt = 0;
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == tp)
+ if (sv->chanID.isSame(cid))
+ if (all || !sv->isPrivate())
+ cnt++;
+ sv=sv->next;
+ }
+ return cnt;
+}
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all)
+{
+ int cnt = 0;
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == tp)
+ if (all || !sv->isPrivate())
+ {
+ // for PCRaw (relay) start.
+ if(tp == Servent::T_RELAY)
+ {
+ Channel *ch = chanMgr->findChannelByID(sv->chanID);
+
+ // index.txt\82Í\83J\83E\83\93\83g\82µ\82È\82¢
+ if(!isIndexTxt(ch))
+ cnt++;
+ }
+ else
+ // for PCRaw (relay) end.
+ {
+ cnt++;
+ }
+ }
+ sv=sv->next;
+ }
+ return cnt;
+}
+
+// --------------------------------------------------
+bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay)
+{
+ // remove file extension (only added for winamp)
+ //char *ext = strstr(str,".");
+ //if (ext) *ext = 0;
+
+ procConnectArgs(str,info);
+
+ WLockBlock wb(&(chanMgr->channellock));
+
+ wb.on();
+ Channel *ch;
+
+ ch = chanMgr->findChannelByNameID(info);
+ if (ch && ch->thread.active)
+ {
+
+ if (!ch->isPlaying())
+ {
+ if (relay)
+ {
+ ch->info.lastPlayStart = 0; // force reconnect
+ ch->info.lastPlayEnd = 0;
+ }else
+ return false;
+ }
+
+ info = ch->info; // get updated channel info
+
+ return true;
+ }else
+ {
+ if (relay)
+ {
+ wb.off();
+ ch = chanMgr->findAndRelay(info);
+ if (ch)
+ {
+ // \81«Exception point
+ info = ch->info; //get updated channel info
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+// --------------------------------------------------
+int ServMgr::findChannel(ChanInfo &info)
+{
+#if 0
+ char idStr[64];
+ info.id.toStr(idStr);
+
+
+ if (info.id.isSet())
+ {
+ // if we have an ID then try and connect to known hosts carrying channel.
+ ServHost sh = getOutgoingServent(info.id);
+ addOutgoing(sh.host,info.id,true);
+ }
+
+ GnuPacket pack;
+
+ XML xml;
+ XML::Node *n = info.createQueryXML();
+ xml.setRoot(n);
+ pack.initFind(NULL,&xml,servMgr->queryTTL);
+
+ addReplyID(pack.id);
+ int cnt = broadcast(pack,NULL);
+
+ LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt);
+
+ return cnt;
+#endif
+ return 0;
+}
+// --------------------------------------------------
+// add outgoing network connection from string (ip:port format)
+bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri)
+{
+#if 0
+ if (h.ip)
+ {
+ if (!findServent(h.ip,h.port,netid))
+ {
+ Servent *sv = allocServent();
+ if (sv)
+ {
+ if (pri)
+ sv->priorityConnect = true;
+ sv->networkID = netid;
+ sv->initOutgoing(h,Servent::T_OUTGOING);
+ return true;
+ }
+ }
+ }
+#endif
+ return false;
+}
+// --------------------------------------------------
+Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == t)
+ if (sv->remoteID.isSame(sid))
+ return sv;
+ sv=sv->next;
+ }
+ return NULL;
+}
+
+// --------------------------------------------------
+void ServMgr::procConnectArgs(char *str,ChanInfo &info)
+{
+ char arg[MAX_CGI_LEN];
+ char curr[MAX_CGI_LEN];
+
+ char *args = strstr(str,"?");
+ if (args)
+ *args++=0;
+
+ info.initNameID(str);
+
+ if (args)
+ {
+
+ while (args=nextCGIarg(args,curr,arg))
+ {
+ LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
+
+ if (strcmp(curr,"sip")==0)
+ // sip - add network connection to client with channel
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ if (addOutgoing(h,servMgr->networkID,true))
+ LOG_NETWORK("Added connection: %s",arg);
+
+ }else if (strcmp(curr,"pip")==0)
+ // pip - add private network connection to client with channel
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ if (addOutgoing(h,info.id,true))
+ LOG_NETWORK("Added private connection: %s",arg);
+ }else if (strcmp(curr,"ip")==0)
+ // ip - add hit
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ ChanHit hit;
+ hit.init();
+ hit.host = h;
+ hit.rhost[0] = h;
+ hit.rhost[1].init();
+ hit.chanID = info.id;
+ hit.recv = true;
+
+ chanMgr->addHit(hit);
+ }else if (strcmp(curr,"tip")==0)
+ // tip - add tracker hit
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ chanMgr->hitlistlock.on();
+ chanMgr->addHit(h,info.id,true);
+ chanMgr->hitlistlock.off();
+
+ }
+
+
+ }
+ }
+}
+
+// --------------------------------------------------
+bool ServMgr::start()
+{
+ char idStr[64];
+
+
+ const char *priv;
+#if PRIVATE_BROADCASTER
+ priv = "(private)";
+#else
+ priv = "";
+#endif
+#ifdef VERSION_EX
+ LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv);
+#else
+ LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv);
+#endif
+
+ sessionID.toStr(idStr);
+ LOG_DEBUG("SessionID: %s",idStr);
+
+ chanMgr->broadcastID.toStr(idStr);
+ LOG_DEBUG("BroadcastID: %s",idStr);
+ checkForceIP();
+
+
+ serverThread.func = ServMgr::serverProc;
+ if (!sys->startThread(&serverThread))
+ return false;
+
+ idleThread.func = ServMgr::idleProc;
+ if (!sys->startThread(&idleThread))
+ return false;
+
+ return true;
+}
+// --------------------------------------------------
+int ServMgr::clientProc(ThreadInfo *thread)
+{
+#if 0
+ thread->lock();
+
+ GnuID netID;
+ netID = servMgr->networkID;
+
+ while(thread->active)
+ {
+ if (servMgr->autoConnect)
+ {
+ if (servMgr->needConnections() || servMgr->forceLookup)
+ {
+ if (servMgr->needHosts() || servMgr->forceLookup)
+ {
+ // do lookup to find some hosts
+
+ Host lh;
+ lh.fromStrName(servMgr->connectHost,DEFAULT_PORT);
+
+
+ if (!servMgr->findServent(lh.ip,lh.port,netID))
+ {
+ Servent *sv = servMgr->allocServent();
+ if (sv)
+ {
+ LOG_DEBUG("Lookup: %s",servMgr->connectHost);
+ sv->networkID = netID;
+ sv->initOutgoing(lh,Servent::T_LOOKUP);
+ servMgr->forceLookup = false;
+ }
+ }
+ }
+
+ for(int i=0; i<MAX_TRYOUT; i++)
+ {
+ if (servMgr->outUsedFull())
+ break;
+ if (servMgr->tryFull())
+ break;
+
+
+ ServHost sh = servMgr->getOutgoingServent(netID);
+
+ if (!servMgr->addOutgoing(sh.host,netID,false))
+ servMgr->deadHost(sh.host,ServHost::T_SERVENT);
+ sys->sleep(servMgr->tryoutDelay);
+ break;
+ }
+ }
+ }else{
+#if 0
+ Servent *s = servMgr->servents;
+ while (s)
+ {
+
+ if (s->type == Servent::T_OUTGOING)
+ s->thread.active = false;
+ s=s->next;
+ }
+#endif
+ }
+ sys->sleepIdle();
+ }
+ thread->unlock();
+#endif
+ return 0;
+}
+// -----------------------------------
+bool ServMgr::acceptGIV(ClientSocket *sock)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->type == Servent::T_COUT)
+ {
+ if (sv->acceptGIV(sock))
+ return true;
+ }
+ sv=sv->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type)
+{
+ ChanPacket pack;
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream atom(pmem);
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeParent(PCP_PUSH,3);
+ atom.writeInt(PCP_PUSH_IP,to.ip);
+ atom.writeShort(PCP_PUSH_PORT,to.port);
+ atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16);
+
+
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+
+ GnuID noID;
+ noID.clear();
+
+ return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type);
+}
+
+// --------------------------------------------------
+void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate)
+{
+ atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0));
+ atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval);
+ atom.writeString(PCP_ROOT_URL,"download.php");
+ atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION);
+ atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval);
+ atom.writeString(PCP_MESG_ASCII,rootMsg.cstr());
+ if (getUpdate)
+ atom.writeParent(PCP_ROOT_UPDATE,0);
+
+}
+// --------------------------------------------------
+void ServMgr::broadcastRootSettings(bool getUpdate)
+{
+ if (isRoot)
+ {
+
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,7);
+#else
+ atom.writeParent(PCP_BCST,9);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeBytes(PCP_BCST_FROM,sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ writeRootAtoms(atom,getUpdate);
+
+ mem.len = mem.pos;
+ mem.rewind();
+ pack.len = mem.len;
+
+ GnuID noID;
+ noID.clear();
+
+ broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN);
+ }
+}
+// --------------------------------------------------
+int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type)
+{
+ int cnt=0;
+
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->sendPacket(pack,chanID,srcID,destID,type))
+ cnt++;
+ sv=sv->next;
+ }
+ return cnt;
+}
+
+// --------------------------------------------------
+int ServMgr::idleProc(ThreadInfo *thread)
+{
+
+// thread->lock();
+
+ unsigned int lastPasvFind=0;
+ unsigned int lastBroadcast=0;
+
+
+ // nothing much to do for the first couple of seconds, so just hang around.
+ sys->sleep(2000);
+
+ unsigned int lastBWcheck=0;
+ unsigned int bytesIn=0,bytesOut=0;
+
+ unsigned int lastBroadcastConnect = 0;
+ unsigned int lastRootBroadcast = 0;
+
+ unsigned int lastForceIPCheck = 0;
+
+ while(thread->active)
+ {
+ stats.update();
+
+
+
+ unsigned int ctime = sys->getTime();
+
+
+ if (!servMgr->forceIP.isEmpty())
+ {
+ if ((ctime-lastForceIPCheck) > 60)
+ {
+ if (servMgr->checkForceIP())
+ {
+ GnuID noID;
+ noID.clear();
+ chanMgr->broadcastTrackerUpdate(noID,true);
+ }
+ lastForceIPCheck = ctime;
+ }
+ }
+
+
+ if (chanMgr->isBroadcasting())
+ {
+ if ((ctime-lastBroadcastConnect) > 30)
+ {
+ servMgr->connectBroadcaster();
+ lastBroadcastConnect = ctime;
+ }
+ }
+
+ if (servMgr->isRoot)
+ {
+ if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60))
+ {
+ peercastInst->saveSettings();
+ sys->exit();
+ }
+
+ if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval)
+ {
+ servMgr->broadcastRootSettings(true);
+ lastRootBroadcast = ctime;
+ }
+ }
+
+
+ // clear dead hits
+ chanMgr->clearDeadHits(true);
+
+ if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX
+ {
+ servMgr->banFirewalledHost();
+ }
+
+ if (servMgr->shutdownTimer)
+ {
+ if (--servMgr->shutdownTimer <= 0)
+ {
+ peercastInst->saveSettings();
+ sys->exit();
+ }
+ }
+
+ // shutdown idle channels
+ if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS)
+ chanMgr->closeOldestIdle();
+
+
+ sys->sleep(500);
+ }
+
+ sys->endThread(thread);
+// thread->unlock();
+ return 0;
+}
+
+// --------------------------------------------------
+int ServMgr::serverProc(ThreadInfo *thread)
+{
+
+// thread->lock();
+
+ Servent *serv = servMgr->allocServent();
+ Servent *serv2 = servMgr->allocServent();
+
+ unsigned int lastLookupTime=0;
+
+
+ while (thread->active)
+ {
+
+ if (servMgr->restartServer)
+ {
+ serv->abort(); // force close
+ serv2->abort(); // force close
+ servMgr->quit();
+
+ servMgr->restartServer = false;
+ }
+
+ if (servMgr->autoServe)
+ {
+ serv->allow = servMgr->allowServer1;
+ serv2->allow = servMgr->allowServer2;
+
+
+ if ((!serv->sock) || (!serv2->sock))
+ {
+ LOG_DEBUG("Starting servers");
+// servMgr->forceLookup = true;
+
+ //if (servMgr->serverHost.ip != 0)
+ {
+
+ if (servMgr->forceNormal)
+ servMgr->setFirewall(ServMgr::FW_OFF);
+ else
+ servMgr->setFirewall(ServMgr::FW_UNKNOWN);
+
+ Host h = servMgr->serverHost;
+
+ if (!serv->sock)
+ serv->initServer(h);
+
+ h.port++;
+ if (!serv2->sock)
+ serv2->initServer(h);
+
+
+ }
+ }
+ }else{
+ // stop server
+ serv->abort(); // force close
+ serv2->abort(); // force close
+
+ // cancel incoming connectuions
+ Servent *s = servMgr->servents;
+ while (s)
+ {
+ if (s->type == Servent::T_INCOMING)
+ s->thread.active = false;
+ s=s->next;
+ }
+
+ servMgr->setFirewall(ServMgr::FW_ON);
+ }
+
+ sys->sleepIdle();
+
+ }
+
+ sys->endThread(thread);
+// thread->unlock();
+ return 0;
+}
+
+// -----------------------------------
+void ServMgr::setMaxRelays(int max)
+{
+ if (max < MIN_RELAYS)
+ max = MIN_RELAYS;
+ maxRelays = max;
+}
+
+// -----------------------------------
+XML::Node *ServMgr::createServentXML()
+{
+
+ return new XML::Node("servent agent=\"%s\" ",PCX_AGENT);
+}
+
+// --------------------------------------------------
+const char *ServHost::getTypeStr(TYPE t)
+{
+ switch(t)
+ {
+ case T_NONE: return "NONE";
+ case T_STREAM: return "STREAM";
+ case T_CHANNEL: return "CHANNEL";
+ case T_SERVENT: return "SERVENT";
+ case T_TRACKER: return "TRACKER";
+ }
+ return "UNKNOWN";
+}
+// --------------------------------------------------
+ServHost::TYPE ServHost::getTypeFromStr(const char *s)
+{
+ if (stricmp(s,"NONE")==0)
+ return T_NONE;
+ else if (stricmp(s,"SERVENT")==0)
+ return T_SERVENT;
+ else if (stricmp(s,"STREAM")==0)
+ return T_STREAM;
+ else if (stricmp(s,"CHANNEL")==0)
+ return T_CHANNEL;
+ else if (stricmp(s,"TRACKER")==0)
+ return T_TRACKER;
+
+ return T_NONE;
+}
+
+
+// --------------------------------------------------
+bool ServFilter::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "network")
+ strcpy(buf,(flags & F_NETWORK)?"1":"0");
+ else if (var == "private")
+ strcpy(buf,(flags & F_PRIVATE)?"1":"0");
+ else if (var == "direct")
+ strcpy(buf,(flags & F_DIRECT)?"1":"0");
+ else if (var == "banned")
+ strcpy(buf,(flags & F_BAN)?"1":"0");
+ else if (var == "ip")
+ host.IPtoStr(buf);
+ else
+ return false;
+
+
+ out.writeString(buf);
+ return true;
+}
+// --------------------------------------------------
+bool BCID::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "id")
+ id.toStr(buf);
+ else if (var == "name")
+ strcpy(buf,name.cstr());
+ else if (var == "email")
+ strcpy(buf,email.cstr());
+ else if (var == "url")
+ strcpy(buf,url.cstr());
+ else if (var == "valid")
+ strcpy(buf,valid?"Yes":"No");
+ else
+ return false;
+
+
+ out.writeString(buf);
+ return true;
+}
+
+
+// --------------------------------------------------
+bool ServMgr::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+ String str;
+
+ if (var == "version")
+#ifdef VERSION_EX
+ strcpy(buf,PCX_VERSTRING_EX);
+#else
+ strcpy(buf,PCX_VERSTRING);
+#endif
+ else if (var == "uptime")
+ {
+ str.setFromStopwatch(getUptime());
+ str.convertTo(String::T_HTML);
+ strcpy(buf,str.cstr());
+ }else if (var == "numRelays")
+ sprintf(buf,"%d",numStreams(Servent::T_RELAY,true));
+ else if (var == "numDirect")
+ sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true));
+ else if (var == "totalConnected")
+ sprintf(buf,"%d",totalConnected());
+ else if (var == "numServHosts")
+ sprintf(buf,"%d",numHosts(ServHost::T_SERVENT));
+ else if (var == "numServents")
+ sprintf(buf,"%d",numServents());
+ else if (var == "serverPort")
+ sprintf(buf,"%d",serverHost.port);
+ else if (var == "serverIP")
+ serverHost.IPtoStr(buf);
+ else if (var == "ypAddress")
+ strcpy(buf,rootHost.cstr());
+ else if (var == "password")
+ strcpy(buf,password);
+ else if (var == "isFirewalled")
+ sprintf(buf,"%d",getFirewall()==FW_ON?1:0);
+ else if (var == "firewallKnown")
+ sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1);
+ else if (var == "rootMsg")
+ strcpy(buf,rootMsg);
+ else if (var == "isRoot")
+ sprintf(buf,"%d",isRoot?1:0);
+ else if (var == "isPrivate")
+ sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0);
+ else if (var == "forceYP")
+ sprintf(buf,"%d",PCP_FORCE_YP?1:0);
+ else if (var == "refreshHTML")
+ sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff);
+ else if (var == "maxRelays")
+ sprintf(buf,"%d",maxRelays);
+ else if (var == "maxDirect")
+ sprintf(buf,"%d",maxDirect);
+ else if (var == "maxBitrateOut")
+ sprintf(buf,"%d",maxBitrateOut);
+ else if (var == "maxControlsIn")
+ sprintf(buf,"%d",maxControl);
+ else if (var == "numFilters")
+ sprintf(buf,"%d",numFilters+1);
+ else if (var == "maxPGNUIn")
+ sprintf(buf,"%d",maxGnuIncoming);
+ else if (var == "minPGNUIn")
+ sprintf(buf,"%d",minGnuIncoming);
+ else if (var == "numActive1")
+ sprintf(buf,"%d",numActiveOnPort(serverHost.port));
+ else if (var == "numActive2")
+ sprintf(buf,"%d",numActiveOnPort(serverHost.port+1));
+ else if (var == "numPGNU")
+ sprintf(buf,"%d",numConnected(Servent::T_PGNU));
+ else if (var == "numCIN")
+ sprintf(buf,"%d",numConnected(Servent::T_CIN));
+ else if (var == "numCOUT")
+ sprintf(buf,"%d",numConnected(Servent::T_COUT));
+ else if (var == "numIncoming")
+ sprintf(buf,"%d",numActive(Servent::T_INCOMING));
+ else if (var == "numValidBCID")
+ {
+ int cnt = 0;
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ cnt++;
+ bcid=bcid->next;
+ }
+ sprintf(buf,"%d",cnt);
+ }
+
+ else if (var == "disabled")
+ sprintf(buf,"%d",isDisabled);
+
+ // JP-EX
+ else if (var.startsWith("autoRelayKeep")) {
+ if (var == "autoRelayKeep.0")
+ strcpy(buf, (autoRelayKeep == 0) ? "1":"0");
+ else if (var == "autoRelayKeep.1")
+ strcpy(buf, (autoRelayKeep == 1) ? "1":"0");
+ else if (var == "autoRelayKeep.2")
+ strcpy(buf, (autoRelayKeep == 2) ? "1":"0");
+ } else if (var == "autoMaxRelaySetting")
+ sprintf(buf,"%d",autoMaxRelaySetting);
+ else if (var == "autoBumpSkipCount")
+ sprintf(buf,"%d",autoBumpSkipCount);
+ else if (var == "kickPushStartRelays")
+ sprintf(buf,"%d",kickPushStartRelays);
+ else if (var == "kickPushInterval")
+ sprintf(buf,"%d",kickPushInterval);
+ else if (var == "allowConnectPCST")
+ strcpy(buf, (allowConnectPCST == 1) ? "1":"0");
+ else if (var == "enableGetName")
+ strcpy(buf, (enableGetName == 1)? "1":"0");
+
+ // VP-EX
+ else if (var == "ypAddress2")
+ strcpy(buf,rootHost2.cstr());
+ else if (var.startsWith("autoPort0Kick")) {
+ if (var == "autoPort0Kick.0")
+ strcpy(buf, (autoPort0Kick == 0) ? "1":"0");
+ else if (var == "autoPort0Kick.1")
+ strcpy(buf, (autoPort0Kick == 1) ? "1":"0");
+ }
+ else if (var.startsWith("allowOnlyVP")) {
+ if (var == "allowOnlyVP.0")
+ strcpy(buf, (allowOnlyVP == 0) ? "1":"0");
+ else if (var == "allowOnlyVP.1")
+ strcpy(buf, (allowOnlyVP == 1) ? "1":"0");
+ }
+ else if (var == "kickKeepTime")
+ sprintf(buf, "%d",kickKeepTime);
+
+ else if (var == "serverPort1")
+ sprintf(buf,"%d",serverHost.port);
+ else if (var == "serverLocalIP")
+ {
+ Host lh(ClientSocket::getIP(NULL),0);
+ char ipStr[64];
+ lh.IPtoStr(ipStr);
+ strcpy(buf,ipStr);
+ }else if (var == "upgradeURL")
+ strcpy(buf,servMgr->downloadURL);
+ else if (var == "serverPort2")
+ sprintf(buf,"%d",serverHost.port+1);
+ else if (var.startsWith("allow."))
+ {
+ if (var == "allow.HTML1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0");
+ else if (var == "allow.HTML2")
+ strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0");
+ else if (var == "allow.broadcasting1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0");
+ else if (var == "allow.broadcasting2")
+ strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0");
+ else if (var == "allow.network1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0");
+ else if (var == "allow.direct1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0");
+ }else if (var.startsWith("auth."))
+ {
+ if (var == "auth.useCookies")
+ strcpy(buf,(authType==AUTH_COOKIE)?"1":"0");
+ else if (var == "auth.useHTTP")
+ strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0");
+ else if (var == "auth.useSessionCookies")
+ strcpy(buf,(cookieList.neverExpire==false)?"1":"0");
+
+ }else if (var.startsWith("log."))
+ {
+ if (var == "log.debug")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_DEBUG))?"1":"0");
+ else if (var == "log.errors")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_ERROR))?"1":"0");
+ else if (var == "log.gnet")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_NETWORK))?"1":"0");
+ else if (var == "log.channel")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_CHANNEL))?"1":"0");
+ else
+ return false;
+ }else if (var == "test")
+ {
+ out.writeUTF8(0x304b);
+ out.writeUTF8(0x304d);
+ out.writeUTF8(0x304f);
+ out.writeUTF8(0x3051);
+ out.writeUTF8(0x3053);
+
+ out.writeUTF8(0x0041);
+ out.writeUTF8(0x0042);
+ out.writeUTF8(0x0043);
+ out.writeUTF8(0x0044);
+
+ out.writeChar('a');
+ out.writeChar('b');
+ out.writeChar('c');
+ out.writeChar('d');
+ return true;
+
+ }else if (var == "maxRelaysIndexTxt") // for PCRaw (relay)
+ sprintf(buf, "%d", maxRelaysIndexTxt);
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+// --------------------------------------------------
+//JP-EX
+bool ServMgr::isCheckPushStream()
+{
+ if (servMgr->kickPushStartRelays)
+ if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1))
+ return true;
+
+ return false;
+}
+// --------------------------------------------------
+//JP-EX
+void ServMgr::banFirewalledHost()
+{
+ unsigned int kickpushtime = sys->getTime();
+ if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval)
+ {
+ servMgr->kickPushTime = kickpushtime;
+ Servent *s = servMgr->servents;
+ LOG_DEBUG("Servent scan start.");
+ while (s)
+ {
+ if (s->type != Servent::T_NONE)
+ {
+ Host h = s->getHost();
+ int ip = h.ip;
+ int port = h.port;
+ Host h2(ip,port);
+ unsigned int tnum = 0;
+
+ if (s->lastConnect)
+ tnum = sys->getTime() - s->lastConnect;
+ if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval))
+ {
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+
+ bool isfw = false;
+ int numRelay = 0;
+ if (numHits)
+ {
+ for(int k=0; k<numHits; k++)
+ {
+ ChanHitList *chl = hits[k];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++ )
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h2.ip == hit->host.ip))
+ {
+ if (hit->firewalled)
+ isfw = true;
+ numRelay = hit->numRelays;
+ }
+ }
+ }
+ }
+ }
+ if ((isfw==true) && (numRelay==0))
+ {
+ char hostName[256];
+ h2.toStr(hostName);
+ if (servMgr->isCheckPushStream())
+ {
+ s->thread.active = false;
+ LOG_ERROR("Stop firewalled Servent : %s",hostName);
+ }
+ }*/
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = chanMgr->findHitListByID(s->chanID);
+ if (chl){
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/)
+ {
+ char hostName[256];
+ h2.toStr(hostName);
+ if (servMgr->isCheckPushStream())
+ {
+ s->thread.active = false;
+ LOG_ERROR("Stop firewalled Servent : %s",hostName);
+ }
+ }
+ hit = hit->next;
+ }
+
+ }
+ chanMgr->hitlistlock.off();
+
+
+ }
+ }
+ s=s->next;
+ }
+ LOG_DEBUG("Servent scan finished.");
+ }
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : servmgr.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SERVMGR_H
+#define _SERVMGR_H
+
+#include "servent.h"
+
+// ----------------------------------
+
+const int MIN_YP_RETRY = 20;
+const int MIN_TRACKER_RETRY = 10;
+const int MIN_RELAY_RETRY = 5;
+
+// ----------------------------------
+class BCID
+{
+public:
+ BCID()
+ :next(0),valid(true)
+ {}
+
+ bool writeVariable(Stream &, const String &);
+
+ GnuID id;
+ String name,email,url;
+ bool valid;
+ BCID *next;
+};
+
+
+// ----------------------------------
+class ServHost
+{
+public:
+ enum TYPE
+ {
+ T_NONE,
+ T_STREAM,
+ T_CHANNEL,
+ T_SERVENT,
+ T_TRACKER
+ };
+
+ ServHost() {init();}
+ void init()
+ {
+ host.init();
+ time = 0;
+ type = T_NONE;
+ }
+ void init(Host &h, TYPE tp, unsigned int tim)
+ {
+ init();
+ host = h;
+ type = tp;
+ if (tim)
+ time = tim;
+ else
+ time = sys->getTime();
+ }
+
+ static const char *getTypeStr(TYPE);
+ static TYPE getTypeFromStr(const char *);
+
+ TYPE type;
+ Host host;
+ unsigned int time;
+};
+// ----------------------------------
+class ServFilter
+{
+public:
+ enum
+ {
+ F_PRIVATE = 0x01,
+ F_BAN = 0x02,
+ F_NETWORK = 0x04,
+ F_DIRECT = 0x08
+ };
+
+ ServFilter() {init();}
+ void init()
+ {
+ flags = 0;
+ host.init();
+ }
+
+ bool writeVariable(Stream &, const String &);
+
+ Host host;
+ unsigned int flags;
+};
+
+// ----------------------------------
+// ServMgr keeps track of Servents
+class ServMgr
+{
+
+
+
+public:
+
+ enum NOTIFY_TYPE
+ {
+ NT_UPGRADE = 0x0001,
+ NT_PEERCAST = 0x0002,
+ NT_BROADCASTERS = 0x0004,
+ NT_TRACKINFO = 0x0008
+ };
+
+ enum FW_STATE
+ {
+ FW_OFF,
+ FW_ON,
+ FW_UNKNOWN
+ };
+ enum {
+
+ MAX_HOSTCACHE = 100, // max. amount of hosts in cache
+ MIN_HOSTS = 3, // min. amount of hosts that should be kept in cache
+
+ MAX_OUTGOING = 3, // max. number of outgoing servents to use
+ MAX_INCOMING = 6, // max. number of public incoming servents to use
+ MAX_TRYOUT = 10, // max. number of outgoing servents to try connect
+ MIN_CONNECTED = 3, // min. amount of connected hosts that should be kept
+
+ MIN_RELAYS = 1,
+
+ MAX_FILTERS = 50,
+
+ MAX_VERSIONS = 16,
+
+ MAX_PREVIEWTIME = 300, // max. seconds preview per channel available (direct connections)
+ MAX_PREVIEWWAIT = 300, // max. seconds wait between previews
+
+ };
+
+ enum AUTH_TYPE
+ {
+ AUTH_COOKIE,
+ AUTH_HTTPBASIC
+ };
+
+
+
+ ServMgr();
+
+ bool start();
+
+ Servent *findServent(unsigned int,unsigned short,GnuID &);
+ Servent *findServent(Servent::TYPE);
+ Servent *findServent(Servent::TYPE,Host &,GnuID &);
+ Servent *findOldestServent(Servent::TYPE,bool);
+ Servent *findServentByIndex(int);
+ Servent *findServentByServentID(int);
+
+ bool writeVariable(Stream &, const String &);
+ Servent *allocServent();
+ unsigned int numUsed(int);
+ unsigned int numStreams(GnuID &, Servent::TYPE,bool);
+ unsigned int numStreams(Servent::TYPE,bool);
+ unsigned int numConnected(int,bool,unsigned int);
+ unsigned int numConnected(int t,int tim = 0)
+ {
+ return numConnected(t,false,tim)+numConnected(t,true,tim);
+ }
+ unsigned int numConnected();
+ unsigned int numServents();
+
+ unsigned int totalConnected()
+ {
+ //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING);
+ return numConnected();
+ }
+ unsigned int numOutgoing();
+ bool isFiltered(int,Host &h);
+ bool addOutgoing(Host,GnuID &,bool);
+ Servent *findConnection(Servent::TYPE,GnuID &);
+
+
+ static THREAD_PROC serverProc(ThreadInfo *);
+ static THREAD_PROC clientProc(ThreadInfo *);
+ static THREAD_PROC trackerProc(ThreadInfo *);
+ static THREAD_PROC idleProc(ThreadInfo *);
+
+ int broadcast(GnuPacket &,Servent * = NULL);
+ int route(GnuPacket &, GnuID &, Servent * = NULL);
+
+ XML::Node *createServentXML();
+
+ void connectBroadcaster();
+ void procConnectArgs(char *,ChanInfo &);
+
+ void quit();
+ void closeConnections(Servent::TYPE);
+
+ void checkFirewall();
+
+ // host cache
+ void addHost(Host &,ServHost::TYPE,unsigned int);
+ int getNewestServents(Host *,int, Host &);
+ ServHost getOutgoingServent(GnuID &);
+ void deadHost(Host &,ServHost::TYPE);
+ unsigned int numHosts(ServHost::TYPE);
+ void clearHostCache(ServHost::TYPE);
+ bool seenHost(Host &,ServHost::TYPE,unsigned int);
+
+ void setMaxRelays(int);
+ void setFirewall(FW_STATE);
+ bool checkForceIP();
+ FW_STATE getFirewall() {return firewalled;}
+ void saveSettings(const char *);
+ void loadSettings(const char *);
+ void setPassiveSearch(unsigned int);
+ int findChannel(ChanInfo &);
+ bool getChannel(char *,ChanInfo &,bool);
+ void setFilterDefaults();
+
+ bool acceptGIV(ClientSocket *);
+ void addVersion(unsigned int);
+
+ void broadcastRootSettings(bool);
+ int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE);
+ void writeRootAtoms(AtomStream &,bool);
+
+ int broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type);
+
+ void addValidBCID(BCID *);
+ void removeValidBCID(GnuID &);
+ BCID *findValidBCID(GnuID &);
+ BCID *findValidBCID(int);
+
+ unsigned int getUptime()
+ {
+ return sys->getTime()-startTime;
+ }
+
+ bool seenPacket(GnuPacket &);
+
+
+ bool needHosts()
+ {
+ return false;
+ //return numHosts(ServHost::T_SERVENT) < maxTryout;
+ }
+
+ unsigned int numActiveOnPort(int);
+ unsigned int numActive(Servent::TYPE);
+
+ bool needConnections()
+ {
+ return numConnected(Servent::T_PGNU,60) < minGnuIncoming;
+ }
+ bool tryFull()
+ {
+ return false;
+ //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false;
+ }
+
+ bool pubInOver()
+ {
+ return numConnected(Servent::T_PGNU) > maxGnuIncoming;
+// return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false;
+ }
+ bool pubInFull()
+ {
+ return numConnected(Servent::T_PGNU) >= maxGnuIncoming;
+// return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false;
+ }
+
+ bool outUsedFull()
+ {
+ return false;
+// return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false;
+ }
+ bool outOver()
+ {
+ return false;
+// return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false;
+ }
+
+ bool controlInFull()
+ {
+ return numConnected(Servent::T_CIN)>=maxControl;
+ }
+
+ bool outFull()
+ {
+ return false;
+// return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false;
+ }
+
+ bool relaysFull()
+ {
+ return numStreams(Servent::T_RELAY,false) >= maxRelays;
+ }
+ bool directFull()
+ {
+ return numStreams(Servent::T_DIRECT,false) >= maxDirect;
+ }
+
+ bool bitrateFull(unsigned int br)
+ {
+ return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut : false;
+ }
+
+ unsigned int totalOutput(bool);
+ unsigned int totalInput(bool);
+
+ static ThreadInfo serverThread,idleThread;
+
+
+ Servent *servents;
+ WLock lock;
+
+ ServHost hostCache[MAX_HOSTCACHE];
+
+ char password[64];
+
+ bool allowGnutella;
+
+ unsigned int maxBitrateOut,maxControl,maxRelays,maxDirect;
+ unsigned int minGnuIncoming,maxGnuIncoming;
+ unsigned int maxServIn;
+
+ bool isDisabled;
+ bool isRoot;
+ int totalStreams;
+
+ Host serverHost;
+ String rootHost;
+ String rootHost2;
+
+ char downloadURL[128];
+ String rootMsg;
+ String forceIP;
+ char connectHost[128];
+ GnuID networkID;
+ unsigned int firewallTimeout;
+ int showLog;
+ int shutdownTimer;
+ bool pauseLog;
+ bool forceNormal;
+ bool useFlowControl;
+ unsigned int lastIncoming;
+
+ bool restartServer;
+ bool allowDirect;
+ bool autoConnect,autoServe,forceLookup;
+ int queryTTL;
+
+ unsigned int allowServer1,allowServer2;
+ unsigned int startTime;
+ unsigned int tryoutDelay;
+ unsigned int refreshHTML;
+ unsigned int relayBroadcast;
+
+ unsigned int notifyMask;
+
+ BCID *validBCID;
+ GnuID sessionID;
+
+ ServFilter filters[MAX_FILTERS];
+ int numFilters;
+
+
+ CookieList cookieList;
+ AUTH_TYPE authType;
+
+ char htmlPath[128];
+ unsigned int clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS];
+ int numVersions;
+
+ int serventNum;
+ String chanLog;
+
+ char modulePath[256]; //JP-EX
+ int enableGetName; //JP-EX
+ int allowConnectPCST; //JP-EX
+ int autoRelayKeep; //JP-EX
+ unsigned int autoMaxRelaySetting; //JP-EX
+ unsigned int autoBumpSkipCount;//JP-EX
+ unsigned int kickPushStartRelays; //JP-EX
+ unsigned int kickPushInterval; //JP-EX
+ unsigned int kickPushTime;
+ bool isCheckPushStream(); //JP-EX
+ void banFirewalledHost(); //JP-EX
+
+ bool getModulePath; //JP-EX
+ bool clearPLS; //JP-EX
+ bool writeLogFile; //JP-EX
+
+ bool autoPort0Kick;
+ bool allowOnlyVP;
+ unsigned int kickKeepTime;
+ bool vpDebug;
+ bool saveIniChannel;
+ bool saveGuiPos;
+ bool keepDownstreams;
+
+ int maxRelaysIndexTxt; // for PCRaw (relay)
+
+private:
+ FW_STATE firewalled;
+};
+
+// ----------------------------------
+extern ServMgr *servMgr;
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : socket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// ClientSocket is a generic socket interface, Non OS/HW dependant.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdio.h>
+#include <string.h>
+#include "socket.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
--- /dev/null
+// ------------------------------------------------
+// File : socket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+
+#include "common.h"
+#include "stream.h"
+
+//#define DISABLE_NAGLE 1
+
+class SocketBuffer {
+
+public:
+ SocketBuffer(const void *p, int l){
+ buf = ::new char[l];
+ len = l;
+ pos = 0;
+ next = NULL;
+ ctime = sys->getTime();
+ memcpy((void*)buf, p, l);
+ }
+
+ ~SocketBuffer(){
+ if (buf){
+ ::delete [] buf;
+ }
+ }
+ char *buf;
+ int len;
+ int pos;
+ unsigned int ctime;
+ SocketBuffer *next;
+};
+
+class SocketBufferList {
+
+public:
+ SocketBufferList(){
+ top = NULL;
+ last = NULL;
+ skipCount = 0;
+ lastSkipTime = 0;
+ }
+
+ bool isNull(){ return (top == NULL); }
+ void add(const void *p, int l){
+ SocketBuffer *tmp = new SocketBuffer(p,l);
+
+ if (!last){
+ top = tmp;
+ last = tmp;
+ } else {
+ last->next = tmp;
+ last = tmp;
+ }
+
+// LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last);
+ }
+
+ SocketBuffer *getTop(){
+ unsigned int ctime = sys->getTime();
+
+ while(top){
+ if (top && (top->ctime + 10 >= ctime)){
+ break;
+ } else {
+// LOG_DEBUG("over 10sec(data skip)");
+ skipCount++;
+ lastSkipTime = sys->getTime();
+ deleteTop();
+ }
+ }
+ return top;
+ }
+
+ void deleteTop(){
+// LOG_DEBUG("oldtop = %d", top);
+ SocketBuffer *tmp = top;
+ top = tmp->next;
+ delete tmp;
+ if (!top){
+ last = NULL;
+ }
+
+// LOG_DEBUG("newtop = %d",top);
+ }
+
+ void clear(){
+ while(top){
+ SocketBuffer *tmp = top;
+ top = tmp->next;
+ delete tmp;
+ }
+ top = NULL;
+ last = NULL;
+ }
+
+ SocketBuffer *top;
+ SocketBuffer *last;
+ unsigned int skipCount;
+ unsigned int lastSkipTime;
+
+};
+
+// --------------------------------------------------
+class ClientSocket : public Stream
+{
+public:
+
+ ClientSocket()
+ {
+ readTimeout = 30000;
+ writeTimeout = 30000;
+#ifdef WIN32
+ skipCount = 0;
+ lastSkipTime = 0;
+#endif
+ }
+
+ ~ClientSocket(){
+#ifdef WIN32
+ bufList.clear();
+#endif
+ }
+
+ // required interface
+ virtual void open(Host &) = 0;
+ virtual void bind(Host &) = 0;
+ virtual void connect() = 0;
+ virtual bool active() = 0;
+ virtual ClientSocket *accept() = 0;
+ virtual Host getLocalHost() = 0;
+
+ virtual void setReadTimeout(unsigned int t)
+ {
+ readTimeout = t;
+ }
+ virtual void setWriteTimeout(unsigned int t)
+ {
+ writeTimeout = t;
+ }
+ virtual void setBlocking(bool) {}
+
+
+ static unsigned int getIP(char *);
+ static bool getHostname(char *,unsigned int);
+
+ virtual bool eof()
+ {
+ return active()==false;
+ }
+
+ Host host;
+
+#ifdef WIN32
+ SocketBufferList bufList;
+ virtual void bufferingWrite(const void *, int) = 0;
+ unsigned int skipCount;
+ unsigned int lastSkipTime;
+#endif
+
+ unsigned int readTimeout,writeTimeout;
+
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : stats.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Statistic logging
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stats.h"
+#include "common.h"
+#include "sys.h"
+#include "stream.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+Stats stats;
+// ------------------------------------
+void Stats::clear()
+{
+ for(int i=0; i<Stats::MAX; i++)
+ {
+ current[i] = 0;
+ last[i] = 0;
+ perSec[i] = 0;
+ }
+ lastUpdate = 0;
+}
+// ------------------------------------
+void Stats::update()
+{
+ unsigned int ctime = sys->getTime();
+
+ unsigned int diff = ctime - lastUpdate;
+ if (diff >= /* 5 */ 1)
+ {
+
+ for(int i=0; i<Stats::MAX; i++)
+ {
+ perSec[i] = (current[i]-last[i])/diff;
+ last[i] = current[i];
+ }
+
+ lastUpdate = ctime;
+ }
+
+}
+// ------------------------------------
+bool Stats::writeVariable(Stream &out,const String &var)
+{
+ char buf[1024];
+
+ if (var == "totalInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)));
+ else if (var == "totalOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)));
+ else if (var == "totalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)+getPerSecond(Stats::BYTESOUT)));
+ else if (var == "wanInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN)));
+ else if (var == "wanOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT)));
+ else if (var == "wanTotalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS((getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN))+(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT))));
+ else if (var == "netInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAIN)));
+ else if (var == "netOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)));
+ else if (var == "netTotalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)+getPerSecond(Stats::PACKETDATAIN)));
+ else if (var == "packInPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSIN));
+ else if (var == "packOutPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT));
+ else if (var == "packTotalPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT)+getPerSecond(Stats::NUMPACKETSIN));
+
+ else
+ return false;
+
+ out.writeString(buf);
+
+ return true;
+}
+
+
+
--- /dev/null
+// ------------------------------------------------
+// File : stats.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STATS_H
+#define _STATS_H
+
+// ------------------------------------------------------
+class Stats
+{
+public:
+
+ void clear();
+ void update();
+
+ enum STAT
+ {
+ NONE,
+
+ PACKETSSTART,
+ NUMQUERYIN,NUMQUERYOUT,
+ NUMPINGIN,NUMPINGOUT,
+ NUMPONGIN,NUMPONGOUT,
+ NUMPUSHIN,NUMPUSHOUT,
+ NUMHITIN,NUMHITOUT,
+ NUMOTHERIN,NUMOTHEROUT,
+ NUMDROPPED,
+ NUMDUP,
+ NUMACCEPTED,
+ NUMOLD,
+ NUMBAD,
+ NUMHOPS1,NUMHOPS2,NUMHOPS3,NUMHOPS4,NUMHOPS5,NUMHOPS6,NUMHOPS7,NUMHOPS8,NUMHOPS9,NUMHOPS10,
+ NUMPACKETSIN,
+ NUMPACKETSOUT,
+ NUMROUTED,
+ NUMBROADCASTED,
+ NUMDISCARDED,
+ NUMDEAD,
+ PACKETDATAIN,
+ PACKETDATAOUT,
+ PACKETSEND,
+
+
+ BYTESIN,
+ BYTESOUT,
+ LOCALBYTESIN,
+ LOCALBYTESOUT,
+
+ MAX
+ };
+
+ bool writeVariable(class Stream &,const class String &);
+
+ void clearRange(STAT s, STAT e)
+ {
+ for(int i=s; i<=e; i++)
+ current[i] = 0;
+ }
+ void clear(STAT s) {current[s]=0;}
+ void add(STAT s,int n=1) {current[s]+=n;}
+ unsigned int getPerSecond(STAT s) {return perSec[s];}
+ unsigned int getCurrent(STAT s) {return current[s];}
+
+ unsigned int current[Stats::MAX],last[Stats::MAX],perSec[Stats::MAX];
+ unsigned int lastUpdate;
+};
+
+extern Stats stats;
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : stream.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Basic stream handling functions.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stream.h"
+#include "common.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void MemoryStream::convertFromBase64()
+{
+ char *out = buf;
+ char *in = buf;
+
+ int rl=len;
+ while(rl >= 4)
+ {
+ out += String::base64WordToChars(out,in);
+ in += 4;
+ rl -= 4;
+ }
+ *out = 0;
+ len = out-buf;
+}
+// -------------------------------------
+void FileStream::openReadOnly(const char *fn)
+{
+ file = fopen(fn,"rb");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteReplace(const char *fn)
+{
+ file = fopen(fn,"wb");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteAppend(const char *fn)
+{
+ file = fopen(fn,"ab");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+
+// -------------------------------------
+void FileStream::close()
+{
+ if (file)
+ {
+ fclose(file);
+ file = NULL;
+ }
+}
+// -------------------------------------
+void FileStream::rewind()
+{
+ if (file)
+ fseek(file,0,SEEK_SET);
+}
+// -------------------------------------
+int FileStream::length()
+{
+ int len = 0;
+ if (file)
+ {
+ int old = ftell(file);
+ fseek(file,0,SEEK_END);
+ len = ftell(file);
+ fseek(file,old,SEEK_SET);
+
+ }
+ return len;
+}
+
+// -------------------------------------
+bool FileStream::eof()
+{
+ if (file)
+ return (feof(file)!=0);
+ else
+ return true;
+}
+// -------------------------------------
+int FileStream::read(void *ptr, int len)
+{
+ if (!file)
+ return 0;
+ if (feof(file))
+ throw StreamException("End of file");
+
+ int r = (int)fread(ptr,1,len,file);
+
+ updateTotals(r, 0);
+ return r;
+}
+
+// -------------------------------------
+void FileStream::write(const void *ptr, int len)
+{
+ if (!file)
+ return;
+ fwrite(ptr,1,len,file);
+ updateTotals(0, len);
+
+}
+// -------------------------------------
+void FileStream::flush()
+{
+ if (!file)
+ return;
+ fflush(file);
+}
+// -------------------------------------
+int FileStream::pos()
+{
+ if (!file)
+ return 0;
+ return ftell(file);
+}
+
+// -------------------------------------
+void FileStream::seekTo(int pos)
+{
+ if (!file)
+ return;
+ fseek(file,pos,SEEK_SET);
+}
+
+// -------------------------------------
+void Stream::writeTo(Stream &out, int len)
+{
+ char tmp[4096];
+ while (len)
+ {
+ int rlen = sizeof(tmp);
+ if (rlen > len)
+ rlen = len;
+
+ read(tmp,rlen);
+ out.write(tmp,rlen);
+
+ len-=rlen;
+ }
+}
+// -------------------------------------
+int Stream::writeUTF8(unsigned int code)
+{
+ if (code < 0x80)
+ {
+ writeChar(code);
+ return 1;
+ }else
+ if (code < 0x0800)
+ {
+ writeChar(code>>6 | 0xC0);
+ writeChar(code & 0x3F | 0x80);
+ return 2;
+ }else if (code < 0x10000)
+ {
+ writeChar(code>>12 | 0xE0);
+ writeChar(code>>6 & 0x3F | 0x80);
+ writeChar(code & 0x3F | 0x80);
+ return 3;
+ }else
+ {
+ writeChar(code>>18 | 0xF0);
+ writeChar(code>>12 & 0x3F | 0x80);
+ writeChar(code>>6 & 0x3F | 0x80);
+ writeChar(code & 0x3F | 0x80);
+ return 4;
+ }
+
+}
+
+// -------------------------------------
+void Stream::skip(int len)
+{
+ char tmp[4096];
+ while (len)
+ {
+ int rlen = sizeof(tmp);
+ if (rlen > len)
+ rlen = len;
+ read(tmp,rlen);
+ len-=rlen;
+ }
+
+}
+
+
+// -------------------------------------
+void Stream::updateTotals(unsigned int in, unsigned int out)
+{
+ totalBytesIn += in;
+ totalBytesOut += out;
+
+ unsigned int tdiff = sys->getTime()-lastUpdate;
+ if (tdiff >= 5)
+ {
+ bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff;
+ bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff;
+ lastBytesIn = totalBytesIn;
+ lastBytesOut = totalBytesOut;
+ lastUpdate = sys->getTime();
+ }
+}
+// -------------------------------------
+int Stream::readLine(char *in, int max)
+{
+ int i=0;
+ max -= 2;
+
+ while(max--)
+ {
+ char c;
+ read(&c,1);
+ if (c == '\n')
+ break;
+ if (c == '\r')
+ continue;
+ in[i++] = c;
+ }
+ in[i] = 0;
+ return i;
+}
+// -------------------------------------
+void Stream::write(const char *fmt,va_list ap)
+{
+ char tmp[4096];
+ vsprintf(tmp,fmt,ap);
+ write(tmp,strlen(tmp));
+}
+// -------------------------------------
+void Stream::writeStringF(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ write(fmt,ap);
+ va_end(ap);
+}
+// -------------------------------------
+void Stream::writeString(const char *str)
+{
+ write(str,strlen(str));
+}
+// -------------------------------------
+void Stream::writeLineF(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ write(fmt,ap);
+
+ if (writeCRLF)
+ write("\r\n",2);
+ else
+ write("\n",1);
+
+ va_end(ap);
+}
+
+// -------------------------------------
+void Stream::writeLine(const char *str)
+{
+ writeString(str);
+
+ if (writeCRLF)
+ write("\r\n",2);
+ else
+ write("\n",1);
+}
+
+// -------------------------------------
+int Stream::readWord(char *in, int max)
+{
+ int i=0;
+ while (!eof())
+ {
+ char c = readChar();
+
+ if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
+ {
+ if (i)
+ break; // stop reading
+ else
+ continue; // skip whitespace
+ }
+
+ if (i >= (max-1))
+ break;
+
+ in[i++] = c;
+ }
+
+ in[i]=0;
+ return i;
+}
+
+
+// --------------------------------------------------
+int Stream::readBase64(char *p, int max)
+{
+ char vals[4];
+
+ int cnt=0;
+ while (cnt < (max-4))
+ {
+ read(vals,4);
+ int rl = String::base64WordToChars(p,vals);
+ if (!rl)
+ break;
+
+ p+=rl;
+ cnt+=rl;
+ }
+ *p = 0;
+ return cnt;
+}
+
+
+// -------------------------------------
+int Stream::readBits(int cnt)
+{
+ int v = 0;
+
+ while (cnt)
+ {
+ if (!bitsPos)
+ bitsBuffer = readChar();
+
+ cnt--;
+
+ v |= (bitsBuffer&(1<<(7-bitsPos)))?(1<<cnt):0;
+
+ bitsPos = (bitsPos+1)&7;
+ }
+
+ return v;
+}
--- /dev/null
+// ------------------------------------------------
+// File : stream.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STREAM_H
+#define _STREAM_H
+
+// -------------------------------------
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "common.h"
+#include "sys.h"
+#include "id.h"
+
+// -------------------------------------
+class Stream
+{
+public:
+ Stream()
+ :writeCRLF(true)
+ ,totalBytesIn(0)
+ ,totalBytesOut(0)
+ ,lastBytesIn(0)
+ ,lastBytesOut(0)
+ ,bytesInPerSec(0)
+ ,bytesOutPerSec(0)
+ ,lastUpdate(0)
+ ,bitsBuffer(0)
+ ,bitsPos(0)
+ {
+ }
+ virtual ~Stream() {}
+
+ virtual int readUpto(void *,int) {return 0;}
+ virtual int read(void *,int)=0;
+ virtual void write(const void *,int) = 0;
+ virtual bool eof()
+ {
+ throw StreamException("Stream can`t eof");
+ return false;
+ }
+
+ virtual void rewind()
+ {
+ throw StreamException("Stream can`t rewind");
+ }
+
+ virtual void seekTo(int)
+ {
+ throw StreamException("Stream can`t seek");
+ }
+
+ void writeTo(Stream &out, int len);
+ virtual void skip(int i);
+
+ virtual void close()
+ {
+ }
+
+ virtual void setReadTimeout(unsigned int )
+ {
+ }
+ virtual void setWriteTimeout(unsigned int )
+ {
+ }
+ virtual void setPollRead(bool)
+ {
+ }
+
+ virtual int getPosition() {return 0;}
+
+
+ // binary
+ char readChar()
+ {
+ char v;
+ read(&v,1);
+ return v;
+ }
+ short readShort()
+ {
+ short v;
+ read(&v,2);
+ CHECK_ENDIAN2(v);
+ return v;
+ }
+ long readLong()
+ {
+ long v;
+ read(&v,4);
+ CHECK_ENDIAN4(v);
+ return v;
+ }
+ int readInt()
+ {
+ return readLong();
+ }
+ ID4 readID4()
+ {
+ ID4 id;
+ read(id.getData(),4);
+ return id;
+ }
+ int readInt24()
+ {
+ int v=0;
+ read(&v,3);
+ CHECK_ENDIAN3(v);
+ }
+
+
+
+ long readTag()
+ {
+ long v = readLong();
+ return SWAP4(v);
+ }
+
+ int readString(char *s, int max)
+ {
+ int cnt=0;
+ while (max)
+ {
+ char c = readChar();
+ *s++ = c;
+ cnt++;
+ max--;
+ if (!c)
+ break;
+ }
+ return cnt;
+ }
+
+ virtual bool readReady() {return true;}
+ virtual int numPending() {return 0;}
+
+
+ void writeID4(ID4 id)
+ {
+ write(id.getData(),4);
+ }
+
+ void writeChar(char v)
+ {
+ write(&v,1);
+ }
+ void writeShort(short v)
+ {
+ CHECK_ENDIAN2(v);
+ write(&v,2);
+ }
+ void writeLong(long v)
+ {
+ CHECK_ENDIAN4(v);
+ write(&v,4);
+ }
+ void writeInt(int v) {writeLong(v);}
+
+ void writeTag(long v)
+ {
+ //CHECK_ENDIAN4(v);
+ writeLong(SWAP4(v));
+ }
+
+ void writeTag(char id[4])
+ {
+ write(id,4);
+ }
+
+ int writeUTF8(unsigned int);
+
+ // text
+ int readLine(char *in, int max);
+
+ int readWord(char *, int);
+ int readBase64(char *, int);
+
+ void write(const char *,va_list);
+ void writeLine(const char *);
+ void writeLineF(const char *,...);
+ void writeString(const char *);
+ void writeStringF(const char *,...);
+
+ bool writeCRLF;
+
+ int readBits(int);
+
+ void updateTotals(unsigned int,unsigned int);
+
+
+ unsigned char bitsBuffer;
+ unsigned int bitsPos;
+
+ unsigned int totalBytesIn,totalBytesOut;
+ unsigned int lastBytesIn,lastBytesOut;
+ unsigned int bytesInPerSec,bytesOutPerSec;
+ unsigned int lastUpdate;
+
+};
+
+
+// -------------------------------------
+class FileStream : public Stream
+{
+public:
+ FileStream() {file=NULL;}
+
+ void openReadOnly(const char *);
+ void openWriteReplace(const char *);
+ void openWriteAppend(const char *);
+ bool isOpen(){return file!=NULL;}
+ int length();
+ int pos();
+
+ virtual void seekTo(int);
+ virtual int getPosition() {return pos();}
+ virtual void flush();
+ virtual int read(void *,int);
+ virtual void write(const void *,int);
+ virtual bool eof();
+ virtual void rewind();
+ virtual void close();
+
+ FILE *file;
+};
+// -------------------------------------
+class MemoryStream : public Stream
+{
+public:
+ MemoryStream()
+ :buf(NULL)
+ ,len(0)
+ ,pos(0)
+ ,own(false)
+ {
+ }
+
+ MemoryStream(void *p, int l)
+ :buf((char *)p)
+ ,len(l)
+ ,pos(0)
+ ,own(false)
+ {
+ }
+
+ MemoryStream(int l)
+ :buf(new char[l])
+ ,len(l)
+ ,pos(0)
+ ,own(true)
+ {
+ }
+
+ ~MemoryStream() {free2();}
+
+ void readFromFile(FileStream &file)
+ {
+ len = file.length();
+ buf = new char[len];
+ own = true;
+ pos = 0;
+ file.read(buf,len);
+ }
+
+ void free2()
+ {
+ if (own && buf)
+ {
+ delete buf;
+ buf = NULL;
+ own = false;
+ }
+
+ }
+
+ virtual int read(void *p,int l)
+ {
+ if (pos+l <= len)
+ {
+ memcpy(p,&buf[pos],l);
+ pos += l;
+ return l;
+ }else
+ {
+ memset(p,0,l);
+ return 0;
+ }
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ if ((pos+l) > len)
+ throw StreamException("Stream - premature end of write()");
+ memcpy(&buf[pos],p,l);
+ pos += l;
+ }
+
+ virtual bool eof()
+ {
+ return pos >= len;
+ }
+
+ virtual void rewind()
+ {
+ pos = 0;
+ }
+
+ virtual void seekTo(int p)
+ {
+ pos = p;
+ }
+
+ virtual int getPosition()
+ {
+ return pos;
+ }
+
+ void convertFromBase64();
+
+
+ char *buf;
+ bool own;
+ int len,pos;
+};
+// --------------------------------------------------
+class IndirectStream : public Stream
+{
+public:
+
+ void init(Stream *s)
+ {
+ stream = s;
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return stream->read(p,l);
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ stream->write(p,l);
+ }
+
+ virtual bool eof()
+ {
+ return stream->eof();
+ }
+
+ virtual void close()
+ {
+ stream->close();
+ }
+
+ Stream *stream;
+};
+
+// -------------------------------------
+
+class SockBufStream : public Stream
+{
+public:
+ SockBufStream(Stream &sockStream, int bufsize=128*1024)
+ : sock(sockStream), mem(bufsize)
+ {
+ }
+
+ ~SockBufStream()
+ {
+ flush();
+ mem.free2();
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return sock.read(p, l);
+ }
+
+ virtual void write(const void *p, int len)
+ {
+ if ( mem.pos+len > mem.len )
+ flush();
+
+ mem.write(p, len);
+ }
+
+ void flush()
+ {
+ if ( mem.pos > 0 ) {
+ sock.write(mem.buf, mem.pos);
+ clearWriteBuffer();
+ }
+ }
+
+ void clearWriteBuffer()
+ {
+ mem.rewind();
+ }
+
+private:
+ Stream &sock;
+ MemoryStream mem;
+};
+
+// -------------------------------------
+class WriteBufferStream : public Stream
+{
+public:
+ WriteBufferStream(Stream *out_)
+ :buf(NULL)
+ ,own(false)
+ ,len(0)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ WriteBufferStream(void *p, int l, Stream *out_)
+ :buf((char *)p)
+ ,own(false)
+ ,len(l)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ WriteBufferStream(int l, Stream *out_)
+ :buf(new char[l])
+ ,own(true)
+ ,len(l)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ virtual ~WriteBufferStream()
+ {
+ try {
+ flush();
+ } catch (StreamException &) {}
+ free();
+ }
+
+ void readFromFile(FileStream &file)
+ {
+ len = file.length();
+ buf = new char[len];
+ own = true;
+ pos = 0;
+ file.read(buf,len);
+ }
+
+ void flush()
+ {
+ if (!out || !buf) return;
+ out->write(buf, pos);
+ pos = 0;
+ }
+
+ void free()
+ {
+ if (own && buf)
+ {
+ delete buf;
+ buf = NULL;
+ own = false;
+ }
+
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return 0;
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ char *cp = (char *) p;
+ while ((pos + l) >= len) {
+ int n = len - pos;
+ memcpy(&buf[pos], cp, n);
+ l -= n;
+ cp += n;
+ pos = len;
+ flush();
+ if (pos != 0) return;
+ }
+ if (l > 0) {
+ memcpy(&buf[pos], cp, l);
+ pos += l;
+ }
+ }
+
+ virtual bool eof()
+ {
+ return true;
+ }
+
+ virtual void rewind()
+ {
+ pos = 0;
+ }
+
+ virtual void seekTo(int p)
+ {
+ pos = p;
+ }
+
+ virtual int getPosition()
+ {
+ return pos;
+ }
+
+ void convertFromBase64();
+
+
+ char *buf;
+ bool own;
+ int len,pos;
+ Stream *out;
+};
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : sys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Sys is a base class for all things systemy, like starting threads, creating sockets etc..
+// Lock is a very basic cross platform CriticalSection class
+// SJIS-UTF8 conversion by ????
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "common.h"
+#include "sys.h"
+#include "socket.h"
+#include "gnutella.h"
+#include "servmgr.h" //JP-EX
+#ifdef WIN32
+#include "utf8.h" //JP-Patch
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc))
+#define isEUC(a) (a >= 0xa1 && a <= 0xfe)
+#define isASCII(a) (a <= 0x7f)
+#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
+#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 )
+#define isESCAPE(a,b) ((a == '&') && (b == '#'))
+#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
+
+
+
+// -----------------------------------
+const char *LogBuffer::logTypes[]=
+{
+ "",
+ "DBUG",
+ "EROR",
+ "GNET",
+ "CHAN",
+};
+
+// -----------------------------------
+// base64 encode/decode taken from ices2 source..
+static char base64table[64] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+#if 0
+// -----------------------------------
+static char *util_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = malloc(len*4/3 + 4);
+ char *result = out;
+ int chunk;
+
+ while(len > 0) {
+ chunk = (len >3)?3:len;
+ *out++ = base64table[(*data & 0xFC)>>2];
+ *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+ switch(chunk) {
+ case 3:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+ *out++ = base64table[(*(data+2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+
+ return result;
+}
+#endif
+
+// -----------------------------------
+static int base64chartoval(char input)
+{
+ if(input >= 'A' && input <= 'Z')
+ return input - 'A';
+ else if(input >= 'a' && input <= 'z')
+ return input - 'a' + 26;
+ else if(input >= '0' && input <= '9')
+ return input - '0' + 52;
+ else if(input == '+')
+ return 62;
+ else if(input == '/')
+ return 63;
+ else if(input == '=')
+ return -1;
+ else
+ return -2;
+}
+
+// -----------------------------------
+static char *util_base64_decode(char *input)
+{
+ return NULL;
+}
+
+
+
+
+
+// ------------------------------------------
+Sys::Sys()
+{
+ idleSleepTime = 10;
+ logBuf = new LogBuffer(1000,100);
+ numThreads=0;
+}
+
+// ------------------------------------------
+void Sys::sleepIdle()
+{
+ sleep(idleSleepTime);
+}
+
+// ------------------------------------------
+bool Host::isLocalhost()
+{
+ return loopbackIP() || (ip == ClientSocket::getIP(NULL));
+}
+// ------------------------------------------
+void Host::fromStrName(const char *str, int p)
+{
+ if (!strlen(str))
+ {
+ port = 0;
+ ip = 0;
+ return;
+ }
+
+ char name[128];
+ strncpy(name,str,sizeof(name)-1);
+ name[127] = '\0';
+ port = p;
+ char *pp = strstr(name,":");
+ if (pp)
+ {
+ port = atoi(pp+1);
+ pp[0] = 0;
+ }
+
+ ip = ClientSocket::getIP(name);
+}
+// ------------------------------------------
+void Host::fromStrIP(const char *str, int p)
+{
+ unsigned int ipb[4];
+ unsigned int ipp;
+
+
+ if (strstr(str,":"))
+ {
+ if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5)
+ {
+ ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+ port = ipp;
+ }else
+ {
+ ip = 0;
+ port = 0;
+ }
+ }else{
+ port = p;
+ if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4)
+ ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+ else
+ ip = 0;
+ }
+}
+// -----------------------------------
+bool Host::isMemberOf(Host &h)
+{
+ if (h.ip==0)
+ return false;
+
+ if( h.ip0() != 255 && ip0() != h.ip0() )
+ return false;
+ if( h.ip1() != 255 && ip1() != h.ip1() )
+ return false;
+ if( h.ip2() != 255 && ip2() != h.ip2() )
+ return false;
+ if( h.ip3() != 255 && ip3() != h.ip3() )
+ return false;
+
+/* removed for endieness compatibility
+ for(int i=0; i<4; i++)
+ if (h.ipByte[i] != 255)
+ if (ipByte[i] != h.ipByte[i])
+ return false;
+*/
+ return true;
+}
+
+// -----------------------------------
+char *trimstr(char *s1)
+{
+ while (*s1)
+ {
+ if ((*s1 == ' ') || (*s1 == '\t'))
+ s1++;
+ else
+ break;
+
+ }
+
+ char *s = s1;
+
+ if(strlen(s1) > 0) {
+/* s1 = s1+strlen(s1);
+
+ while (*--s1)
+ if ((*s1 != ' ') && (*s1 != '\t'))
+ break;*/
+
+ s1 = s1+strlen(s1);
+
+// s1[1] = 0;
+
+ while (*--s1)
+ if ((*s1 != ' ') && (*s1 != '\t'))
+ break;
+
+ s1[1] = 0;
+ }
+ return s;
+}
+
+// -----------------------------------
+char *stristr(const char *s1, const char *s2)
+{
+ while (*s1)
+ {
+ if (TOUPPER(*s1) == TOUPPER(*s2))
+ {
+ const char *c1 = s1;
+ const char *c2 = s2;
+
+ while (*c1 && *c2)
+ {
+ if (TOUPPER(*c1) != TOUPPER(*c2))
+ break;
+ c1++;
+ c2++;
+ }
+ if (*c2==0)
+ return (char *)s1;
+ }
+
+ s1++;
+ }
+ return NULL;
+}
+// -----------------------------------
+bool String::isValidURL()
+{
+ return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0);
+}
+
+// -----------------------------------
+void String::setFromTime(unsigned int t)
+{
+// char *p = ctime((time_t*)&t);
+ time_t tmp = t;
+ char *p = ctime(&tmp);
+ if (p)
+ strcpy(data,p);
+ else
+ strcpy(data,"-");
+ type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromStopwatch(unsigned int t)
+{
+ unsigned int sec,min,hour,day;
+
+ sec = t%60;
+ min = (t/60)%60;
+ hour = (t/3600)%24;
+ day = (t/86400);
+
+ if (day)
+ sprintf(data,"%d day, %d hour",day,hour);
+ else if (hour)
+ sprintf(data,"%d hour, %d min",hour,min);
+ else if (min)
+ sprintf(data,"%d min, %d sec",min,sec);
+ else if (sec)
+ sprintf(data,"%d sec",sec);
+ else
+ sprintf(data,"-");
+
+ type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromString(const char *str, TYPE t)
+{
+ int cnt=0;
+ bool quote=false;
+ while (*str)
+ {
+ bool add=true;
+ if (*str == '\"')
+ {
+ if (quote)
+ break;
+ else
+ quote = true;
+ add = false;
+ }else if (*str == ' ')
+ {
+ if (!quote)
+ {
+ if (cnt)
+ break;
+ else
+ add = false;
+ }
+ }
+
+ if (add)
+ {
+ data[cnt++] = *str++;
+ if (cnt >= (MAX_LEN-1))
+ break;
+ }else
+ str++;
+ }
+ data[cnt] = 0;
+ type = t;
+}
+
+// -----------------------------------
+int String::base64WordToChars(char *out,const char *input)
+{
+ char *start = out;
+ signed char vals[4];
+
+ vals[0] = base64chartoval(*input++);
+ vals[1] = base64chartoval(*input++);
+ vals[2] = base64chartoval(*input++);
+ vals[3] = base64chartoval(*input++);
+
+ if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1)
+ return 0;
+
+ *out++ = vals[0]<<2 | vals[1]>>4;
+ if(vals[2] >= 0)
+ *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2);
+ else
+ *out++ = 0;
+
+ if(vals[3] >= 0)
+ *out++ = ((vals[2]&0x03)<<6) | (vals[3]);
+ else
+ *out++ = 0;
+
+ return out-start;
+}
+
+// -----------------------------------
+void String::BASE642ASCII(const char *input)
+{
+ char *out = data;
+ int len = strlen(input);
+
+ while(len >= 4)
+ {
+ out += base64WordToChars(out,input);
+ input += 4;
+ len -= 4;
+ }
+ *out = 0;
+}
+
+
+
+// -----------------------------------
+void String::UNKNOWN2UNICODE(const char *in,bool safe)
+{
+ MemoryStream utf8(data,MAX_LEN-1);
+
+ unsigned char c;
+ unsigned char d;
+
+ while (c = *in++)
+ {
+ d = *in;
+
+ if (isUTF8(c,d)) // utf8 encoded
+ {
+ int numChars=0;
+ int i;
+
+ for(i=0; i<6; i++)
+ {
+ if (c & (0x80>>i))
+ numChars++;
+ else
+ break;
+ }
+
+ utf8.writeChar(c);
+ for(i=0; i<numChars-1; i++)
+ utf8.writeChar(*in++);
+
+ }
+ else if(isSJIS(c,d)) // shift_jis
+ {
+ utf8.writeUTF8(JISConverter::sjisToUnicode((c<<8 | d)));
+ in++;
+
+ }
+ else if(isEUC(c) && isEUC(d)) // euc-jp
+ {
+ utf8.writeUTF8(JISConverter::eucToUnicode((c<<8 | d)));
+ in++;
+
+ }
+ else if (isESCAPE(c,d)) // html escape tags &#xx;
+ {
+ in++;
+ char code[16];
+ char *cp = code;
+ while (c=*in++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+
+ utf8.writeUTF8(strtoul(code,NULL,10));
+
+ }
+ else if (isPLAINASCII(c)) // plain ascii : a-z 0-9 etc..
+ {
+ utf8.writeUTF8(c);
+
+ }
+ else if (isHTMLSPECIAL(c) && safe)
+ {
+ const char *str = NULL;
+ if (c == '&') str = "&";
+ else if (c == '\"') str = """;
+ else if (c == '\'') str = "'";
+ else if (c == '<') str = "<";
+ else if (c == '>') str = ">";
+ else str = "?";
+
+ utf8.writeString(str);
+ }
+ else
+ {
+ utf8.writeUTF8(c);
+ }
+
+ if (utf8.pos >= (MAX_LEN-10))
+ break;
+
+
+ }
+
+ utf8.writeChar(0); // null terminate
+
+}
+
+// -----------------------------------
+void String::ASCII2HTML(const char *in)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ unsigned char c;
+ const char *p = in;
+ while (c = *p++)
+ {
+
+ if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+ {
+ *op++ = c;
+ }else
+ {
+ sprintf(op,"&#x%02X;",(int)c);
+ op+=6;
+ }
+ if (op >= oe)
+ break;
+ }
+ *op = 0;
+}
+// -----------------------------------
+void String::ASCII2ESC(const char *in, bool safe)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ unsigned char c;
+ while (c = *p++)
+ {
+ if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+ *op++ = c;
+ else
+ {
+ *op++ = '%';
+ if (safe)
+ *op++ = '%';
+ *op=0;
+ sprintf(op,"%02X",(int)c);
+ op+=2;
+ }
+ if (op >= oe)
+ break;
+ }
+ *op=0;
+}
+// -----------------------------------
+void String::HTML2ASCII(const char *in)
+{
+ unsigned char c;
+ char *o = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ while (c = *p++)
+ {
+ if ((c == '&') && (p[0] == '#'))
+ {
+ p++;
+ char code[8];
+ char *cp = code;
+ char ec = *p++; // hex/dec
+ while (c=*p++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+ c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10);
+ }
+ *o++ = c;
+ if (o >= oe)
+ break;
+ }
+
+ *o=0;
+}
+// -----------------------------------
+void String::HTML2UNICODE(const char *in)
+{
+ MemoryStream utf8(data,MAX_LEN-1);
+
+ unsigned char c;
+ while (c = *in++)
+ {
+ if ((c == '&') && (*in == '#'))
+ {
+ in++;
+ char code[16];
+ char *cp = code;
+ char ec = *in++; // hex/dec
+ while (c=*in++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+ utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10));
+ }else
+ utf8.writeUTF8(c);
+
+ if (utf8.pos >= (MAX_LEN-10))
+ break;
+ }
+
+ utf8.writeUTF8(0);
+}
+
+// -----------------------------------
+void String::ESC2ASCII(const char *in)
+{
+ unsigned char c;
+ char *o = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ while (c = *p++)
+ {
+ if (c == '+')
+ c = ' ';
+ else if (c == '%')
+ {
+ if (p[0] == '%')
+ p++;
+
+ char hi = TOUPPER(p[0]);
+ char lo = TOUPPER(p[1]);
+ c = (TONIBBLE(hi)<<4) | TONIBBLE(lo);
+ p+=2;
+ }
+ *o++ = c;
+ if (o >= oe)
+ break;
+ }
+
+ *o=0;
+}
+// -----------------------------------
+void String::ASCII2META(const char *in, bool safe)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ unsigned char c;
+ while (c = *p++)
+ {
+ switch (c)
+ {
+ case '%':
+ if (safe)
+ *op++='%';
+ break;
+ case ';':
+ c = ':';
+ break;
+ }
+
+ *op++=c;
+ if (op >= oe)
+ break;
+ }
+ *op=0;
+}
+#ifdef WIN32
+// -----------------------------------
+void String::ASCII2SJIS(const char *in) //JP-EX
+{
+ char *op = data;
+ char *p;
+ if (utf8_decode(in,&p)<0)
+ {
+ strcpy(op,in);
+ return;
+ }
+ strcpy(op,p);
+ free(p);
+}
+#endif
+// -----------------------------------
+void String::convertTo(TYPE t)
+{
+ if (t != type)
+ {
+ String tmp = *this;
+
+ // convert to ASCII
+ switch (type)
+ {
+ case T_UNKNOWN:
+ case T_ASCII:
+ break;
+ case T_HTML:
+ tmp.HTML2ASCII(data);
+ break;
+ case T_ESC:
+ case T_ESCSAFE:
+ tmp.ESC2ASCII(data);
+ break;
+ case T_META:
+ case T_METASAFE:
+ break;
+ case T_BASE64:
+ tmp.BASE642ASCII(data);
+ break;
+ }
+
+ // convert to new format
+ switch (t)
+ {
+ case T_UNKNOWN:
+ case T_ASCII:
+ strcpy(data,tmp.data);
+ break;
+ case T_UNICODE:
+ UNKNOWN2UNICODE(tmp.data,false);
+ break;
+ case T_UNICODESAFE:
+ UNKNOWN2UNICODE(tmp.data,true);
+ break;
+ case T_HTML:
+ ASCII2HTML(tmp.data);
+ break;
+ case T_ESC:
+ ASCII2ESC(tmp.data,false);
+ break;
+ case T_ESCSAFE:
+ ASCII2ESC(tmp.data,true);
+ break;
+ case T_META:
+ ASCII2META(tmp.data,false);
+ break;
+ case T_METASAFE:
+ ASCII2META(tmp.data,true);
+ break;
+#ifdef WIN32
+ case T_SJIS: //JP-EX
+ ASCII2SJIS(tmp.data);
+ break;
+#endif
+ }
+
+ type = t;
+ }
+}
+// -----------------------------------
+void LogBuffer::write(const char *str, TYPE t)
+{
+ lock.on();
+
+ unsigned int len = strlen(str);
+ int cnt=0;
+ while (len)
+ {
+ unsigned int rlen = len;
+ if (rlen > (lineLen-1))
+ rlen = lineLen-1;
+
+ int i = currLine % maxLines;
+ int bp = i*lineLen;
+ strncpy(&buf[bp],str,rlen);
+ buf[bp+rlen] = 0;
+ if (cnt==0)
+ {
+ times[i] = sys->getTime();
+ types[i] = t;
+ }else
+ {
+ times[i] = 0;
+ types[i] = T_NONE;
+ }
+ currLine++;
+
+ str += rlen;
+ len -= rlen;
+ cnt++;
+ }
+
+ lock.off();
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg)
+{
+ if (!str)
+ return NULL;
+
+// char *s = strstr(str,arg);
+ char *s = (char*)strstr(str,arg);
+
+ if (!s)
+ return NULL;
+
+ s += strlen(arg);
+
+ return s;
+}
+
+// -----------------------------------
+bool cmpCGIarg(char *str, char *arg, char *value)
+{
+ if ((!str) || (!strlen(value)))
+ return false;
+
+ if (strnicmp(str,arg,strlen(arg)) == 0)
+ {
+
+ str += strlen(arg);
+
+ return strncmp(str,value,strlen(value))==0;
+ }else
+ return false;
+}
+// -----------------------------------
+bool hasCGIarg(char *str, char *arg)
+{
+ if (!str)
+ return false;
+
+ char *s = strstr(str,arg);
+
+ if (!s)
+ return false;
+
+ return true;
+}
+
+
+// ---------------------------
+void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3)
+{
+ int s1=0,s2=0;
+ for(int i=0; i<16; i++)
+ {
+ unsigned char ipb = id[i];
+
+ // encode with IP address
+ if (h)
+ ipb ^= ((unsigned char *)&h->ip)[i&3];
+
+ // add a bit of salt
+ if (salt1)
+ {
+ if (salt1[s1])
+ ipb ^= salt1[s1++];
+ else
+ s1=0;
+ }
+
+ // and some more
+ if (salt2)
+ {
+ if (salt2[s2])
+ ipb ^= salt2[s2++];
+ else
+ s2=0;
+ }
+
+ // plus some pepper
+ ipb ^= salt3;
+
+ id[i] = ipb;
+ }
+
+}
+// ---------------------------
+void GnuID::toStr(char *str)
+{
+
+ str[0] = 0;
+ for(int i=0; i<16; i++)
+ {
+ char tmp[8];
+ unsigned char ipb = id[i];
+
+ sprintf(tmp,"%02X",ipb);
+ strcat(str,tmp);
+ }
+
+}
+// ---------------------------
+void GnuID::fromStr(const char *str)
+{
+ clear();
+
+ if (strlen(str) < 32)
+ return;
+
+ char buf[8];
+
+ buf[2] = 0;
+
+ for(int i=0; i<16; i++)
+ {
+ buf[0] = str[i*2];
+ buf[1] = str[i*2+1];
+ id[i] = (unsigned char)strtoul(buf,NULL,16);
+ }
+
+}
+
+// ---------------------------
+void GnuID::generate(unsigned char flags)
+{
+ clear();
+
+ for(int i=0; i<16; i++)
+ id[i] = sys->rnd();
+
+ id[0] = flags;
+}
+
+// ---------------------------
+unsigned char GnuID::getFlags()
+{
+ return id[0];
+}
+
+// ---------------------------
+GnuIDList::GnuIDList(int max)
+:ids(new GnuID[max])
+{
+ maxID = max;
+ for(int i=0; i<maxID; i++)
+ ids[i].clear();
+}
+// ---------------------------
+GnuIDList::~GnuIDList()
+{
+ delete [] ids;
+}
+// ---------------------------
+bool GnuIDList::contains(GnuID &id)
+{
+ for(int i=0; i<maxID; i++)
+ if (ids[i].isSame(id))
+ return true;
+ return false;
+}
+// ---------------------------
+int GnuIDList::numUsed()
+{
+ int cnt=0;
+ for(int i=0; i<maxID; i++)
+ if (ids[i].storeTime)
+ cnt++;
+ return cnt;
+}
+// ---------------------------
+unsigned int GnuIDList::getOldest()
+{
+ unsigned int t=(unsigned int)-1;
+ for(int i=0; i<maxID; i++)
+ if (ids[i].storeTime)
+ if (ids[i].storeTime < t)
+ t = ids[i].storeTime;
+ return t;
+}
+// ---------------------------
+void GnuIDList::add(GnuID &id)
+{
+ unsigned int minTime = (unsigned int) -1;
+ int minIndex = 0;
+
+ // find same or oldest
+ for(int i=0; i<maxID; i++)
+ {
+ if (ids[i].isSame(id))
+ {
+ ids[i].storeTime = sys->getTime();
+ return;
+ }
+ if (ids[i].storeTime <= minTime)
+ {
+ minTime = ids[i].storeTime;
+ minIndex = i;
+ }
+ }
+
+ ids[minIndex] = id;
+ ids[minIndex].storeTime = sys->getTime();
+}
+// ---------------------------
+void GnuIDList::clear()
+{
+ for(int i=0; i<maxID; i++)
+ ids[i].clear();
+}
+
+// ---------------------------
+void LogBuffer::dumpHTML(Stream &out)
+{
+ WLockBlock lb(&lock);
+ lb.on();
+
+ unsigned int nl = currLine;
+ unsigned int sp = 0;
+ if (nl > maxLines)
+ {
+ nl = maxLines-1;
+ sp = (currLine+1)%maxLines;
+ }
+
+ String tim,str;
+ if (nl)
+ {
+ for(unsigned int i=0; i<nl; i++)
+ {
+ unsigned int bp = sp*lineLen;
+
+ if (types[sp])
+ {
+ tim.setFromTime(times[sp]);
+
+ out.writeString(tim.cstr());
+ out.writeString(" <b>[");
+ out.writeString(getTypeStr(types[sp]));
+ out.writeString("]</b> ");
+ }
+ str.set(&buf[bp]);
+ str.convertTo(String::T_HTML);
+
+ out.writeString(str.cstr());
+ out.writeString("<br>");
+
+ sp++;
+ sp %= maxLines;
+ }
+ }
+
+ lb.off();
+
+}
+
+// ---------------------------
+void ThreadInfo::shutdown()
+{
+ active = false;
+ //sys->waitThread(this);
+}
--- /dev/null
+// ------------------------------------------------
+// File : sys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SYS_H
+#define _SYS_H
+
+#include <string.h>
+#include "common.h"
+
+#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \
+ (b = 18000 * (b & 65535) + (b >> 16)) )
+extern char *stristr(const char *s1, const char *s2);
+extern char *trimstr(char *s);
+
+
+#define MAX_CGI_LEN 1024
+// ------------------------------------
+class String
+{
+public:
+ enum {
+ MAX_LEN = 256
+ };
+
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_ASCII,
+ T_HTML,
+ T_ESC,
+ T_ESCSAFE,
+ T_META,
+ T_METASAFE,
+ T_BASE64,
+ T_UNICODE,
+ T_UNICODESAFE,
+#ifdef WIN32
+ T_SJIS, //JP-EX
+#endif
+ };
+
+ String() {clear();}
+ String(const char *p, TYPE t=T_ASCII)
+ {
+ set(p,t);
+ }
+
+ // set from straight null terminated string
+ void set(const char *p, TYPE t=T_ASCII)
+ {
+ strncpy(data,p,MAX_LEN-1);
+ data[MAX_LEN-1] = 0;
+ type = t;
+ }
+
+ // set from quoted or unquoted null terminated string
+ void setFromString(const char *str, TYPE t=T_ASCII);
+
+ // set from stopwatch
+ void setFromStopwatch(unsigned int t);
+
+ // set from time
+ void setFromTime(unsigned int t);
+
+
+ // from single word (end at whitespace)
+ void setFromWord(const char *str)
+ {
+ int i;
+ for(i=0; i<MAX_LEN-1; i++)
+ {
+ data[i] = *str++;
+ if ((data[i]==0) || (data[i]==' '))
+ break;
+ }
+ data[i]=0;
+ }
+
+
+ // set from null terminated string, remove first/last chars
+ void setUnquote(const char *p, TYPE t=T_ASCII)
+ {
+ int slen = strlen(p);
+ if (slen > 2)
+ {
+ if (slen >= MAX_LEN) slen = MAX_LEN;
+ strncpy(data,p+1,slen-2);
+ data[slen-2]=0;
+ }else
+ clear();
+ type = t;
+ }
+
+ void clear()
+ {
+ data[0]=0;
+ type = T_UNKNOWN;
+ }
+ void ASCII2ESC(const char *,bool);
+ void ASCII2HTML(const char *);
+ void ASCII2META(const char *,bool);
+ void ESC2ASCII(const char *);
+ void HTML2ASCII(const char *);
+ void HTML2UNICODE(const char *);
+ void BASE642ASCII(const char *);
+ void UNKNOWN2UNICODE(const char *,bool);
+#ifdef WIN32
+ void ASCII2SJIS(const char *); //JP-EX
+#endif
+
+ static int base64WordToChars(char *,const char *);
+
+ static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;}
+
+ bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;}
+ bool isValidURL();
+ bool isEmpty() {return data[0]==0;}
+ bool isSame(::String &s) const {return strcmp(data,s.data)==0;}
+ bool isSame(const char *s) const {return strcmp(data,s)==0;}
+ bool contains(::String &s) {return stristr(data,s.data)!=NULL;}
+ bool contains(const char *s) {return stristr(data,s)!=NULL;}
+ void append(const char *s)
+ {
+ if ((strlen(s)+strlen(data) < (MAX_LEN-1)))
+ strcat(data,s);
+ }
+ void append(char c)
+ {
+ char tmp[2];
+ tmp[0]=c;
+ tmp[1]=0;
+ append(tmp);
+ }
+
+ void prepend(const char *s)
+ {
+ ::String tmp;
+ tmp.set(s);
+ tmp.append(data);
+ tmp.type = type;
+ *this = tmp;
+ }
+
+ bool operator == (const char *s) const {return isSame(s);}
+
+ operator const char *() const {return data;}
+
+ void convertTo(TYPE t);
+
+ char *cstr() {return data;}
+
+ static bool isWhitespace(char c) {return c==' ' || c=='\t';}
+
+ TYPE type;
+ char data[MAX_LEN];
+};
+
+// ------------------------------------
+namespace peercast {
+class Random {
+public:
+ Random(int s=0x14235465)
+ {
+ setSeed(s);
+ }
+
+ unsigned int next()
+ {
+ return RAND(a[0],a[1]);
+ }
+
+ void setSeed(int s)
+ {
+ a[0] = a[1] = s;
+ }
+
+ unsigned long a[2];
+};
+}
+// ------------------------------------
+class Sys
+{
+public:
+ Sys();
+
+
+
+ virtual class ClientSocket *createSocket() = 0;
+ virtual bool startThread(class ThreadInfo *) = 0;
+ virtual void sleep(int) = 0;
+ virtual void appMsg(long,long = 0) = 0;
+ virtual unsigned int getTime() = 0;
+ virtual double getDTime() = 0;
+ virtual unsigned int rnd() = 0;
+ virtual void getURL(const char *) = 0;
+ virtual void exit() = 0;
+ virtual bool hasGUI() = 0;
+ virtual void callLocalURL(const char *,int)=0;
+ virtual void executeFile(const char *) = 0;
+ virtual void endThread(ThreadInfo *) {}
+ virtual void waitThread(ThreadInfo *, int timeout = 30000) {}
+
+
+
+#ifdef __BIG_ENDIAN__
+ unsigned short convertEndian(unsigned short v) { return SWAP2(v); }
+ unsigned int convertEndian(unsigned int v) { return SWAP4(v); }
+#else
+ unsigned short convertEndian(unsigned short v) { return v; }
+ unsigned int convertEndian(unsigned int v) { return v; }
+#endif
+
+
+ void sleepIdle();
+
+ unsigned int idleSleepTime;
+ unsigned int rndSeed;
+ unsigned int numThreads;
+
+ class LogBuffer *logBuf;
+};
+
+
+#ifdef WIN32
+#include <windows.h>
+
+typedef __int64 int64_t;
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+ WEvent()
+ {
+ event = ::CreateEvent(NULL, // no security attributes
+ TRUE, // manual-reset
+ FALSE,// initially non-signaled
+ NULL);// anonymous
+ }
+
+ ~WEvent()
+ {
+ ::CloseHandle(event);
+ }
+
+ void signal()
+ {
+ ::SetEvent(event);
+ }
+
+ void wait(int timeout = 30000)
+ {
+ switch(::WaitForSingleObject(event, timeout))
+ {
+ case WAIT_TIMEOUT:
+ throw TimeoutException();
+ break;
+ //case WAIT_OBJECT_0:
+ //break;
+ }
+ }
+
+ void reset()
+ {
+ ::ResetEvent(event);
+ }
+
+
+
+ HANDLE event;
+};
+
+
+
+// ------------------------------------
+typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *);
+typedef unsigned int THREAD_HANDLE;
+#define THREAD_PROC int WINAPI
+#define vsnprintf _vsnprintf
+
+// ------------------------------------
+class WLock
+{
+public:
+ WLock()
+ {
+ InitializeCriticalSection(&cs);
+ }
+
+
+ void on()
+ {
+ EnterCriticalSection(&cs);
+ }
+
+ void off()
+ {
+ LeaveCriticalSection(&cs);
+ }
+
+ CRITICAL_SECTION cs;
+};
+#endif
+
+
+#ifdef _UNIX
+// ------------------------------------
+#include <pthread.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#include <sched.h>
+#define _BIG_ENDIAN 1
+#endif
+
+typedef long long int64_t;
+
+typedef int (*THREAD_FUNC)(ThreadInfo *);
+#define THREAD_PROC int
+typedef pthread_t THREAD_HANDLE;
+
+// ------------------------------------
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+
+ WEvent()
+ {
+ }
+
+ void signal()
+ {
+ }
+
+ void wait(int timeout = 30000)
+ {
+ }
+
+ void reset()
+ {
+ }
+
+};
+
+// ------------------------------------
+class WLock
+{
+private:
+ pthread_mutex_t mutex;
+public:
+ WLock()
+ {
+ const pthread_mutexattr_t mattr =
+ {
+#ifdef __APPLE__
+ PTHREAD_MUTEX_RECURSIVE
+#else
+ PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+ };
+
+ pthread_mutex_init( &mutex, &mattr );
+ }
+
+ ~WLock()
+ {
+ pthread_mutex_destroy( &mutex );
+ }
+
+
+ void on()
+ {
+ pthread_mutex_lock(&mutex);
+ }
+
+ void off()
+ {
+ pthread_mutex_unlock(&mutex);
+ }
+
+};
+#endif
+
+class WLockBlock
+{
+private:
+ WLock *lock;
+ bool flg;
+public:
+ WLockBlock(WLock *l){
+ lock = l;
+ flg = false;
+ }
+ ~WLockBlock(){
+ if (flg){
+ lock->off();
+ LOG_DEBUG("LOCK OFF by destructor");
+ }
+ }
+ void on(){
+ flg = true;
+ lock->on();
+ }
+ void off(){
+ flg = false;
+ lock->off();
+ }
+};
+
+// ------------------------------------
+class ThreadInfo
+{
+public:
+ //typedef int (__stdcall *THREAD_FUNC)(ThreadInfo *);
+
+ ThreadInfo()
+ {
+ active = false;
+ finish = false;
+ id = 0;
+ func = NULL;
+ data = NULL;
+ }
+
+ void shutdown();
+
+ volatile bool active;
+ volatile bool finish;
+ int id;
+ THREAD_FUNC func;
+ THREAD_HANDLE handle;
+
+
+ void *data;
+};
+
+
+// ------------------------------------
+class LogBuffer
+{
+public:
+ enum TYPE
+ {
+ T_NONE,
+ T_DEBUG,
+ T_ERROR,
+ T_NETWORK,
+ T_CHANNEL,
+ };
+
+ LogBuffer(int i, int l)
+ {
+ lineLen = l;
+ maxLines = i;
+ currLine = 0;
+ buf = new char[lineLen*maxLines];
+ times = new unsigned int [maxLines];
+ types = new TYPE [maxLines];
+ }
+
+ void clear()
+ {
+ currLine = 0;
+ }
+ void write(const char *, TYPE);
+ static const char *getTypeStr(TYPE t) {return logTypes[t];}
+ void dumpHTML(class Stream &);
+
+ char *buf;
+ unsigned int *times;
+ unsigned int currLine,maxLines,lineLen;
+ TYPE *types;
+ WLock lock;
+ static const char *logTypes[];
+
+};
+
+#define RWLOCK_READ_MAX 32
+
+class LockBlock
+{
+public:
+ LockBlock(WLock &l){ flg = false; lock = l; }
+ ~LockBlock(){ if (flg) lock.off(); }
+ void lockon(){ flg = true; lock.on(); }
+ void lockoff(){ flg = false; lock.off(); }
+
+private:
+ WLock lock;
+ bool flg;
+};
+
+// ------------------------------------
+extern Sys *sys;
+
+// ------------------------------------
+
+
+#if _BIG_ENDIAN
+#define CHECK_ENDIAN2(v) v=SWAP2(v)
+#define CHECK_ENDIAN3(v) v=SWAP3(v)
+#define CHECK_ENDIAN4(v) v=SWAP4(v)
+#else
+#define CHECK_ENDIAN2
+#define CHECK_ENDIAN3
+#define CHECK_ENDIAN4
+#endif
+
+
+// ------------------------------------
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "url.h"
+#include "socket.h"
+#include "http.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void URLSource::stream(Channel *ch)
+{
+
+ String url,tmpUrl;
+ while (ch->thread.active && !peercastInst->isQuitting)
+ {
+ tmpUrl = url;
+ if (url.isEmpty())
+ url = baseurl;
+
+ url = streamURL(ch,url.cstr());
+ if (url == tmpUrl){
+ sys->sleep(2000);
+ }
+ }
+
+}
+// ------------------------------------------------
+int URLSource::getSourceRate()
+{
+ if (inputStream)
+ return inputStream->bytesInPerSec;
+ else
+ return 0;
+}
+
+// ------------------------------------------------
+::String URLSource::streamURL(Channel *ch, const char *url)
+{
+ String nextURL;
+
+ if (peercastInst->isQuitting || !ch->thread.active)
+ return nextURL;
+
+
+ String urlTmp;
+ urlTmp.set(url);
+
+ char *fileName = urlTmp.cstr();
+
+ PlayList *pls=NULL;
+ ChannelStream *source=NULL;
+
+ LOG_CHANNEL("Fetch URL=%s",fileName);
+
+ try
+ {
+
+ // get the source protocol
+ if (strnicmp(fileName,"http://",7)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_HTTP;
+ fileName += 7;
+ }
+ else if (strnicmp(fileName,"mms://",6)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+ fileName += 6;
+ }
+ else if (strnicmp(fileName,"pcp://",6)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_PCP;
+ fileName += 6;
+ }
+ else if (strnicmp(fileName,"file://",7)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_FILE;
+ fileName += 7;
+ }
+ else
+ {
+ ch->info.srcProtocol = ChanInfo::SP_FILE;
+ }
+
+ // default to mp3 for shoutcast servers
+ if (ch->info.contentType == ChanInfo::T_PLS)
+ ch->info.contentType = ChanInfo::T_MP3;
+
+
+ ch->setStatus(Channel::S_CONNECTING);
+
+ if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
+ {
+
+ if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+
+
+ LOG_CHANNEL("Channel source is HTTP");
+
+ ClientSocket *inputSocket = sys->createSocket();
+ if (!inputSocket)
+ throw StreamException("Channel cannot create socket");
+
+
+ inputStream = inputSocket;
+
+
+ char *dir = strstr(fileName,"/");
+ if (dir)
+ *dir++=0;
+
+
+ LOG_CHANNEL("Fetch Host=%s",fileName);
+ if (dir)
+ LOG_CHANNEL("Fetch Dir=%s",dir);
+
+
+ Host host;
+ host.fromStrName(fileName,80);
+
+ inputSocket->open(host);
+ inputSocket->connect();
+
+ HTTP http(*inputSocket);
+ http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
+
+ http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
+ http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+
+ if (ch->info.srcProtocol == ChanInfo::SP_MMS)
+ {
+ http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
+ http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
+ //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
+ http.writeLine("Pragma: xPlayStrm=1");
+ http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
+ http.writeLine("Pragma: stream-switch-count=2");
+ http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
+ }else
+ {
+ http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+ http.writeLineF("%s %d",PCX_HS_PCP,1);
+ http.writeLine("Icy-MetaData:1"); // fix by ravon
+ }
+
+ http.writeLine("");
+
+ int res = http.readResponse();
+
+
+ String name = ch->info.name;
+
+ while (http.nextHeader())
+ {
+
+ LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
+
+ ChanInfo tmpInfo = ch->info;
+ Servent::readICYHeader(http,ch->info,NULL);
+
+ if (!tmpInfo.name.isEmpty())
+ ch->info.name = tmpInfo.name;
+ if (!tmpInfo.genre.isEmpty())
+ ch->info.genre = tmpInfo.genre;
+ if (!tmpInfo.url.isEmpty())
+ ch->info.url = tmpInfo.url;
+
+ if (http.isHeader("icy-metaint"))
+ ch->icyMetaInterval = http.getArgInt();
+ else if (http.isHeader("Location:"))
+ nextURL.set(http.getArgStr());
+
+ char *arg = http.getArgStr();
+ if (arg)
+ {
+ if (http.isHeader("content-type"))
+ {
+ if (stristr(arg,MIME_XSCPLS))
+ pls = new PlayList(PlayList::T_SCPLS, 1000);
+ else if (stristr(arg,MIME_PLS))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_XPLS))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_M3U))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_TEXT))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_ASX))
+ pls = new PlayList(PlayList::T_ASX, 1000);
+ else if (stristr(arg,MIME_MMS))
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+ }
+ }
+
+ }
+
+ if ((!nextURL.isEmpty()) && (res==302))
+ {
+ LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
+ inputSocket->close();
+ delete inputSocket;
+ inputSocket = NULL;
+ return nextURL;
+ }
+
+ if (res!=200)
+ {
+ LOG_ERROR("HTTP response: %d",res);
+ throw StreamException("Bad HTTP connect");
+ }
+
+
+ }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
+ {
+
+ LOG_CHANNEL("Channel source is FILE");
+
+ FileStream *fs = new FileStream();
+ fs->openReadOnly(fileName);
+ inputStream = fs;
+
+ ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
+ // if filetype is unknown, try and figure it out from file extension.
+ //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
+ {
+ const char *ext = fileName+strlen(fileName);
+ while (*--ext)
+ if (*ext=='.')
+ {
+ ext++;
+ break;
+ }
+
+ fileType = ChanInfo::getTypeFromStr(ext);
+ }
+
+
+ if (ch->info.bitrate)
+ ch->readDelay = true;
+
+
+ if (fileType == ChanInfo::T_PLS)
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (fileType == ChanInfo::T_ASX)
+ pls = new PlayList(PlayList::T_ASX, 1000);
+ else
+ ch->info.contentType = fileType;
+
+ }else
+ {
+ throw StreamException("Unsupported URL");
+ }
+
+
+ if (pls)
+ {
+
+ LOG_CHANNEL("Channel is Playlist");
+
+ pls->read(*inputStream);
+
+ inputStream->close();
+ delete inputStream;
+ inputStream = NULL;
+
+ int urlNum=0;
+ String url;
+
+ LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
+ while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
+ {
+ if (url.isEmpty())
+ {
+ url = pls->urls[urlNum%pls->numURLs];
+ urlNum++;
+ }
+ try
+ {
+ url = streamURL(ch,url.cstr());
+ }catch(StreamException &)
+ {}
+ }
+
+ delete pls;
+
+ }else
+ {
+
+ // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
+ if (!ch->info.id.isSet())
+ {
+ ch->info.id = chanMgr->broadcastID;
+ ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
+ }
+
+ if (ch->info.contentType == ChanInfo::T_ASX)
+ ch->info.contentType = ChanInfo::T_WMV;
+
+ ch->setStatus(Channel::S_BROADCASTING);
+
+ inputStream->setReadTimeout(60); // use longer read timeout
+
+ source = ch->createSource();
+
+ ch->readStream(*inputStream,source);
+
+ inputStream->close();
+ }
+
+ }catch(StreamException &e)
+ {
+ ch->setStatus(Channel::S_ERROR);
+ LOG_ERROR("Channel error: %s",e.msg);
+ sys->sleep(1000);
+ }
+
+
+ ch->setStatus(Channel::S_CLOSING);
+ if (inputStream)
+ {
+ delete inputStream;
+ inputStream = NULL;
+ }
+
+ if (source)
+ delete source;
+
+
+ return nextURL;
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _URL_H
+#define _URL_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class URLSource : public ChannelSource
+{
+public:
+ URLSource(const char *url)
+ :inputStream(NULL)
+ {
+ baseurl.set(url);
+ }
+
+ ::String streamURL(Channel *, const char *);
+
+ virtual void stream(Channel *);
+
+ virtual int getSourceRate();
+
+
+ Stream *inputStream;
+ ::String baseurl;
+};
+
+
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+#include "identify_encoding.h"
+#ifdef _WIN32
+
+/* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+ int size = 0, index = 0, out_index = 0;
+ unsigned char *out;
+ unsigned short c;
+
+ /* first calculate the size of the target string */
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x0080)
+ {
+ size += 1;
+ }
+ else if (c < 0x0800)
+ {
+ size += 2;
+ }else{
+ size += 3;
+ }
+ c = unicode[index++];
+ }
+
+ out = (unsigned char *)malloc(size + 1);
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x080)
+ {
+ out[out_index++] = (unsigned char)c;
+ }else if (c < 0x800)
+ {
+ out[out_index++] = 0xc0 | (c >> 6);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }else{
+ out[out_index++] = 0xe0 | (c >> 12);
+ out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ c = unicode[index++];
+ }
+ out[out_index] = 0x00;
+
+ return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+ int size = 0, index = 0, out_index = 0;
+ wchar_t *out;
+ unsigned char c;
+
+ /* first calculate the size of the target string */
+ c = utf8[index++];
+ while (c)
+ {
+ if ((c & 0x80) == 0)
+ {
+ index += 0;
+ }else if((c & 0xe0) == 0xe0)
+ {
+ index += 2;
+ }else{
+ index += 1;
+ }
+ size += 1;
+ c = utf8[index++];
+ }
+
+ out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = utf8[index++];
+ while (c)
+ {
+ if ((c & 0x80) == 0)
+ {
+ out[out_index++] = c;
+ }else if ((c & 0xe0) == 0xe0)
+ {
+ out[out_index] = (c & 0x1F) << 12;
+ c = utf8[index++];
+ out[out_index] |= (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }else{
+ out[out_index] = (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ c = utf8[index++];
+ }
+ out[out_index] = 0;
+
+ return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int wchars, err;
+
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlen(from), NULL, 0);
+
+ if(wchars == 0)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
+ if(unicode == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string to UTF8\n");
+ return -1;
+ }
+
+ err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars);
+ if (err != wchars)
+ {
+ free(unicode);
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ /* On NT-based windows systems, we could use WideCharToMultiByte(), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ *to = (char *)make_utf8_string(unicode);
+
+ free(unicode);
+ return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int chars, err;
+
+ const char *cds;
+ identify_encoding_t *cdt;
+ enum identify_encoding_order order;
+ order = ieo_SJIS;
+ cdt = identify_encoding_open(order);
+ cds = identify_encoding(cdt,(char *)from);
+ if (strcmp(cds,"UTF-8")!=0)
+ {
+ identify_encoding_close(cdt);
+ return -1;
+ }
+ identify_encoding_close(cdt);
+
+
+ /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ unicode = (wchar_t *)make_unicode_string((const unsigned char *)from);
+ if (unicode == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return -1;
+ }
+
+ chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+
+ if (chars == 0)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ return -1;
+ }
+
+ *to = (char *)calloc(chars + 1, sizeof(unsigned char));
+ if (*to == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string to local charset\n");
+ free(unicode);
+ return -1;
+ }
+
+ err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+ if (err != chars)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ free(*to);
+ *to = NULL;
+ return -1;
+ }
+
+ free(unicode);
+ return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen);
+
+static char *current_charset = 0; /* means "US-ASCII" */
+
+void convert_set_charset(const char *charset)
+{
+
+ if (!charset)
+ charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+ if (!charset)
+ charset = nl_langinfo(CODESET);
+#endif
+
+ free(current_charset);
+ current_charset = 0;
+ if (charset && *charset)
+ current_charset = strdup(charset);
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = -1;
+
+#ifdef HAVE_ICONV
+ ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+ ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+ return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+ const char *from, char **to, char replace)
+{
+ int ret;
+ size_t fromlen;
+ char *s;
+
+ fromlen = strlen(from);
+ ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+ if (ret == -2)
+ return -1;
+ if (ret != -1)
+ return ret;
+
+ s = malloc(fromlen + 1);
+ if (!s)
+ return -1;
+ strcpy(s, from);
+ *to = s;
+ for (; *s; s++)
+ if (*s & ~0x7f)
+ *s = replace;
+ return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ char *charset;
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string(charset, "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ char *charset;
+
+ if (*from == 0)
+ {
+ *to = malloc(1);
+ **to = 0;
+ return 1;
+ }
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string("UTF-8", charset, from, to, '?');
+}
+
+#endif
--- /dev/null
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ * -1 : memory allocation failed
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ * 3 : unknown encoding (but still converted, using '?')
+ */
+
+#ifndef __UTF8_H
+#define __UTF8_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void convert_set_charset(const char *charset);
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTF8_H */
--- /dev/null
+// ------------------------------------------------
+// File : version2.h
+// Date: 17-june-2005
+// Author: giles
+//
+// (c) 2005 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _VERSION2_H
+#define _VERSION2_H
+
+// ------------------------------------------------
+#ifdef PRIVATE_BROADCASTER
+static const char PCP_BROADCAST_FLAGS = 0x01;
+static bool PCP_FORCE_YP = true;
+#else
+static const char PCP_BROADCAST_FLAGS = 0x00;
+static bool PCP_FORCE_YP = false;
+#endif
+// ------------------------------------------------
+static const int PCP_CLIENT_VERSION = 1217;
+static const int PCP_CLIENT_VERSION_VP = 23;
+static const int PCP_ROOT_VERSION = 1212;
+
+static const int PCP_CLIENT_MINVERSION = 1200;
+
+static const char *PCX_AGENT = "PeerCast/0.1217";
+static const char *PCX_AGENTJP = "PeerCast/0.1217-J";
+static const char *PCX_AGENTVP = "PeerCast/0.1217(VP0023)";
+static const char *PCX_VERSTRING = "v0.1217(VP0023)";
+
+#if 1 /* for VP extend version */
+#define VERSION_EX 1
+static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only
+static const int PCP_CLIENT_VERSION_EX_NUMBER = 7651;
+static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)";
+static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)";
+#endif
+
+// ------------------------------------------------
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : xml.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Basic XML parsing/creation
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "xml.h"
+#include "stream.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ----------------------------------
+void XML::Node::add(Node *n)
+{
+ if (!n)
+ return;
+
+ n->parent = this;
+
+ if (child)
+ {
+ // has children, add to last sibling
+ Node *s = child;
+ while (s->sibling)
+ s = s->sibling;
+ s->sibling = n;
+
+ }else{
+ // no children yet
+ child = n;
+ }
+}
+// ---------------------------------
+inline char nibsToByte(char n1, char n2)
+{
+ if (n1 >= 'A') n1 = n1-'A'+10;
+ else n1 = n1-'0';
+ if (n2 >= 'A') n2 = n2-'A'+10;
+ else n2 = n2-'0';
+
+ return ((n2&0xf)<<4)|(n1&0xf);
+}
+
+// ----------------------------------
+int XML::Node::getBinaryContent(void *ptr, int size)
+{
+ char *in = contData;
+ char *out = (char *)ptr;
+
+ int i=0;
+ while (*in)
+ {
+ if (isWhiteSpace(*in))
+ {
+ in++;
+ }else
+ {
+ if (i >= size)
+ throw StreamException("Too much binary data");
+ out[i++] = nibsToByte(in[0],in[1]);
+ in+=2;
+ }
+ }
+ return i;
+}
+// ----------------------------------
+void XML::Node::setBinaryContent(void *ptr, int size)
+{
+ const char hexTable[] = "0123456789ABCDEF";
+ const int lineWidth = 1023;
+
+ contData = new char[size*2+1+(size/lineWidth)];
+
+ char *bp = (char *)ptr;
+ register char *ap = contData;
+
+ for(register int i=0; i<size; i++)
+ {
+ register char c = bp[i];
+ *ap++ = hexTable[c&0xf];
+ *ap++ = hexTable[(c>>4)&0xf];
+ if ((i&lineWidth)==lineWidth)
+ *ap++ = '\n';
+ }
+ ap[0] = 0;
+}
+
+
+// ----------------------------------
+void XML::Node::setContent(const char *n)
+{
+ contData = strdup(n);
+}
+// ----------------------------------
+void XML::Node::setAttributes(const char *n)
+{
+ char c;
+
+ attrData = strdup(n);
+
+ // count maximum amount of attributes
+ int maxAttr = 1; // 1 for tag name
+ bool inQ = false;
+ int i=0;
+ while ((c=attrData[i++])!=0)
+ {
+ if (c=='\"')
+ inQ ^= true;
+
+ if (!inQ)
+ if (c=='=')
+ maxAttr++;
+ }
+
+
+ attr = new Attribute[maxAttr];
+
+ attr[0].namePos = 0;
+ attr[0].valuePos = 0;
+
+ numAttr=1;
+
+ i=0;
+
+ // skip until whitespace
+ while (c=attrData[i++])
+ if (isWhiteSpace(c))
+ break;
+
+ if (!c) return; // no values
+
+ attrData[i-1]=0;
+
+
+ while ((c=attrData[i])!=0)
+ {
+ if (!isWhiteSpace(c))
+ {
+ if (numAttr>=maxAttr)
+ throw StreamException("Too many attributes");
+
+ // get start of tag name
+ attr[numAttr].namePos = i;
+
+
+ // skip whitespaces until next '='
+ // terminate name on next whitespace or '='
+ while (attrData[i])
+ {
+ c = attrData[i++];
+
+ if ((c == '=') || isWhiteSpace(c))
+ {
+ attrData[i-1] = 0; // null term. name
+ if (c == '=')
+ break;
+ }
+ }
+
+ // skip whitespaces
+ while (attrData[i])
+ {
+ if (isWhiteSpace(attrData[i]))
+ i++;
+ else
+ break;
+ }
+
+ // check for valid start of attribute value - '"'
+ if (attrData[i++] != '\"')
+ throw StreamException("Bad tag value");
+
+ attr[numAttr++].valuePos = i;
+
+ // terminate attribute value at next '"'
+
+ while (attrData[i])
+ if (attrData[i++] == '\"')
+ break;
+
+ attrData[i-1] = 0; // null term. value
+
+
+ }else{
+ i++;
+ }
+ }
+}
+// ----------------------------------
+XML::Node::Node(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[8192];
+ vsprintf(tmp,fmt,ap);
+ setAttributes(tmp);
+
+ va_end(ap);
+ init();
+}
+
+// ----------------------------------
+void XML::Node::init()
+{
+ parent = sibling = child = NULL;
+ contData = NULL;
+ userPtr = NULL;
+}
+// ----------------------------------
+int XML::Node::findAttrInt(const char *name)
+{
+ char *v = findAttr(name);
+ if (!v) return 0;
+ return atoi(v);
+}
+// ----------------------------------
+int XML::Node::findAttrID(const char *name)
+{
+ char *v = findAttr(name);
+ if (!v) return 0;
+ return strToID(v);
+}
+// ----------------------------------
+char *XML::Node::findAttr(const char *name)
+{
+ int nlen = strlen(name);
+ for(int i=1; i<numAttr; i++)
+ {
+ char *an = getAttrName(i);
+ if (strnicmp(an,name,nlen)==0)
+ return getAttrValue(i);
+ }
+ return NULL;
+}
+// ----------------------------------
+void XML::Node::write(Stream &out, int level)
+{
+ int i;
+#if 0
+ char tabs[64];
+
+ for(i=0; i<level; i++)
+ tabs[i] = ' ';
+ tabs[i] = '\0';
+
+
+ if (level)
+ out.write(tabs,i);
+#endif
+ char *name = getAttrValue(0);
+
+ out.write("<",1);
+ out.write(name,strlen(name));
+
+ for(i=1; i<numAttr; i++)
+ {
+ out.write(" ",1);
+ char *at = getAttrName(i);
+ out.write(at,strlen(at));
+
+ out.write("=\"",2);
+ char *av = getAttrValue(i);
+ out.write(av,strlen(av));
+ out.write("\"",1);
+ }
+
+ if ((!contData) && (!child))
+ {
+ out.write("/>\n",3);
+ }else
+ {
+ out.write(">\n",2);
+
+ if (contData)
+ out.write(contData,strlen(contData));
+
+ if (child)
+ child->write(out,level+1);
+#if 0
+ if (level)
+ out.write(tabs,strlen(tabs));
+#endif
+ out.write("</",2);
+ out.write(name,strlen(name));
+ out.write(">\n",2);
+ }
+
+ if (sibling)
+ sibling->write(out,level);
+}
+// ----------------------------------
+XML::Node::~Node()
+{
+// LOG("delete %s",getName());
+
+ if (contData)
+ delete [] contData;
+ if (attrData)
+ delete [] attrData;
+ if (attr)
+ delete [] attr;
+
+ Node *n = child;
+ while (n)
+ {
+ Node *nn = n->sibling;
+ delete n;
+ n = nn;
+ }
+}
+
+
+// ----------------------------------
+XML::~XML()
+{
+ if (root)
+ delete root;
+}
+
+// ----------------------------------
+void XML::write(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
+ root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeCompact(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ out.writeLine("<?xml ?>");
+ root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeHTML(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ root->write(out,1);
+}
+
+// ----------------------------------
+void XML::setRoot(Node *n)
+{
+ root=n;
+}
+
+
+// ----------------------------------
+XML::Node *XML::findNode(const char *n)
+{
+ if (root)
+ return root->findNode(n);
+ else
+ return NULL;
+}
+
+
+// ----------------------------------
+XML::Node *XML::Node::findNode(const char *name)
+{
+ if (stricmp(getName(),name)==0)
+ return this;
+
+ XML::Node *c = child;
+
+ while (c)
+ {
+ XML::Node *fn = c->findNode(name);
+ if (fn)
+ return fn;
+ c=c->sibling;
+ }
+
+ return NULL;
+}
+
+// ----------------------------------
+void XML::read(Stream &in)
+{
+ const int BUFFER_LEN = 100*1024;
+ static char buf[BUFFER_LEN];
+
+ Node *currNode=NULL;
+ int tp=0;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '<')
+ {
+ if (tp && currNode) // check for content
+ {
+ buf[tp] = 0;
+ currNode->setContent(buf);
+ }
+ tp = 0;
+
+ // read to next '>'
+ while (!in.eof())
+ {
+ c = in.readChar();
+ if (c == '>')
+ break;
+
+ if (tp >= BUFFER_LEN)
+ throw StreamException("Tag too long");
+
+ buf[tp++] = c;
+ }
+ buf[tp]=0;
+
+ if (buf[0] == '!') // comment
+ {
+ // do nothing
+ }else if (buf[0] == '?') // doc type
+ {
+ if (strnicmp(&buf[1],"xml ",4))
+ throw StreamException("Not XML document");
+ }else if (buf[0] == '/') // end tag
+ {
+ if (!currNode)
+ throw StreamException("Unexpected end tag");
+ currNode = currNode->parent;
+ }else // new tag
+ {
+ //LOG("tag: %s",buf);
+
+ bool singleTag = false;
+
+ if (buf[tp-1] == '/') // check for single tag
+ {
+ singleTag = true;
+ buf[tp-1] = 0;
+ }
+
+ // only add valid tags
+ if (strlen(buf))
+ {
+ Node *n = new Node(buf);
+
+ if (currNode)
+ currNode->add(n);
+ else
+ setRoot(n);
+
+ if (!singleTag)
+ currNode = n;
+ }
+ }
+
+ tp = 0;
+ } else {
+
+ if (tp >= BUFFER_LEN)
+ throw StreamException("Content too big");
+
+ buf[tp++] = c;
+
+ }
+ }
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : xml.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _XML_H
+#define _XML_H
+
+//-----------------------
+#include "common.h"
+#include <stdarg.h>
+
+//-----------------------
+class Stream;
+
+//-----------------------
+class XML
+{
+public:
+ class Node
+ {
+ public:
+ class Attribute
+ {
+ public:
+ int namePos,valuePos;
+ };
+
+ Node(const char *,...);
+
+ void init();
+
+ ~Node();
+
+ void add(Node *);
+ void write(Stream &,int); // output, level
+ char *getName() {return getAttrName(0);}
+
+ char *getAttrValue(int i) {return &attrData[attr[i].valuePos];}
+ char *getAttrName(int i) {return &attrData[attr[i].namePos];}
+ char *getContent() {return contData; }
+ int getBinaryContent(void *, int);
+
+ void setAttributes(const char *);
+ void setContent(const char *);
+ void setBinaryContent(void *, int);
+
+ Node *findNode(const char *);
+ char *findAttr(const char *);
+ int findAttrInt(const char *);
+ int findAttrID(const char *);
+
+ char *contData,*attrData;
+
+ Attribute *attr;
+ int numAttr;
+
+ Node *child,*parent,*sibling;
+ void *userPtr;
+ };
+
+ XML()
+ {
+ root = NULL;
+ }
+
+ ~XML();
+
+ void setRoot(Node *n);
+ void write(Stream &);
+ void writeCompact(Stream &);
+ void writeHTML(Stream &);
+ void read(Stream &);
+ Node *findNode(const char *n);
+
+ Node *root;
+};
+#endif
--- /dev/null
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="corelib"
+ ProjectGUID="{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+ RootNamespace="corelib"
+ SccProjectName=""$/PeerCast.root/PeerCast", JCAAAAAA"
+ SccLocalPath="..\..\.."
+ SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Private Release|Win32"
+ OutputDirectory=".\corelib___Win32_Private_Release"
+ IntermediateDirectory=".\corelib___Win32_Private_Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PRIVATE_BROADCASTER"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\corelib___Win32_Private_Release/corelib.pch"
+ AssemblerListingLocation=".\corelib___Win32_Private_Release/"
+ ObjectFile=".\corelib___Win32_Private_Release/"
+ ProgramDataBaseFileName=".\corelib___Win32_Private_Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\corelib___Win32_Private_Release\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\corelib___Win32_Private_Release/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../,../../common,../../../ui/win32/simple"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Debug/corelib.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Debug\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/corelib.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Release\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Private Debug|Win32"
+ OutputDirectory=".\corelib___Win32_Private_Debug"
+ IntermediateDirectory=".\corelib___Win32_Private_Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PRIVATE_BROADCASTER"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\corelib___Win32_Private_Debug/corelib.pch"
+ AssemblerListingLocation=".\corelib___Win32_Private_Debug/"
+ ObjectFile=".\corelib___Win32_Private_Debug/"
+ ProgramDataBaseFileName=".\corelib___Win32_Private_Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\corelib___Win32_Private_Debug\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\corelib___Win32_Private_Debug/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Core Source"
+ >
+ <File
+ RelativePath="..\..\common\channel.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\gnutella.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\html.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\http.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\icy.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\inifile.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\jis.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\mms.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\mp3.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\nsv.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\ogg.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\pcp.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\peercast.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\rtsp.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servent.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servhs.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servmgr.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\socket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\stats.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\stream.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\sys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\url.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\xml.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Core Includes"
+ >
+ <File
+ RelativePath="..\..\common\asf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\atom.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\channel.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\common.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\cstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\gnutella.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\html-xml.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\html.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\http.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\icy.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\id.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\inifile.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\jis.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\mms.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\mp3.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\nsv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\ogg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\pcp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\peercast.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\rtsp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\servent.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\servmgr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\socket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\stats.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\sys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\url.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\version2.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\xml.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Win32 Source"
+ >
+ <File
+ RelativePath="..\wsocket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\wsys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Win32 Includes"
+ >
+ <File
+ RelativePath="..\wsocket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\wsys.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Unix Source"
+ >
+ <File
+ RelativePath="..\..\unix\usocket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\unix\usys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Unix Includes"
+ >
+ <File
+ RelativePath="..\..\unix\usocket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\unix\usys.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// ------------------------------------------------
+// File : wsocket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Windows version of ClientSocket. Handles the nitty gritty of actually
+// reading and writing TCP
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+// TODO: fix socket closing
+
+
+//#include "stdafx.h"
+//#include "winsock2.h"
+#include <windows.h>
+#include <stdio.h>
+#include "wsocket.h"
+#include "stats.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void WSAClientSocket::init()
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 2, 0 );
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 )
+ throw SockException("Unable to init sockets");
+
+ //LOG4("WSAStartup: OK");
+
+}
+// --------------------------------------------------
+bool ClientSocket::getHostname(char *str,unsigned int ip)
+{
+ HOSTENT *he;
+
+ ip = htonl(ip);
+
+ he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+ if (he)
+ {
+ strcpy(str,he->h_name);
+ return true;
+ }else
+ return false;
+}
+
+unsigned int cache_ip = 0;
+unsigned int cache_time = 0;
+
+// --------------------------------------------------
+unsigned int ClientSocket::getIP(char *name)
+{
+ unsigned int ctime = sys->getTime();
+ bool null_flg = (name == NULL);
+
+ if (null_flg){
+ if ((cache_time != 0) && (cache_time + 60 > ctime)){
+ return cache_ip;
+ } else {
+ cache_time = 0;
+ cache_ip = 0;
+ }
+ }
+
+ char szHostName[256];
+
+ if (!name)
+ {
+ if (gethostname(szHostName, sizeof(szHostName))==0)
+ name = szHostName;
+ else
+ return 0;
+ }
+
+ HOSTENT *he = WSAClientSocket::resolveHost(name);
+
+ if (!he)
+ return 0;
+
+
+ LPSTR lpAddr = he->h_addr_list[0];
+ if (lpAddr)
+ {
+ unsigned int ret;
+ struct in_addr inAddr;
+ memmove (&inAddr, lpAddr, 4);
+
+ ret = inAddr.S_un.S_un_b.s_b1<<24 |
+ inAddr.S_un.S_un_b.s_b2<<16 |
+ inAddr.S_un.S_un_b.s_b3<<8 |
+ inAddr.S_un.S_un_b.s_b4;
+
+ if (null_flg){
+ cache_ip = ret;
+ cache_time = ctime;
+ }
+ return ret;
+ }
+ return 0;
+}
+// --------------------------------------------------
+void WSAClientSocket::setLinger(int sec)
+{
+ linger linger;
+ linger.l_onoff = (sec>0)?1:0;
+ linger.l_linger = sec;
+
+ if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1)
+ throw SockException("Unable to set LINGER");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBlocking(bool yes)
+{
+ unsigned long op = yes ? 0 : 1;
+ if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR)
+ throw SockException("Can`t set blocking");
+}
+// --------------------------------------------------
+void WSAClientSocket::setNagle(bool on)
+{
+ int nodelay = (on==false);
+ if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1)
+ throw SockException("Unable to set NODELAY");
+
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setReuse(bool yes)
+{
+ unsigned long op = yes ? 1 : 0;
+ if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1)
+ throw SockException("Unable to set REUSE");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBufSize(int size)
+{
+ int oldop;
+ int op = size;
+ int len = sizeof(op);
+ if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) {
+ LOG_DEBUG("Unable to get RCVBUF");
+ } else if (oldop < size) {
+ if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1)
+ LOG_DEBUG("Unable to set RCVBUF");
+ //else
+ // LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op);
+ }
+
+ if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) {
+ LOG_DEBUG("Unable to get SNDBUF");
+ } else if (oldop < size) {
+ if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1)
+ LOG_DEBUG("Unable to set SNDBUF");
+ //else
+ // LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op);
+ }
+}
+
+// --------------------------------------------------
+HOSTENT *WSAClientSocket::resolveHost(const char *hostName)
+{
+ HOSTENT *he;
+
+ if ((he = gethostbyname(hostName)) == NULL)
+ {
+ // if failed, try using gethostbyaddr instead
+
+ unsigned long ip = inet_addr(hostName);
+
+ if (ip == INADDR_NONE)
+ return NULL;
+
+ if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL)
+ return NULL;
+ }
+ return he;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::open(Host &rh)
+{
+ sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sockNum == INVALID_SOCKET)
+ throw SockException("Can`t open socket");
+
+ setBlocking(false);
+#ifdef DISABLE_NAGLE
+ setNagle(false);
+#endif
+ setBufSize(65535);
+
+ host = rh;
+
+ memset(&remoteAddr,0,sizeof(remoteAddr));
+
+ remoteAddr.sin_family = AF_INET;
+ remoteAddr.sin_port = htons(host.port);
+ remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip);
+
+}
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout(bool r, bool w)
+{
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK)
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+
+ }else{
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout2(bool r, bool w)
+{
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+ }
+}
+
+// --------------------------------------------------
+Host WSAClientSocket::getLocalHost()
+{
+ struct sockaddr_in localAddr;
+
+ int len = sizeof(localAddr);
+ if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0)
+ return Host(SWAP4(localAddr.sin_addr.s_addr),0);
+ else
+ return Host(0,0);
+}
+
+// --------------------------------------------------
+void WSAClientSocket::connect()
+{
+ if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR)
+ checkTimeout(false,true);
+
+}
+// --------------------------------------------------
+int WSAClientSocket::read(void *p, int l)
+{
+ int bytesRead=0;
+
+ while (l)
+ {
+ if (rbDataSize >= l) {
+ memcpy(p, &apReadBuf[rbPos], l);
+ rbPos += l;
+ rbDataSize -= l;
+ return l;
+ } else if (rbDataSize > 0) {
+ memcpy(p, &apReadBuf[rbPos], rbDataSize);
+ p = (char *) p + rbDataSize;
+ l -= rbDataSize;
+ bytesRead += rbDataSize;
+ }
+
+ rbPos = 0;
+ rbDataSize = 0;
+ //int r = recv(sockNum, (char *)p, l, 0);
+ int r = recv(sockNum, apReadBuf, RBSIZE, 0);
+ if (r == SOCKET_ERROR)
+ {
+ // non-blocking sockets always fall through to here
+ checkTimeout(true,false);
+
+ }else if (r == 0)
+ {
+ throw EOFException("Closed on read");
+
+ }else
+ {
+ stats.add(Stats::BYTESIN,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESIN,r);
+ updateTotals(r,0);
+ //bytesRead += r;
+ //l -= r;
+ //p = (char *)p+r;
+
+ rbDataSize += r;
+ }
+ }
+ return bytesRead;
+}
+// --------------------------------------------------
+int WSAClientSocket::readUpto(void *p, int l)
+{
+ int bytesRead=0;
+ while (l)
+ {
+ int r = recv(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR)
+ {
+ // non-blocking sockets always fall through to here
+ //checkTimeout(true,false);
+ return r;
+
+ }else if (r == 0)
+ {
+ break;
+ }else
+ {
+ stats.add(Stats::BYTESIN,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESIN,r);
+ updateTotals(r,0);
+ bytesRead += r;
+ l -= r;
+ p = (char *)p+r;
+ }
+ if (bytesRead) break;
+ }
+ return bytesRead;
+}
+
+
+// --------------------------------------------------
+void WSAClientSocket::write(const void *p, int l)
+{
+ while (l)
+ {
+ int r = send(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR)
+ {
+ checkTimeout(false,true);
+ }
+ else if (r == 0)
+ {
+ throw SockException("Closed on write");
+ }
+ else
+ if (r > 0)
+ {
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+ l -= r;
+ p = (char *)p+r;
+ }
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bufferingWrite(const void *p, int l)
+{
+ if (bufList.isNull() && p != NULL){
+ while(l){
+ int r = send(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR){
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK){
+ bufList.add(p, l);
+// LOG_DEBUG("normal add");
+ break;
+ } else {
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+ } else if (r == 0) {
+ throw SockException("Closed on write");
+ } else if (r > 0){
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+ l -= r;
+ p = (char *)p+r;
+ }
+ }
+ } else {
+// LOG_DEBUG("***************BufferingWrite");
+ if (p)
+ bufList.add(p,l);
+
+ bool flg = true;
+
+ while(flg){
+ SocketBuffer *tmp;
+ tmp = bufList.getTop();
+
+ if (tmp){
+// LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp);
+ while(tmp->pos < tmp->len){
+ int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0);
+// LOG_DEBUG("send = %d", r);
+ if (r == SOCKET_ERROR){
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK){
+ flg = false;
+ break;
+ } else {
+ bufList.clear();
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+ } else if (r == 0){
+ bufList.clear();
+ throw SockException("Closed on write");
+ } else if (r > 0){
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+
+ tmp->pos += r;
+ if (tmp->pos >= tmp->len){
+// LOG_DEBUG("deleteTop");
+ bufList.deleteTop();
+ break;
+ }
+ }
+ }
+ } else {
+ flg = false;
+ }
+ }
+// LOG_DEBUG("bufferingWrite end");
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkBuffering(bool r, bool w)
+{
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK)
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+
+ }else{
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bind(Host &h)
+{
+ struct sockaddr_in localAddr;
+
+ if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ throw SockException("Can`t open socket");
+
+ setBlocking(false);
+ setReuse(true);
+
+ memset(&localAddr,0,sizeof(localAddr));
+ localAddr.sin_family = AF_INET;
+ localAddr.sin_port = htons(h.port);
+ localAddr.sin_addr.s_addr = INADDR_ANY;
+
+ if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1)
+ throw SockException("Can`t bind socket");
+
+ if (::listen(sockNum,SOMAXCONN))
+ throw SockException("Can`t listen",WSAGetLastError());
+
+ host = h;
+}
+// --------------------------------------------------
+ClientSocket *WSAClientSocket::accept()
+{
+
+ int fromSize = sizeof(sockaddr_in);
+ sockaddr_in from;
+
+ int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize);
+
+
+ if (conSock == INVALID_SOCKET)
+ return NULL;
+
+
+ WSAClientSocket *cs = new WSAClientSocket();
+ cs->sockNum = conSock;
+
+ cs->host.port = from.sin_port;
+ cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |
+ from.sin_addr.S_un.S_un_b.s_b2<<16 |
+ from.sin_addr.S_un.S_un_b.s_b3<<8 |
+ from.sin_addr.S_un.S_un_b.s_b4;
+
+
+ cs->setBlocking(false);
+#ifdef DISABLE_NAGLE
+ cs->setNagle(false);
+#endif
+ cs->setBufSize(65535);
+
+ return cs;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::close()
+{
+ sockLock.on();
+ if (sockNum)
+ {
+// shutdown(sockNum,SD_SEND);
+
+ setReadTimeout(2000);
+ unsigned int stime = sys->getTime();
+ try
+ {
+ char c[1024];
+ while (readUpto(&c,1024) > 0)
+ if (sys->getTime() - stime > 5) break;
+ //readUpto(&c,1);
+ }catch(StreamException &) {}
+
+ if (closesocket (sockNum))
+ LOG_ERROR("closesocket() error");
+
+
+ sockNum=0;
+ }
+ sockLock.off();
+}
+
+// --------------------------------------------------
+bool WSAClientSocket::readReady()
+{
+ if (rbDataSize) return true;
+
+ timeval timeout;
+ fd_set read_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&read_fds);
+ FD_SET (sockNum, &read_fds);
+
+ return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1;
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : wsocket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// see .cpp for details
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _WSOCKET_H
+#define _WSOCKET_H
+
+#include <windows.h>
+#include "socket.h"
+//#include "winsock2.h"
+
+
+// --------------------------------------------------
+class WSAClientSocket : public ClientSocket
+{
+public:
+ static void init();
+
+ WSAClientSocket()
+ :sockNum(0)
+ ,writeCnt(0)
+ ,rbPos(0)
+ ,rbDataSize(0)
+ {
+ }
+
+ ~WSAClientSocket(){
+ bufList.clear();
+ }
+
+ virtual void open(Host &);
+ virtual int read(void *, int);
+ virtual int readUpto(void *, int);
+ virtual void write(const void *, int);
+ virtual void bind(Host &);
+ virtual void connect();
+ virtual void close();
+ virtual ClientSocket * accept();
+ virtual bool active() {return sockNum != 0;}
+ virtual bool readReady();
+ virtual Host getLocalHost();
+ virtual void setBlocking(bool);
+ void setReuse(bool);
+ void setNagle(bool);
+ void setLinger(int);
+ void setBufSize(int size);
+
+// static HOSTENT *resolveHost(const char *);
+ static hostent *resolveHost(const char *);
+
+ void checkTimeout(bool,bool);
+ void checkTimeout2(bool,bool);
+
+ virtual void bufferingWrite(const void*, int);
+ void checkBuffering(bool, bool);
+
+ unsigned int writeCnt;
+ unsigned int sockNum;
+ struct sockaddr_in remoteAddr;
+
+ enum {RBSIZE = 8192};
+ char apReadBuf[RBSIZE];
+ int rbPos;
+ int rbDataSize;
+
+ WLock sockLock;
+};
+
+#endif
+
\ No newline at end of file
--- /dev/null
+// ------------------------------------------------
+// File : wsys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+//#include "stdafx.h"
+#include <process.h>
+#include <windows.h>
+#include <time.h>
+#include "win32/wsys.h"
+#include "win32/wsocket.h"
+#include "stats.h"
+#include "peercast.h"
+#include <sys/timeb.h>
+#include <time.h>
+#include "shellapi.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------------
+WSys::WSys(HWND w)
+{
+ stats.clear();
+
+ rndGen.setSeed(getTime());
+
+ mainWindow = w;
+ WSAClientSocket::init();
+
+ rndSeed = rnd();
+}
+// ---------------------------------
+double WSys::getDTime()
+{
+ struct _timeb timebuffer;
+
+ _ftime( &timebuffer );
+
+ return (double)timebuffer.time+(((double)timebuffer.millitm)/1000);
+}
+// ---------------------------------
+unsigned int WSys::getTime()
+{
+ time_t ltime;
+ time( <ime );
+ return ltime;
+}
+
+// ---------------------------------
+ClientSocket *WSys::createSocket()
+{
+ return new WSAClientSocket();
+}
+// ---------------------------------
+void WSys::endThread(ThreadInfo *info)
+{
+}
+// ---------------------------------
+void WSys::waitThread(ThreadInfo *info, int timeout)
+{
+ switch(WaitForSingleObject((void *)info->handle, timeout))
+ {
+ case WAIT_TIMEOUT:
+ throw TimeoutException();
+ break;
+ }
+}
+
+
+// ---------------------------------
+bool WSys::startThread(ThreadInfo *info)
+{
+ info->active = true;
+
+/* typedef unsigned ( __stdcall *start_address )( void * );
+
+ unsigned int threadID;
+ info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID );
+
+ if(info->handle == 0)
+ return false;*/
+
+ typedef void (__cdecl *start_address)( void * );
+ info->handle = _beginthread((start_address)info->func, 0,info);
+
+ if(info->handle == -1)
+ return false;
+
+ return true;
+
+}
+// ---------------------------------
+void WSys::sleep(int ms)
+{
+ Sleep(ms);
+}
+
+// ---------------------------------
+void WSys::appMsg(long msg, long arg)
+{
+ //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg);
+}
+
+// --------------------------------------------------
+void WSys::callLocalURL(const char *str,int port)
+{
+ char cmd[512];
+ sprintf(cmd,"http://localhost:%d/%s",port,str);
+ ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL);
+}
+
+// ---------------------------------
+void WSys::getURL(const char *url)
+{
+ if (mainWindow)
+ if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7))
+ ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL);
+}
+// ---------------------------------
+void WSys::exit()
+{
+ if (mainWindow)
+ PostMessage(mainWindow,WM_CLOSE,0,0);
+ else
+ ::exit(0);
+}
+// --------------------------------------------------
+void WSys::executeFile(const char *file)
+{
+ ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL);
+}
--- /dev/null
+// ------------------------------------------------
+// File : wsys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+#ifndef _WSYS_H
+#define _WSYS_H
+// ------------------------------------
+#include <windows.h>
+#include "socket.h"
+#include "sys.h"
+
+// ------------------------------------
+class WSys : public Sys
+{
+public:
+ WSys(HWND);
+
+ virtual ClientSocket *createSocket();
+ virtual bool startThread(ThreadInfo *);
+ virtual void sleep(int );
+ virtual void appMsg(long,long);
+ virtual unsigned int getTime();
+ virtual double getDTime();
+ virtual unsigned int rnd() {return rndGen.next();}
+ virtual void getURL(const char *);
+ virtual void exit();
+ virtual bool hasGUI() {return mainWindow!=NULL;}
+ virtual void callLocalURL(const char *str,int port);
+ virtual void executeFile(const char *);
+ virtual void endThread(ThreadInfo *);
+ virtual void waitThread(ThreadInfo *, int timeout = 30000);
+
+
+ HWND mainWindow;
+ peercast::Random rndGen;
+};
+
+
+// ------------------------------------
+#endif
+
+
+
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}"
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 3
+ SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA
+ SccLocalPath0 = ..\\..
+ SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
+ SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\
+ SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj
+ SccLocalPath1 = ..\\..
+ SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\
+ SccProjectUniqueName2 = simple\\Simple.vcproj
+ SccLocalPath2 = ..\\..
+ SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Private Debug|Win32 = Private Debug|Win32
+ Private Release|Win32 = Private Release|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// ------------------------------------------------
+// File : simple.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Simple tray icon interface to PeerCast, mostly win32 related stuff.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <windows.h>
+#include <direct.h>
+#include "stdafx.h"
+#include "resource.h"
+#include "gui.h"
+#include "channel.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "win32/wsys.h"
+#include "peercast.h"
+#include "simple.h"
+#include "version2.h"
+#include "gdiplus.h"
+#include "time.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+#define MAX_LOADSTRING 100
+
+#define PLAY_CMD 7000
+#define RELAY_CMD 8000
+#define INFO_CMD 9000
+#define URL_CMD 10000
+
+#define MAX_CHANNELS 999
+
+
+extern "C"
+{
+ void loadIcons(HINSTANCE hInstance, HWND hWnd);
+};
+
+UINT g_iTaskbarCreated = ~0; // for PCRaw (tray icon)
+
+// PeerCast globals
+
+static int currNotify=0;
+String iniFileName;
+HWND guiWnd;
+HWND mainWnd;
+static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon)
+bool showGUI=true;
+bool allowMulti=false;
+bool killMe=false;
+bool allowTrayMenu=true;
+static bool winDistinctionNT=false;
+int seenNewVersionTime=0;
+HICON icon1,icon2;
+ChanInfo chanInfo;
+bool chanInfoIsRelayed;
+//GnuID lastPlayID;
+String exePath;
+ULONG_PTR gdiplusToken;
+
+// ---------------------------------
+Sys * APICALL MyPeercastInst::createSys()
+{
+ return new WSys(mainWnd);
+}
+// ---------------------------------
+const char * APICALL MyPeercastApp ::getIniFilename()
+{
+ return iniFileName.cstr();
+}
+
+// ---------------------------------
+const char *APICALL MyPeercastApp ::getClientTypeOS()
+{
+ return PCX_OS_WIN32;
+}
+
+// ---------------------------------
+const char * APICALL MyPeercastApp::getPath()
+{
+ return exePath.cstr();
+}
+
+// --------------------------------- JP-EX
+void APICALL MyPeercastApp ::openLogFile()
+{
+ logFile.openWriteReplace("log.txt");
+}
+// --------------------------------- JP-EX
+void APICALL MyPeercastApp ::getDirectory()
+{
+ char path_buffer[256],drive[32],dir[128];
+ GetModuleFileName(NULL,path_buffer,255);
+ _splitpath(path_buffer,drive,dir,NULL,NULL);
+ sprintf(servMgr->modulePath,"%s%s",drive,dir);
+}
+// --------------------------------- JP-EX
+bool APICALL MyPeercastApp ::clearTemp()
+{
+ if (servMgr->clearPLS)
+ return true;
+
+ return false;
+}
+
+
+class NOTIFYICONDATA2
+{
+public:
+ DWORD cbSize; // DWORD
+ HWND hWnd; // HWND
+ UINT uID; // UINT
+ UINT uFlags; // UINT
+ UINT uCallbackMessage; // UINT
+ HICON hIcon; // HICON
+ char szTip[128]; // char[128]
+ DWORD dwState; // DWORD
+ DWORD dwStateMask; // DWORD
+ char szInfo[256]; // char[256]
+ UINT uTimeoutOrVersion; // UINT
+ char szInfoTitle[64]; // char[64]
+ DWORD dwInfoFlags; // DWORD
+ //GUID guidItem; > IE 6
+};
+
+NOTIFYICONDATA2 trayIcon;
+
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass2[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass3[MAX_LOADSTRING]; // The title bar text
+
+// Foward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+ATOM MyRegisterClass2(HINSTANCE hInstance);
+ATOM MyRegisterClass3(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK ChanInfoProc(HWND, UINT, WPARAM, LPARAM);
+
+void setTrayIcon(int type, const char *,const char *,bool);
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt);
+
+
+HWND chWnd=NULL;
+
+bool gbGetFile = FALSE;
+bool gbStart = FALSE;
+time_t gtGetFile;
+time_t gtStartTime;
+// --------------------------------------------------
+void LOG2(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char str[4096];
+ vsprintf(str,fmt,ap);
+ OutputDebugString(str);
+ va_end(ap);
+}
+
+
+
+// ---------------------------------------
+int APIENTRY WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+#ifdef _DEBUG
+ // memory leak check
+ ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ char tmpURL[8192];
+ tmpURL[0]=0;
+ char *chanURL=NULL;
+
+ hInst = hInstance;
+
+ iniFileName.set(".\\peercast.ini");
+
+ WIN32_FIND_DATA fd; //JP-EX
+ HANDLE hFind; //JP-EX
+
+ OSVERSIONINFO osInfo; //JP-EX
+ osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX
+ GetVersionEx(&osInfo);
+ if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ winDistinctionNT = true;
+ else
+ winDistinctionNT = false;
+
+ // off by default now
+ showGUI = false;
+
+ if (strlen(lpCmdLine) > 0)
+ {
+ char *p;
+ if ((p = strstr(lpCmdLine,"-inifile"))!=NULL)
+ iniFileName.setFromString(p+8);
+
+ if (strstr(lpCmdLine,"-zen"))
+ showGUI = false;
+
+ if (strstr(lpCmdLine,"-multi"))
+ allowMulti = true;
+
+ if (strstr(lpCmdLine,"-kill"))
+ killMe = true;
+
+ if ((p = strstr(lpCmdLine,"-url"))!=NULL)
+ {
+ p+=4;
+ while (*p)
+ {
+ if (*p=='"')
+ {
+ p++;
+ break;
+ }
+ if (*p != ' ')
+ break;
+ p++;
+ }
+ if (*p)
+ strncpy(tmpURL,p,sizeof(tmpURL)-1);
+ }
+ }
+
+ // get current path
+ {
+ exePath = iniFileName;
+ char *s = exePath.cstr();
+ char *end = NULL;
+ while (*s)
+ {
+ if (*s++ == '\\')
+ end = s;
+ }
+ if (end)
+ *end = 0;
+ }
+
+
+ if (strnicmp(tmpURL,"peercast://",11)==0)
+ {
+ if (strnicmp(tmpURL+11,"pls/",4)==0)
+ chanURL = tmpURL+11+4;
+ else
+ chanURL = tmpURL+11;
+ showGUI = false;
+ }
+
+
+ MSG msg;
+ HACCEL hAccelTable;
+
+ // Initialize global strings
+ //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING);
+
+ strcpy(szTitle,"PeerCast");
+ strcpy(szWindowClass,"PeerCast");
+ strcpy(szWindowClass2,"Main");
+ strcpy(szWindowClass3,"Start");
+
+
+
+ if (!allowMulti)
+ {
+ HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass);
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ HWND oldWin = FindWindow(szWindowClass,NULL);
+ if (oldWin)
+ {
+ SendMessage(oldWin,WM_SHOWGUI,0,0);
+ if (killMe)
+ {
+ SendMessage(oldWin,WM_DESTROY,0,0);
+ return 0;
+ }
+
+ if (chanURL)
+ {
+ COPYDATASTRUCT copy;
+ copy.dwData = WM_PLAYCHANNEL;
+ copy.cbData = strlen(chanURL)+1; // plus null term
+ copy.lpData = chanURL;
+ SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)©);
+ }else{
+ if (showGUI)
+ SendMessage(oldWin,WM_SHOWGUI,0,0);
+ }
+ }
+ return 0;
+ }
+ }
+
+ if (killMe)
+ return 0;
+
+ MyRegisterClass(hInstance);
+ MyRegisterClass2(hInstance);
+ MyRegisterClass3(hInstance);
+
+ // Perform application initialization:
+ if (!InitInstance (hInstance, nCmdShow))
+ return FALSE;
+
+ peercastInst = new MyPeercastInst();
+ peercastApp = new MyPeercastApp();
+
+ peercastInst->init();
+
+ LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x");
+
+ if (peercastApp->clearTemp()) //JP-EX
+ {
+ DeleteFile("play.pls");
+ hFind = FindFirstFile("*.asx",&fd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ DeleteFile((char *)&fd.cFileName);
+ }
+ while (FindNextFile(hFind,&fd));
+
+ FindClose(hFind);
+ }
+ }
+
+ if (chanURL)
+ {
+ ChanInfo info;
+ servMgr->procConnectArgs(chanURL,info);
+ chanMgr->findAndPlayChannel(info,false);
+ }
+
+ struct tm t;
+ memset(&t,0,sizeof(t));
+ t.tm_year = 2007 - 1900;
+ t.tm_mon = 4 - 1;
+ t.tm_mday = 7;
+ t.tm_hour = 21;
+ t.tm_min = 0;
+ t.tm_sec = 0;
+ gtStartTime = ::mktime(&t);
+ t.tm_hour = 20;
+ t.tm_min = 50;
+ gtGetFile = ::mktime(&t);
+
+ if (gtStartTime > sys->getTime()){
+ gbGetFile = TRUE;
+ gbStart = TRUE;
+ }
+
+ hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE);
+
+ // setup menu notifes
+ int mask = peercastInst->getNotifyMask();
+ if (mask & ServMgr::NT_PEERCAST)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND);
+ if (mask & ServMgr::NT_BROADCASTERS)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND);
+ if (mask & ServMgr::NT_TRACKINFO)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND);
+
+ // Main message loop:
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon);
+
+ peercastInst->saveSettings();
+ peercastInst->quit();
+
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+
+ return msg.wParam;
+}
+
+
+
+//
+// FUNCTION: MyRegisterClass()
+//
+// PURPOSE: Registers the window class.
+//
+// COMMENTS:
+//
+// This function and its usage is only necessary if you want this code
+// to be compatible with Win32 systems prior to the 'RegisterClassEx'
+// function that was added to Windows 95. It is important to call this function
+// so that the application will get 'well formed' small icons associated
+// with it.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass2(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
+ wcex.lpfnWndProc = (WNDPROC)GUIProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass2;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass3(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)StartProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass3;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+//-----------------------------
+void loadIcons(HINSTANCE hInstance, HWND hWnd)
+{
+ icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL);
+ icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2);
+
+ trayIcon.cbSize = sizeof(trayIcon);
+ trayIcon.hWnd = hWnd;
+ trayIcon.uID = 100;
+ trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP;
+ trayIcon.uCallbackMessage = WM_TRAYICON;
+ trayIcon.hIcon = icon1;
+ strcpy(trayIcon.szTip, "PeerCast");
+
+ Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon);
+
+ //ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ if(!trayMenu) // for PCRaw (tray icon)
+ trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU));
+ if(!ltrayMenu) // for PCRaw (tray icon)
+ ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU));
+
+
+}
+
+//-----------------------------
+//
+// FUNCTION: InitInstance(HANDLE, int)
+//
+// PURPOSE: Saves instance handle and creates main window
+//
+// COMMENTS:
+//
+// In this function, we save the instance handle in a global variable and
+// create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ HWND hWnd;
+
+ hInst = hInstance; // Store instance handle in our global variable
+
+ hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+ if (!hWnd)
+ {
+ return FALSE;
+ }
+
+ mainWnd = hWnd;
+
+ g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated"); // for PCRaw (tray icon)
+
+ loadIcons(hInstance,hWnd);
+
+ using namespace Gdiplus;
+ GdiplusStartupInput gdiplusStartupInput;
+ GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+ return TRUE;
+}
+//-----------------------------
+//static String trackTitle;
+//static String channelComment;
+
+//-----------------------------
+void channelPopup(const char *title, const char *msg, bool isPopup = true)
+{
+ String both;
+
+ if (*title == '\0') return;
+ both.append(msg);
+ both.append(" (");
+ both.append(title);
+ both.append(")");
+
+ trayIcon.uFlags = NIF_ICON|NIF_TIP;
+ strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1);
+ trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0;
+
+ if (isPopup) trayIcon.uFlags |= 16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+//-----------------------------
+void clearChannelPopup()
+{
+ trayIcon.uFlags = NIF_ICON|16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1);
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+
+//-----------------------------
+// PopupEntry
+struct PopupEntry {
+ GnuID id;
+ String name;
+ String track;
+ String comment;
+ PopupEntry *next;
+};
+static PopupEntry *PEList = NULL;
+static WLock PELock;
+
+static void putPopupEntry(PopupEntry *pe)
+{
+ PELock.on();
+ pe->next = PEList;
+ PEList = pe;
+ PELock.off();
+}
+
+static PopupEntry *getPopupEntry(GnuID id)
+{
+ PELock.on();
+ PopupEntry *pe = PEList;
+ PopupEntry *prev = NULL;
+ while (pe) {
+ if (id.isSame(pe->id)) {
+ if (prev) prev->next = pe->next;
+ else PEList = pe->next;
+ PELock.off();
+ pe->next = NULL;
+ return pe;
+ }
+ prev = pe;
+ pe = pe->next;
+ }
+ PELock.off();
+ return NULL;
+}
+
+static PopupEntry *getTopPopupEntry()
+{
+ PopupEntry *p = NULL;
+ PELock.on();
+ if (PEList) {
+ p = PEList;
+ PEList = PEList->next;
+ }
+ PELock.off();
+ return p;
+}
+
+//-----------------------------
+void APICALL MyPeercastApp::channelStart(ChanInfo *info)
+{
+
+// lastPlayID = info->id;
+//
+// if(!isIndexTxt(info)) // for PCRaw (popup)
+// clearChannelPopup();
+
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (!pe) {
+ pe = new PopupEntry;
+ pe->id = info->id;
+ }
+ if (!isIndexTxt(info))
+ putPopupEntry(pe);
+ else
+ delete pe;
+}
+//-----------------------------
+void APICALL MyPeercastApp::channelStop(ChanInfo *info)
+{
+// if (info->id.isSame(lastPlayID))
+// {
+// lastPlayID.clear();
+//
+// if(!isIndexTxt(info)) // for PCRaw (popup)
+// clearChannelPopup();
+// }
+
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (pe) delete pe;
+
+ pe = getTopPopupEntry();
+ if (!pe) {
+ clearChannelPopup();
+ } else {
+ if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+ {
+ String name,track; //JP-Patch
+ name = pe->name; //JP-Patch
+ track = pe->track; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ track.convertTo(String::T_SJIS); //JP-Patch
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),trackTitle.cstr());
+ channelPopup(name.cstr(),track.cstr(), false); //JP-Patch
+ }
+ putPopupEntry(pe);
+ }
+}
+//-----------------------------
+void APICALL MyPeercastApp::channelUpdate(ChanInfo *info)
+{
+ if (info)
+ {
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (!pe) return;
+
+ String tmp;
+ tmp.append(info->track.artist);
+ tmp.append(" ");
+ tmp.append(info->track.title);
+
+
+ if (!tmp.isSame(pe->track))
+ {
+ pe->name = info->name;
+ pe->track = tmp;
+ if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+ {
+ //trackTitle=tmp;
+ String name,track; //JP-Patch
+ name = info->name; //JP-Patch
+ track = tmp; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ track.convertTo(String::T_SJIS); //JP-Patch
+ if(!isIndexTxt(info)) // for PCRaw (popup)
+ {
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),trackTitle.cstr());
+ channelPopup(name.cstr(),track.cstr()); //JP-Patch
+ }
+ }
+ } else if (!info->comment.isSame(pe->comment))
+ {
+ pe->name = info->name;
+ pe->comment = info->comment;
+ if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask())
+ {
+ //channelComment = info->comment;
+ String name,comment; //JP-Patch
+ name = info->name; //JP-Patch
+ comment = info->comment; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ comment.convertTo(String::T_SJIS); //JP-Patch
+ if(!isIndexTxt(info)) // for PCRaw (popup)
+ {
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),channelComment.cstr());
+ channelPopup(name.cstr(),comment.cstr());
+ }
+ }
+ }
+
+ if (!isIndexTxt(info))
+ putPopupEntry(pe);
+ else
+ delete pe;
+ }
+}
+//-----------------------------
+void APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg)
+{
+ currNotify = type;
+
+ if (type == ServMgr::NT_UPGRADE)
+ {
+ trayIcon.uFlags = NIF_ICON;
+ trayIcon.hIcon = icon2;
+ }else{
+ trayIcon.uFlags = NIF_ICON;
+ trayIcon.hIcon = icon1;
+ }
+
+ const char *title="";
+
+ switch(type)
+ {
+ case ServMgr::NT_UPGRADE:
+ title = "Upgrade alert";
+ break;
+ case ServMgr::NT_PEERCAST:
+ title = "Message from PeerCast:";
+ break;
+
+ }
+
+ if (type & peercastInst->getNotifyMask())
+ {
+ trayIcon.uFlags |= 16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+ }
+}
+//-----------------------------
+
+// createGUI()
+//
+void createGUI(HWND hWnd)
+{
+ if (!guiWnd){
+ guiWnd = ::CreateWindow(szWindowClass2,
+ "Peercast-IM@S",
+ WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/,
+ 0,
+ 0,
+ 800,
+ 600,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+ }
+ ShowWindow(guiWnd,SW_SHOWNORMAL);
+}
+
+
+//
+// addRelayedChannelsMenu(HMENU m)
+//
+//
+void addRelayedChannelsMenu(HMENU cm)
+{
+ int cnt = GetMenuItemCount(cm);
+ for(int i=0; i<cnt-3; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);
+
+ Channel *c = chanMgr->channel;
+ while(c)
+ {
+ if (c->isActive())
+ {
+ char str[128],name[64];
+ strncpy(name,c->info.name,32);
+ name[32]=0;
+ if (strlen(c->info.name) > 32)
+ strcat(name,"...");
+
+
+ sprintf(str,"%s (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType));
+ //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str);
+ }
+ c=c->next;
+ }
+}
+
+typedef int (*COMPARE_FUNC)(const void *,const void *);
+
+static int compareHitLists(ChanHitList **c2, ChanHitList **c1)
+{
+ return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+static int compareChannels(Channel **c2, Channel **c1)
+{
+ return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+//
+// addAllChannelsMenu(HMENU m)
+//
+//
+void addAllChannelsMenu(HMENU cm)
+{
+ int cnt = GetMenuItemCount(cm);
+/* for(int i=0; i<cnt-2; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);*/
+
+ for(int i=0; i<cnt; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);
+
+ HMENU yMenu = CreatePopupMenu();
+ if (!servMgr->rootHost2.isEmpty()){
+ InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2);
+ }
+ if (!servMgr->rootHost.isEmpty()){
+ InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost);
+ }
+
+ InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"\83C\83G\83\8d\81[\83y\81[\83W");
+ InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL);
+ // add channels to menu
+ int numActive=0;
+ Channel *ch = chanMgr->channel;
+ while(ch)
+ {
+ char str[128],name[64];
+ String sjis; //JP-Patch
+ sjis = ch->info.name; //JP-Patch
+ sjis.convertTo(String::T_SJIS); //JP-Patch
+ strncpy(name,sjis.cstr(),32);
+ //strncpy(name,ch->info.name,32);
+ name[32]=0;
+ //if (strlen(ch->info.name) > 32)
+ if (strlen(sjis.cstr()) > 32) //JP-Patch
+ strcat(name,"...");
+
+ sprintf(str,"%s (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType));
+
+ HMENU opMenu = CreatePopupMenu();
+ InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info");
+ if (ch->info.url.isValidURL())
+ InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL");
+ InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play");
+
+ UINT fl = MF_BYPOSITION|MF_POPUP;
+ if (ch)
+ fl |= (ch->isPlaying()?MF_CHECKED:0);
+
+ InsertMenu(cm,0,fl,(UINT)opMenu,str);
+
+ numActive++;
+
+ ch=ch->next;
+ }
+
+
+ //if (!numActive)
+ // InsertMenu(cm,0,MF_BYPOSITION,0,"<No channels>");
+
+
+
+
+}
+
+
+//
+// flipNotifyPopup(id, flag)
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt)
+{
+ int mask = peercastInst->getNotifyMask();
+
+ mask ^= nt;
+ if (mask & nt)
+ CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND);
+
+ peercastInst->setNotifyMask(mask);
+ peercastInst->saveSettings();
+}
+
+
+static void showHTML(const char *file)
+{
+ char url[256];
+ sprintf(url,"%s/%s",servMgr->htmlPath,file);
+
+// sys->callLocalURL(url,servMgr->serverHost.port);
+ sys->callLocalURL(url, // for PCRaw (url)
+ (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1));
+}
+
+static ChanInfo getChannelInfo(int index)
+{
+ Channel *c = chanMgr->findChannelByIndex(index);
+ if (c)
+ return c->info;
+
+ ChanInfo info;
+ return info;
+}
+
+//
+// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+// PURPOSE: Processes messages for the main window.
+//
+// WM_COMMAND - process the application menu
+// WM_PAINT - Paint the main window
+// WM_DESTROY - post a quit message and return
+//
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ POINT point;
+ char buf[1024];
+
+ if(message == g_iTaskbarCreated) // for PCRaw (tray icon)
+ loadIcons(hInst, hWnd);
+
+ switch (message)
+ {
+ case WM_SHOWGUI:
+ createGUI(hWnd);
+ break;
+
+
+ case WM_TRAYICON:
+ switch((UINT)lParam)
+ {
+ case WM_LBUTTONDOWN:
+ if (allowTrayMenu)
+ SendMessage(hWnd,WM_SHOWMENU,2,0);
+ SetForegroundWindow(hWnd);
+ break;
+ case WM_RBUTTONDOWN:
+ if (allowTrayMenu)
+ SendMessage(hWnd,WM_SHOWMENU,1,0);
+ SetForegroundWindow(hWnd);
+ break;
+ case WM_LBUTTONDBLCLK:
+ createGUI(hWnd);
+ break;
+ }
+ break;
+
+ case WM_COPYDATA:
+ {
+ COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam;
+ LOG_DEBUG("URL request: %s",pc->lpData);
+ if (pc->dwData == WM_PLAYCHANNEL)
+ {
+ ChanInfo info;
+ servMgr->procConnectArgs((char *)pc->lpData,info);
+ chanMgr->findAndPlayChannel(info,false);
+ }
+ //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port);
+ }
+ break;
+ case WM_GETPORTNUMBER:
+ {
+ int port;
+ port=servMgr->serverHost.port;
+ ReplyMessage(port);
+ }
+ break;
+
+ case WM_SHOWMENU:
+ {
+ if (servMgr->saveGuiPos){
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+ } else {
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+ }
+
+ SetForegroundWindow(hWnd);
+ bool skipMenu=false;
+
+ allowTrayMenu = false;
+
+ // check for notifications
+ if (currNotify & ServMgr::NT_UPGRADE)
+ {
+ if (servMgr->downloadURL[0])
+ {
+ if ((sys->getTime()-seenNewVersionTime) > (60*60)) // notify every hour
+ {
+ if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK)
+ sys->getURL(servMgr->downloadURL);
+
+ seenNewVersionTime=sys->getTime();
+ skipMenu=true;
+ }
+ }
+ }
+
+
+ if (!skipMenu)
+ {
+ RECT rcWnd;
+ HMENU menu;
+ UINT flg = 0;
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0);
+ GetCursorPos(&point);
+
+ if (point.x < rcWnd.left){
+ point.x = rcWnd.left;
+ flg |= TPM_LEFTALIGN;
+ }
+ if (point.x > rcWnd.right){
+ point.x = rcWnd.right;
+ flg |= TPM_RIGHTALIGN;
+ }
+ if (point.y < rcWnd.top){
+ point.y = rcWnd.top;
+ flg |= TPM_TOPALIGN;
+ }
+ if (point.y > rcWnd.bottom){
+ point.y = rcWnd.bottom;
+ flg |= TPM_BOTTOMALIGN;
+ }
+ if (flg == 0){
+ flg = TPM_RIGHTALIGN;
+ }
+
+ switch (wParam)
+ {
+ case 1:
+ menu = GetSubMenu(trayMenu,0);
+ addAllChannelsMenu(GetSubMenu(menu,0));
+ addRelayedChannelsMenu(GetSubMenu(menu,1));
+ break;
+ case 2:
+ menu = GetSubMenu(ltrayMenu,0);
+ addAllChannelsMenu(menu);
+ break;
+ }
+ if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL))
+ {
+ LOG_ERROR("Can`t track popup menu: %d",GetLastError());
+ }
+ PostMessage(hWnd,WM_NULL,0,0);
+
+ }
+ allowTrayMenu = true;
+ }
+ break;
+
+ case WM_CREATE:
+ if (showGUI)
+ createGUI(hWnd);
+ break;
+
+ case WM_COMMAND:
+ wmId = LOWORD(wParam);
+ wmEvent = HIWORD(wParam);
+
+ if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - INFO_CMD;
+ chanInfo = getChannelInfo(c);
+ chanInfoIsRelayed = false;
+ if (winDistinctionNT)
+ DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc);
+ else
+ {
+ HWND WKDLG; //JP-Patch
+ WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch
+ ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch
+ }
+ return 0;
+ }
+ if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - URL_CMD;
+ chanInfo = getChannelInfo(c);
+ if (chanInfo.url.isValidURL())
+ sys->getURL(chanInfo.url);
+ return 0;
+ }
+ if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - PLAY_CMD;
+ chanInfo = getChannelInfo(c);
+ chanMgr->findAndPlayChannel(chanInfo,false);
+ return 0;
+ }
+ if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - RELAY_CMD;
+ chanInfo = getChannelInfo(c);
+ chanMgr->findAndPlayChannel(chanInfo,true);
+ return 0;
+ }
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case ID_POPUP_SHOWMESSAGES_PEERCAST:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST);
+ break;
+ case ID_POPUP_SHOWMESSAGES_BROADCASTERS:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS);
+ break;
+ case ID_POPUP_SHOWMESSAGES_TRACKINFO:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO);
+ break;
+
+ case ID_POPUP_ABOUT:
+ case IDM_ABOUT:
+ DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+ break;
+ case ID_POPUP_SHOWGUI:
+ case IDM_SETTINGS_GUI:
+ case ID_POPUP_ADVANCED_SHOWGUI:
+ {
+ createGUI(hWnd);
+ break;
+ }
+ case ID_POPUP_YELLOWPAGES:
+ sys->getURL("http://yp.peercast.org/");
+ break;
+ case ID_POPUP_YELLOWPAGES1:
+ sprintf(buf, "http://%s",servMgr->rootHost.cstr());
+ sys->getURL(buf);
+ break;
+ case ID_POPUP_YELLOWPAGES2:
+ sprintf(buf, "http://%s",servMgr->rootHost2.cstr());
+ sys->getURL(buf);
+ break;
+
+ case ID_POPUP_ADVANCED_VIEWLOG:
+ showHTML("viewlog.html");
+ break;
+ case ID_POPUP_ADVANCED_SAVESETTINGS:
+ servMgr->saveSettings(iniFileName.cstr());
+ break;
+ case ID_POPUP_ADVANCED_INFORMATION:
+ showHTML("index.html");
+ break;
+ case ID_FIND_CHANNELS:
+ case ID_POPUP_ADVANCED_ALLCHANNELS:
+ case ID_POPUP_UPGRADE:
+ sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port);
+ break;
+ case ID_POPUP_ADVANCED_RELAYEDCHANNELS:
+ case ID_POPUP_FAVORITES_EDIT:
+ showHTML("relays.html");
+ break;
+ case ID_POPUP_ADVANCED_BROADCAST:
+ showHTML("broadcast.html");
+ break;
+ case ID_POPUP_SETTINGS:
+ showHTML("settings.html");
+ break;
+ case ID_POPUP_CONNECTIONS:
+ showHTML("connections.html");
+ break;
+ case ID_POPUP_HELP:
+ sys->getURL("http://www.peercast.org/help.php");
+ break;
+
+ case ID_POPUP_SAVE_GUI_POS:
+ if (servMgr->saveGuiPos){
+ servMgr->saveGuiPos = false;
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+ } else {
+ servMgr->saveGuiPos = true;
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+ }
+ peercastInst->saveSettings();
+ break;
+
+ case ID_POPUP_KEEP_DOWNSTREAMS:
+ if (servMgr->keepDownstreams){
+ servMgr->keepDownstreams = false;
+ CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND);
+ } else {
+ servMgr->keepDownstreams = true;
+ CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND);
+ }
+ //peercastInst->saveSettings();
+ break;
+
+ case ID_POPUP_EXIT_CONFIRM:
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT);
+// SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP);
+#ifdef VERSION_EX
+ SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX);
+#else
+ SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP);
+#endif
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+ case IDC_BUTTON1:
+ sys->getURL("http://www.peercast.org");
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+// Mesage handler for chaninfo box
+LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ char str[1024];
+ //strcpy(str,chanInfo.track.artist.cstr());
+ strcpy(str,chanInfo.track.artist); //JP-Patch
+ strcat(str," - ");
+ //strcat(str,chanInfo.track.title.cstr());
+ strcat(str,chanInfo.track.title);
+ String name,track,comment,desc,genre; //JP-Patch
+ name = chanInfo.name; //JP-Patch
+ track = str; //JP-Patch
+ comment = chanInfo.comment; //JP-Patch
+ desc = chanInfo.desc; //JP-Patc
+ genre = chanInfo.genre; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patc
+ track.convertTo(String::T_SJIS); //JP-Patch
+ comment.convertTo(String::T_SJIS); //JP-Patch
+ desc.convertTo(String::T_SJIS); //JP-Patch
+ genre.convertTo(String::T_SJIS); //JP-Patch
+
+ //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str);
+ SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch
+
+ sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType));
+ SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str);
+
+
+ if (!chanInfo.url.isValidURL())
+ EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false);
+
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ {
+ SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr());
+ SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0);
+ }else
+ {
+ SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK");
+ EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false);
+ }
+
+
+
+ POINT point;
+ RECT rect,drect;
+ HWND hDsk = GetDesktopWindow();
+ GetWindowRect(hDsk,&drect);
+ GetWindowRect(hDlg,&rect);
+ GetCursorPos(&point);
+
+ POINT pos,size;
+ size.x = rect.right-rect.left;
+ size.y = rect.bottom-rect.top;
+
+ if (point.x-drect.left < size.x)
+ pos.x = point.x;
+ else
+ pos.x = point.x-size.x;
+
+ if (point.y-drect.top < size.y)
+ pos.y = point.y;
+ else
+ pos.y = point.y-size.y;
+
+ SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0);
+ chWnd = hDlg;
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ {
+ char str[1024],idstr[64];
+ chanInfo.id.toStr(idstr);
+
+ switch (LOWORD(wParam))
+ {
+ case IDC_CONTACT:
+ {
+ sys->getURL(chanInfo.url);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ {
+ sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed);
+ sys->callLocalURL(str,servMgr->serverHost.port);
+ return TRUE;
+ }
+ case IDC_KEEP:
+ {
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;;
+ return TRUE;
+ }
+
+
+ case IDC_PLAY:
+ {
+ chanMgr->findAndPlayChannel(chanInfo,false);
+ return TRUE;
+ }
+
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ if (winDistinctionNT)
+ EndDialog(hDlg, 0);
+ else
+ DestroyWindow(hDlg); //JP-Patch
+ break;
+
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) == WA_INACTIVE)
+ if (winDistinctionNT)
+ EndDialog(hDlg, 0);
+ else
+ DestroyWindow(hDlg); //JP-Patch
+ break;
+ case WM_DESTROY:
+ chWnd = NULL;
+ break;
+
+
+ }
+ return FALSE;
+}
--- /dev/null
+
+// ------------------------------------------------
+// File : simple.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
+#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+// ---------------------------------
+class MyPeercastInst : public PeercastInstance
+{
+public:
+ virtual Sys * APICALL createSys();
+};
+// ---------------------------------
+class MyPeercastApp : public PeercastApplication
+{
+public:
+ MyPeercastApp ()
+ {
+ //logFile.openWriteReplace("log.txt");
+ }
+
+ virtual const char * APICALL getPath();
+
+ virtual const char * APICALL getIniFilename();
+ virtual const char *APICALL getClientTypeOS();
+ virtual void APICALL openLogFile(); //JP-EX
+ virtual void APICALL getDirectory(); //JP-EX
+ virtual bool APICALL clearTemp(); //JP-EX
+ virtual void APICALL printLog(LogBuffer::TYPE t, const char *str);
+
+ virtual void APICALL updateSettings();
+ virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *);
+
+ virtual void APICALL channelStart(ChanInfo *);
+ virtual void APICALL channelStop(ChanInfo *);
+ virtual void APICALL channelUpdate(ChanInfo *);
+
+ FileStream logFile;
+
+};
+
+
+#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
--- /dev/null
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(932)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAYMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM "\8fî\95ñ", ID_POPUP_ABOUT
+ MENUITEM "\83w\83\8b\83v", ID_POPUP_HELP
+ MENUITEM SEPARATOR
+ POPUP "\83|\83b\83v\83A\83b\83v\83\81\83b\83Z\81[\83W"
+ BEGIN
+ MENUITEM "PeerCast", ID_POPUP_SHOWMESSAGES_PEERCAST
+
+ MENUITEM "\94z\90M\8eÒ", ID_POPUP_SHOWMESSAGES_BROADCASTERS
+
+ MENUITEM "\83g\83\89\83b\83N\8fî\95ñ", ID_POPUP_SHOWMESSAGES_TRACKINFO
+
+ MENUITEM "\83A\83b\83v\83f\81[\83g\8fî\95ñ", ID_POPUP_POPUPMESSAGES_UPGRADEALERTS
+ , CHECKED, GRAYED
+ END
+ POPUP "\8d\82\93x"
+ BEGIN
+ MENUITEM "\8fî\95ñ", ID_POPUP_ADVANCED_INFORMATION
+
+ MENUITEM "\83\8a\83\8c\81[\83`\83\83\83\93\83l\83\8b", ID_POPUP_ADVANCED_RELAYEDCHANNELS
+
+ MENUITEM "\94z\90M", ID_POPUP_ADVANCED_BROADCAST
+
+ MENUITEM "\83R\83l\83N\83V\83\87\83\93", ID_POPUP_CONNECTIONS
+ MENUITEM "\83\8d\83O", ID_POPUP_ADVANCED_VIEWLOG
+
+ MENUITEM "\90Ý\92è", ID_POPUP_SETTINGS
+ MENUITEM "GUI\82ð\8aJ\82", ID_POPUP_ADVANCED_SHOWGUI
+
+ END
+ POPUP "\92Ç\89Á\90Ý\92è"
+ BEGIN
+ MENUITEM "\8fI\97¹\8e\9e\81A\95\\8e¦\88Ê\92u\82ð\95Û\91¶", ID_POPUP_SAVE_GUI_POS
+ , CHECKED
+ MENUITEM "\8dÄ\90Ú\91±\8e\9e\89º\97¬\88Û\8e\9d", ID_POPUP_KEEP_DOWNSTREAMS
+ , CHECKED
+ END
+ MENUITEM SEPARATOR
+ POPUP "\8fI\97¹"
+ BEGIN
+ MENUITEM "\82Í\82¢", ID_POPUP_EXIT_CONFIRM
+ MENUITEM "\82¢\82¢\82¦", ID_POPUP_EXIT_NO
+ END
+ END
+END
+
+IDR_LTRAYMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "\83C\83G\83\8d\81[\83y\81[\83W", ID_POPUP_YELLOWPAGES
+ POPUP "\83C\83G\83\8d\81[\83y\81[\83W"
+ BEGIN
+ MENUITEM "AAA", ID_POPUP_YELLOWPAGES1
+ MENUITEM "BBB", ID_POPUP_YELLOWPAGES2
+ END
+ END
+END
+
+IDR_GUIMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "\90§\8cä", ID_POPUP_YELLOWPAGES
+ POPUP "\90§\8cä"
+ BEGIN
+ MENUITEM "AAA", ID_POPUP_YELLOWPAGES1
+ MENUITEM "BBB", ID_POPUP_YELLOWPAGES2
+ END
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341
+STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU |
+ WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "PeerCast"
+FONT 9, "MS UI Gothic", 0, 0, 0x1
+BEGIN
+ LISTBOX IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "\97L\8cø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT
+ EDITTEXT IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL
+ RTEXT "\83|\81[\83g :",IDC_STATIC,107,20,18,8
+ LISTBOX IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "\83\8d\83O",IDC_STATIC_LOG,3,282,13,8
+ LTEXT "\83R\83l\83N\83V\83\87\83\93",IDC_STATIC_CONNECTION,3,184,40,8
+ GROUPBOX "",IDC_STATIC,3,4,291,49
+ PUSHBUTTON "\83N\83\8a\83A",IDC_BUTTON1,35,279,25,11
+ LISTBOX IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "\90Ø\92f",IDC_BUTTON5,67,65,43,13
+ GROUPBOX "\83\8a\83\8c\81[",IDC_GROUPBOX_RELAY,3,54,291,96
+ EDITTEXT IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL
+ RTEXT "\83p\83X\83\8f\81[\83h :",IDC_STATIC,89,36,36,8
+ CONTROL "\83f\83o\83b\83O",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,127,279,32,11
+ CONTROL "\83l\83b\83g\83\8f\81[\83N",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,185,279,35,11
+ CONTROL "\83G\83\89\81[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,159,279,25,11
+ CONTROL "\92â\8e~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,60,279,30,11
+ PUSHBUTTON "\8dÄ\90¶",IDC_BUTTON8,10,65,22,13
+ CONTROL "\83`\83\83\83\93\83l\83\8b",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,221,279,35,11
+ PUSHBUTTON "\8dÄ\90Ú\91±",IDC_BUTTON3,41,65,24,13
+ EDITTEXT IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL
+ CONTROL "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,5,160,23,12
+ RTEXT "\8dÅ\91å\83\8a\83\8c\81[\90\94 :",IDC_STATIC,203,20,40,8
+ EDITTEXT IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER
+ PUSHBUTTON "\83L\81[\83v",IDC_BUTTON9,112,65,24,13
+ PUSHBUTTON "\90Ø\92f",IDC_BUTTON6,47,179,43,13
+ LTEXT "Peercast-VP",IDC_STATIC,21,14,39,8
+END
+
+IDD_CHANINFO DIALOGEX 0, 0, 184, 207
+STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Channel Information"
+FONT 9, "MS UI Gothic", 400, 0, 0x80
+BEGIN
+ LTEXT "\96¼\91O:",IDC_STATIC,7,8,24,9
+ EDITTEXT IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ LTEXT "\93à\97e:",IDC_STATIC,7,79,93,9
+ EDITTEXT IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ LTEXT "DJ \83\81\83b\83Z\81[\83W:",IDC_STATIC,7,117,41,9
+ EDITTEXT IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ PUSHBUTTON "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT
+ LTEXT "\8fÚ\8d×:",IDC_STATIC,7,43,67,8
+ EDITTEXT IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ RTEXT "\8c`\8e®",IDC_FORMAT,69,80,107,8
+ LTEXT "\83W\83\83\83\93\83\8b:",IDC_STATIC,63,5,22,8
+ EDITTEXT IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ CONTROL "\83L\81[\83v",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 144,188,33,10
+ LTEXT "\83X\83e\81[\83^\83X:",IDC_STATIC,7,153,41,9
+ EDITTEXT IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER |
+ NOT WS_TABSTOP,WS_EX_STATICEDGE
+ PUSHBUTTON "\8dÄ\90¶",IDC_PLAY,56,185,34,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MAINWINDOW, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 294
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 336
+ END
+
+ IDD_CHANINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 177
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// \89p\8cê (\95Ä\8d\91) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_SIMPLE MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About ...", IDM_ABOUT
+ END
+ POPUP "Settings"
+ BEGIN
+ MENUITEM "GUI", IDM_SETTINGS_GUI
+ END
+END
+
+IDR_VERMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM "Please upgrade PeerCast. Click here to download.",
+ ID_POPUP_UPGRADE
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG 22, 17, 163, 59
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+ ICON IDI_SIMPLE,IDC_MYICON,14,9,20,20
+ LTEXT "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 2005",IDC_STATIC,43,22,119,8
+ PUSHBUTTON "OK",IDOK,134,40,24,12,WS_GROUP
+ PUSHBUTTON "www.peercast.org",IDC_BUTTON1,42,40,66,12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 58
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SIMPLE ICON "Simple.ICO"
+IDI_SMALL2 ICON "small1.ico"
+IDI_SMALL ICON "small3.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_SIMPLE ACCELERATORS
+BEGIN
+ "?", IDM_ABOUT, ASCII, ALT
+ "/", IDM_ABOUT, ASCII, ALT
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""resource.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_APP_TITLE "PeerCast"
+END
+
+#endif // \89p\8cê (\95Ä\8d\91) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
--- /dev/null
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Simple"
+ ProjectGUID="{7D4833CE-1286-4587-9470-52E098B29C12}"
+ RootNamespace="Simple"
+ SccProjectName=""$/PeerCast.root/PeerCast", JCAAAAAA"
+ SccLocalPath="..\..\.."
+ SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Private Debug|Win32"
+ OutputDirectory=".\Simple___Win32_Private_Debug"
+ IntermediateDirectory=".\Simple___Win32_Private_Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Simple___Win32_Private_Debug/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Simple___Win32_Private_Debug/Simple.pch"
+ AssemblerListingLocation=".\Simple___Win32_Private_Debug/"
+ ObjectFile=".\Simple___Win32_Private_Debug/"
+ ProgramDataBaseFileName=".\Simple___Win32_Private_Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile="Debug/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Simple___Win32_Private_Debug/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Simple___Win32_Private_Debug/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to program files"
+ CommandLine="copy debug\peercast.exe "c:\program files\peercast""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/Simple.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+ OutputFile="Release/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=""C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Release""
+ ProgramDatabaseFile=".\Release/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to pimp & program files"
+ CommandLine="copy release\peercast.exe "c:\program files\peercast"
copy release\peercast.exe ..\pimp\
"
+ />
+ </Configuration>
+ <Configuration
+ Name="Private Release|Win32"
+ OutputDirectory=".\Simple___Win32_Private_Release"
+ IntermediateDirectory=".\Simple___Win32_Private_Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Simple___Win32_Private_Release/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Simple___Win32_Private_Release/Simple.pch"
+ AssemblerListingLocation=".\Simple___Win32_Private_Release/"
+ ObjectFile=".\Simple___Win32_Private_Release/"
+ ProgramDataBaseFileName=".\Simple___Win32_Private_Release/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile="PrivRelease/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\Simple___Win32_Private_Release/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Simple___Win32_Private_Release/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to pimp & program files"
+ CommandLine="copy release\peercast.exe "c:\program files\peercast"
copy release\peercast.exe ..\pimp\
"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Debug/Simple.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+ OutputFile="Debug/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=""C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Debug""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/PeerCast.pdb"
+ SubSystem="2"
+ HeapReserveSize="4194304"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to program files"
+ CommandLine="copy debug\peercast.exe "c:\program files\peercast""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="chkMemoryLeak.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="gui.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\identify_encoding.c"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Simple.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Simple.rc"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="StdAfx.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\utf8.c"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="chkMemoryLeak.h"
+ >
+ </File>
+ <File
+ RelativePath="gui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\identify_encoding.h"
+ >
+ </File>
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ <File
+ RelativePath="Simple.h"
+ >
+ </File>
+ <File
+ RelativePath="StdAfx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\utf8.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="Simple.ico"
+ >
+ </File>
+ <File
+ RelativePath="small.ico"
+ >
+ </File>
+ <File
+ RelativePath="small1.ico"
+ >
+ </File>
+ <File
+ RelativePath="small3.ico"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Linux"
+ >
+ <File
+ RelativePath="..\..\linux\main.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\linux\makefile"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="OSX"
+ >
+ <File
+ RelativePath="..\..\osx\main.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\osx\makefile"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// stdafx.cpp : source file that includes just the standard includes
+// Simple.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
+
--- /dev/null
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
+#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+// Local Header Files
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
--- /dev/null
+#ifdef _DEBUG
+//#include "stdafx.h"
+#include "chkMemoryLeak.h"
+
+#ifdef __AFXWIN_H__ // MFC\82Ì\83E\83B\83\93\83h\83E\82ð\8eg\82¤\8fê\8d\87\82É\8cÀ\92è\82µ\82Ä\82¢\82Ü\82·
+#else
+ #if defined(_DEBUG)
+ #define __chkMemoryLeak_H__
+ void* operator new(size_t size, const char *filename, int linenumber)
+ {
+ return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber);
+ }
+ void operator delete(void * _P, const char *filename, int linenumber)
+ {
+ _free_dbg(_P, _NORMAL_BLOCK);
+ return;
+ }
+
+ #endif
+#endif
+#endif
--- /dev/null
+#ifndef _CHKMEMORYLEAK_H
+#define _CHKMEMORYLEAK_H
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef _DEBUG
+ #define _CRTDBG_MAP_ALLOC
+
+ #define SET_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+ #define CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+
+ void* operator new(size_t size, const char *filename, int linenumber);
+ void operator delete(void * _P, const char *filename, int linenumber);
+#else
+ #define SET_CRT_DEBUG_FIELD(a) ((void) 0)
+ #define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
+#endif
+
+#include <crtdbg.h>
+
+#include <malloc.h>
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : gui.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Windows front end GUI, PeerCast core is not dependant on any of this.
+// Its very messy at the moment, but then again Windows UI always is.
+// I really don`t like programming win32 UI.. I want my borland back..
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#define _WIN32_WINNT 0x0500
+
+#include <windows.h>
+#include "stdio.h"
+#include "string.h"
+#include "stdarg.h"
+#include "resource.h"
+#include "socket.h"
+#include "win32/wsys.h"
+#include "servent.h"
+#include "win32/wsocket.h"
+#include "inifile.h"
+#include "gui.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "simple.h"
+#include "gdiplus.h"
+#include "commctrl.h"
+#include "locale.h"
+#include "stats.h"
+#include "socket.h"
+#include "wininet.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo guiThread;
+bool shownChannels=false;
+WINDOWPLACEMENT winPlace;
+bool guiFlg = false;
+
+using namespace Gdiplus;
+
+#include <comdef.h>
+
+void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str)
+{
+/* ADDLOG(str,logID,true,NULL,t);
+ if (logFile.isOpen())
+ {
+ logFile.writeLine(str);
+ logFile.flush();
+ }*/
+}
+
+void APICALL MyPeercastApp::updateSettings()
+{
+// setControls(true);
+}
+
+Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB);
+UINT backWidth;
+UINT backHeight;
+
+Gdiplus::Image *backImage;
+Gdiplus::Bitmap *backBmp;
+Gdiplus::Graphics *backGra;
+
+Gdiplus::Image *img_idle;
+Gdiplus::Image *img_connect;
+Gdiplus::Image *img_conn_ok;
+Gdiplus::Image *img_conn_full;
+Gdiplus::Image *img_conn_over;
+Gdiplus::Image *img_conn_ok_skip;
+Gdiplus::Image *img_conn_full_skip;
+Gdiplus::Image *img_conn_over_skip;
+Gdiplus::Image *img_error;
+Gdiplus::Image *img_broad_ok;
+Gdiplus::Image *img_broad_full;
+
+UINT winWidth=0;
+UINT winHeight=0;
+
+static HWND hTree;
+extern HINSTANCE hInst;
+extern HWND guiWnd;
+extern Stats stats;
+
+WLock sd_lock;
+WLock ChannelDataLock;
+WLock MakeBackLock;
+ChannelData *channelDataTop = NULL;
+
+extern bool gbGetFile;
+extern bool gbStart;
+extern time_t gtGetFile;
+extern time_t gtStartTime;
+ThreadInfo gtiStart;
+ThreadInfo gtiGetFile;
+static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg";
+static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg";
+HWND ghStart;
+
+bool gbDispTop = false;
+bool gbAllOpen = false;
+
+THREAD_PROC FestivalStart(ThreadInfo *thread);
+
+THREAD_PROC GetHostName(ThreadInfo *thread){
+ IdData *id = (IdData*)(thread->data);
+
+ HOSTENT *he;
+ unsigned int ip;
+ bool flg = TRUE;
+
+ ChannelDataLock.on();
+ ip = htonl(id->getIpAddr());
+
+ for (int i=0; i<5 && flg; i++){
+ he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+ ChannelData* cd = channelDataTop;
+ if (he)
+ {
+ while(cd){
+ if (cd->setName(id->getServentId(), he->h_name)){
+ flg = FALSE;
+ break;
+ }
+ cd = cd->getNextData();
+ }
+ }
+// ::delete id;
+ ChannelDataLock.off();
+ sys->sleep(1000);
+ }
+
+
+ return 0;
+}
+
+bool DownloadFile(LPCTSTR URL, LPCTSTR local){
+ char header[] = "Accept: */*\r\n\r\n";
+ char buf[4096];
+
+ FileStream f;
+ HINTERNET hInternet;
+ HINTERNET hConnect;
+
+ try{
+ f.openWriteReplace(local);
+ }catch(StreamException &e){
+ return false;
+ }
+
+ hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+ if (hInternet == NULL){
+ return false;
+ }
+
+ hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0);
+ if (hConnect == NULL){
+ ::InternetCloseHandle(hInternet);
+ return false;
+ }
+
+ while(1){
+ sys->sleep(0);
+ DWORD dwReadSize;
+ BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize);
+ if (ret){
+ if (dwReadSize == 0){
+ break;
+ }
+ try{
+ f.write(buf, dwReadSize);
+ continue;
+ } catch(StreamException e){
+ }
+ f.close();
+ ::InternetCloseHandle(hConnect);
+ ::InternetCloseHandle(hInternet);
+ return false;
+ }
+ }
+
+ f.flush();
+ f.close();
+ ::InternetCloseHandle(hConnect);
+ ::InternetCloseHandle(hInternet);
+
+ return true;
+}
+
+THREAD_PROC GetInternetFile(ThreadInfo *thread){
+
+ DownloadFile(data1URL, "data1.jpg");
+ DownloadFile(data2URL, "data2.jpg");
+ return 0;
+}
+
+extern TCHAR szWindowClass3[]; // The title bar text
+
+
+int drawSpeed(Graphics *gra, int posX, int posY){
+
+ // \91¬\93x\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82\82·\82é
+ SolidBrush b(Color(180,255,255,255));
+ backGra->FillRectangle(&b, posX, posY, 200, 14);
+ // \83t\83H\83\93\83g\90Ý\92è
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",10);
+ // \95¶\8e\9a\90F
+ SolidBrush strBrush(Color::Black);
+ // \95¶\8e\9a\97ñ\8dì\90¬
+ char tmp[256];
+ sprintf(tmp, "R:%.1fkbps S:%.1fkbps",
+ BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)),
+ BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT)));
+ _bstr_t bstr(tmp);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ StringFormat format;
+ format.SetAlignment(StringAlignmentCenter);
+ RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14);
+ // \95¶\8e\9a\95`\89æ
+ gra->DrawString(bstr, -1, &font, r, &format, &strBrush);
+
+
+
+ return posY + 15;
+}
+
+void MakeBack(HWND hwnd, UINT x, UINT y){
+ MakeBackLock.on();
+
+ winWidth = x;
+ winHeight = y;
+
+ if (backGra){
+ ::delete backBmp;
+ ::delete backGra;
+ }
+
+ backBmp = ::new Bitmap(x,y);
+ backGra = ::new Graphics(backBmp);
+
+ // \91S\82Ä\94\92\82Å\93h\82è\82Â\82Ô\82µ
+ SolidBrush b(Color(255,255,255,255));
+ backGra->FillRectangle(&b, 0, 0, x, y);
+
+ backWidth = backImage->GetWidth();
+ backHeight = backImage->GetHeight();
+
+ // \94w\8ci\89æ\91\9c\82ð\95`\89æ
+ for (UINT xx = 0; xx < x/backWidth + 1; xx++){
+ for (UINT yy = 0; yy < y/backHeight + 1; yy++){
+ UINT width,height;
+ if (backWidth*(xx+1) > x){
+ width = x % backWidth;
+ } else {
+ width = backWidth;
+ }
+ if (backHeight*(yy+1) > y){
+ height = y % backHeight;
+ } else {
+ height = backHeight;
+ }
+ Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height);
+ backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel);
+ }
+ }
+
+ INT posX = 20;
+ INT posY = 20;
+
+ // \91¬\93x\95`\89æ
+ drawSpeed(backGra, winWidth-205, 5);
+
+ // \83`\83\83\83\93\83l\83\8b\8fî\95ñ\82ð\95`\89æ
+ ChannelDataLock.on();
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ posY = cd->drawChannel(backGra, 20, posY);
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ MakeBackLock.off();
+}
+
+void MakeBack(HWND hwnd){
+ MakeBack(hwnd, winWidth, winHeight);
+ ::InvalidateRect(guiWnd, NULL, FALSE);
+}
+
+void ChannelData::setData(Channel *c){
+ String sjis;
+ sjis = c->getName();
+ sjis.convertTo(String::T_SJIS);
+
+ strncpy(name, sjis, 256);
+ name[256] = '\0';
+ channel_id = c->channel_id;
+ bitRate = c->info.bitrate;
+ lastPlayStart = c->info.lastPlayStart;
+ status = c->status;
+ totalListeners = c->totalListeners();
+ totalRelays = c->totalRelays();
+ localListeners = c->localListeners();
+ localRelays = c->localRelays();
+ stayConnected = c->stayConnected;
+ chDisp = c->chDisp;
+ bTracker = c->sourceHost.tracker;
+ lastSkipTime = c->lastSkipTime;
+ skipCount = c->skipCount;
+}
+
+int gW = 0;
+int gWS = 0;
+
+int ChannelData::drawChannel(Graphics *g, int x, int y){
+ REAL xx = x * 1.0f;
+ REAL yy = y * 1.0f;
+ ServentData* sd;
+
+ // \88Ê\92u\82ð\95Û\91¶
+ posX = x;
+ posY = y;
+
+ int w,h;
+
+ if (getWidth() == 0){
+ if (gW){
+ w = gW;
+ } else {
+ w = 400;
+ }
+ } else {
+ w = getWidth();
+ gW = w;
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+ if (isSelected()){
+ // \91I\91ð\92\86
+ SolidBrush b(Color(160,49,106,197));
+ g->FillRectangle(&b, x, y, w, 14);
+ } else {
+ // \94ñ\91I\91ð
+ SolidBrush b(Color(160,255,255,255));
+ g->FillRectangle(&b, x, y, w, 14);
+ }
+
+ // \83X\83e\81[\83^\83X\95\\8e¦
+ Gdiplus::Image *img = NULL;
+ unsigned int nowTime = sys->getTime();
+ switch(this->getStatus()){
+ case Channel::S_IDLE:
+ img = img_idle;
+ break;
+ case Channel::S_SEARCHING:
+ case Channel::S_CONNECTING:
+ img = img_connect;
+ break;
+ case Channel::S_RECEIVING:
+ if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){
+ if (chDisp.relay){
+ img = img_conn_ok_skip;
+ } else {
+ if (chDisp.numRelays){
+ img = img_conn_full_skip;
+ } else {
+ img = img_conn_over_skip;
+ }
+ }
+ } else {
+ if (chDisp.relay){
+ img = img_conn_ok;
+ } else {
+ if (chDisp.numRelays){
+ img = img_conn_full;
+ } else {
+ img = img_conn_over;
+ }
+ }
+ }
+ break;
+ case Channel::S_BROADCASTING:
+ img = img_broad_ok;
+ break;
+ case Channel::S_ERROR:
+ img = img_error;
+ break;
+ default:
+ img = img_idle;
+ break;
+ }
+ // \95`\89æ\8aî\93_
+ PointF origin(xx, yy);
+ // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+ Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12);
+ // \83X\83e\81[\83^\83X\95`\89æ
+ ImageAttributes att;
+// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+ g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += img_rect.Width;
+
+ // \83t\83H\83\93\83g\90Ý\92è
+ Gdiplus::Font font(L"\82l\82r \82o\83S\83V\83b\83N",10);
+ // \95¶\8e\9a\90F
+ SolidBrush *strBrush;
+ if (servMgr->getFirewall() == ServMgr::FW_ON){
+ strBrush = ::new SolidBrush(Color::Red);
+ } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){
+ strBrush = ::new SolidBrush(Color::Green);
+ } else {
+ if (isSelected()){
+ // \91I\91ð\92\86
+ strBrush = ::new SolidBrush(Color::White);
+ } else {
+ // \94ñ\91I\91ð
+ strBrush = ::new SolidBrush(Color::Black);
+ }
+ }
+ // \83`\83\83\83\93\83l\83\8b\96¼\95\\8e¦
+ g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ _bstr_t bstr1(getName());
+ // \95¶\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+ RectF r1(origin.X, origin.Y, 120.0f, 13.0f);
+ StringFormat format;
+ format.SetAlignment(StringAlignmentNear);
+ g->DrawString(bstr1, -1, &font, r1, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r1.Width;
+
+ // \83\8a\83X\83i\81[\90\94/\83\8a\83\8c\81[\90\94\95\\8e¦
+ char tmp[256];
+ sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays());
+ _bstr_t bstr2(tmp);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ RectF r2(origin.X, origin.Y, 100.0f, 13.0f);
+ format.SetAlignment(StringAlignmentCenter);
+ g->DrawString(bstr2, -1, &font, r2, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r2.Width;
+
+ // bps\95\\8e¦
+ Font *f;
+ if (isStayConnected()){
+ f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint);
+ } else {
+ f = ::new Font(L"Arial", 9.0f);
+ }
+ sprintf(tmp, "%dkbps", getBitRate());
+ _bstr_t bstr3(tmp);
+ format.SetAlignment(StringAlignmentFar);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ RectF r3(origin.X, origin.Y, 80.0f, 13.0f);
+ g->DrawString(bstr3, -1, f, r3, &format, strBrush);
+ // \83t\83H\83\93\83g\8aJ\95ú
+ ::delete f;
+
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r3.Width;
+
+ // \83u\83\89\83V\8dí\8f\9c
+ ::delete strBrush;
+
+
+ // Servent\95\\8e¦
+ if (!openFlg){
+ int count = getServentCount();
+ // Servent\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82É\82·\82é
+ SolidBrush b(Color(160,255,255,255));
+ g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14);
+
+ sd = serventDataTop;
+ int index = 0;
+ while(sd){
+ SolidBrush *serventBrush;
+ if (sd->getInfoFlg()){
+ ChanHit *hit = sd->getChanHit();
+ if (hit->firewalled){
+ SolidBrush bb(Color(180,255,0,0));
+ g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14);
+ }
+ if (hit->relay){
+ // \83\8a\83\8c\81[\82n\82j
+ serventBrush = ::new SolidBrush(Color::Green);
+ } else {
+ // \83\8a\83\8c\81[\95s\89Â
+ if (hit->numRelays){
+ // \83\8a\83\8c\81[\88ê\94t
+ serventBrush = ::new SolidBrush(Color::Blue);
+ } else {
+ // \83\8a\83\8c\81[\82È\82µ
+ serventBrush = ::new SolidBrush(Color::Purple);
+ }
+ }
+ } else {
+ // \8fî\95ñ\82È\82µ
+ serventBrush = ::new SolidBrush(Color::Black);
+ }
+ // \8el\8ap\95`\89æ
+ backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12);
+
+ ::delete serventBrush;
+ sd = sd->getNextData();
+ index++;
+ }
+ }
+
+ // \8e\9f\82Ì\8aî\93_
+ origin.Y += 15;
+
+ // \83T\83C\83Y\82ð\95Û\91¶
+ setWidth((int)origin.X - posX);
+ setHeight((int)origin.Y - posY);
+
+ // ServentData\95\\8e¦
+ sd = serventDataTop;
+ while(sd){
+ if (openFlg || sd->getSelected()){
+ sd->drawServent(g, (INT)x+12, (INT)origin.Y);
+ // \8e\9f\82Ì\8aî\93_
+ origin.Y += 15;
+ }
+ sd = sd->getNextData();
+ }
+
+
+ return (int)(origin.Y);
+}
+
+bool ChannelData::checkDown(int x,int y){
+ // \94Í\88Í\93à\83`\83F\83b\83N
+ if (
+ (x > posX)
+ && (x < posX + getWidth())
+ && (y > posY)
+ && (y < posY + getHeight())
+ ){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ServentData *ChannelData::findServentData(int servent_id){
+ ServentData *sv = serventDataTop;
+ while(sv){
+ if (sv->getServentId() == servent_id){
+ return sv;
+ }
+ sv = sv->getNextData();
+ }
+ return NULL;
+}
+
+void ChannelData::addServentData(ServentData *sd){
+ sd->setNextData(serventDataTop);
+ serventDataTop = sd;
+}
+
+void ChannelData::deleteDisableServents(){
+ ServentData *sd = serventDataTop;
+ ServentData *prev = NULL;
+
+ while(sd){
+ if (!(sd->getEnableFlg())){
+ ServentData *next = sd->getNextData();
+ if (prev){
+ prev->setNextData(next);
+ } else {
+ serventDataTop = next;
+ }
+ ::delete sd;
+ sd = next;
+ } else {
+ prev = sd;
+ sd = sd->getNextData();
+ }
+ }
+}
+
+int ChannelData::getServentCount(){
+ int ret = 0;
+
+ ServentData *sd = serventDataTop;
+ while(sd){
+ ret++;
+ sd = sd->getNextData();
+ }
+ return ret;
+}
+
+bool ChannelData::setName(int servent_id, String name){
+ ServentData *sd = serventDataTop;
+ while(sd){
+ if (sd->getServentId() == servent_id){
+ sd->setName(name);
+ return TRUE;
+ }
+ sd = sd->getNextData();
+ }
+ return FALSE;
+}
+
+void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){
+ servent_id = s->servent_id;
+ type = s->type;
+ status = s->status;
+ lastSkipTime = s->lastSkipTime;
+ host = s->getHost();
+
+ chanHit.numRelays = hit->numRelays;
+ chanHit.relay = hit->relay;
+ chanHit.firewalled = hit->firewalled;
+ chanHit.version = hit->version;
+ chanHit.version_vp = hit->version_vp;
+ chanHit.version_ex_number = hit->version_ex_number;
+ chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0];
+ chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1];
+
+ totalListeners = listeners;
+ totalRelays = relays;
+
+ infoFlg = f;
+}
+
+int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){
+ REAL xx = x * 1.0f;
+ REAL yy = y * 1.0f;
+ int w,h;
+
+ // \88Ê\92u\82ð\95Û\91¶
+ posX = x;
+ posY = y;
+
+ if (getWidth() == 0){
+ if (gWS){
+ w = gWS;
+ } else {
+ w = 400;
+ }
+ } else {
+ w = getWidth();
+ gWS = w;
+ }
+
+ // \95`\89æ\8aî\93_
+ PointF origin(xx, yy);
+
+ // \83t\83H\83\93\83g\90Ý\92è
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",9);
+ // \95¶\8e\9a\90F
+ SolidBrush *strBrush;
+ if (chanHit.firewalled){
+ strBrush = ::new SolidBrush(Color::Red);
+ } else {
+ if (getSelected()){
+ // \91I\91ð\92\86
+ strBrush = ::new SolidBrush(Color::White);
+ } else {
+ // \94ñ\91I\91ð
+ strBrush = ::new SolidBrush(Color::Black);
+ }
+ }
+ // ServantData\95\\8e¦
+ g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ // \95¶\8e\9a\97ñ\8dì\90¬
+ char tmp[256];
+ char host1[256];
+ host.toStr(host1);
+
+ if (infoFlg){
+ if (chanHit.version_ex_number){
+ // \8ag\92£\83o\81[\83W\83\87\83\93
+ sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)",
+ chanHit.version_ex_prefix[0],
+ chanHit.version_ex_prefix[1],
+ chanHit.version_ex_number,
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ } else if (chanHit.version_vp){
+ sprintf(tmp, "VP%04d - %d/%d - %s(%s)",
+ chanHit.version_vp,
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ } else {
+ sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ }
+ } else {
+ sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ }
+ _bstr_t bstr1(tmp);
+
+ // \83X\83e\81[\83^\83X\95\\8e¦
+ Gdiplus::Image *img = NULL;
+ unsigned int nowTime = sys->getTime();
+ switch(getStatus()){
+ case Servent::S_CONNECTING:
+ img = img_connect;
+ break;
+ case Servent::S_CONNECTED:
+ if (lastSkipTime + 120 > nowTime){
+ if (chanHit.relay){
+ img = img_conn_ok_skip;
+ } else {
+ if (chanHit.numRelays){
+ img = img_conn_full_skip;
+ } else {
+ img = img_conn_over_skip;
+ }
+ }
+ } else {
+ if (chanHit.relay){
+ img = img_conn_ok;
+ } else {
+ if (chanHit.numRelays){
+ img = img_conn_full;
+ } else {
+ img = img_conn_over;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // \95¶\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+ RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f);
+ RectF r2;
+ StringFormat format;
+ format.SetAlignment(StringAlignmentNear);
+ g->MeasureString(bstr1, -1, &font, r1, &format, &r2);
+
+ w = (INT)r2.Width + img->GetWidth() + 2;
+ // ServentData\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+ if (getSelected()){
+ // \91I\91ð\92\86
+ SolidBrush b(Color(160,49,106,197));
+ g->FillRectangle(&b, x, y, w, 13);
+ } else {
+ // \94ñ\91I\91ð
+ SolidBrush b(Color(160,200,200,200));
+ g->FillRectangle(&b, x, y, w, 13);
+ }
+
+ // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+ Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12);
+ // \83X\83e\81[\83^\83X\95`\89æ
+ ImageAttributes att;
+// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+ g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += 12;
+
+ g->DrawString(bstr1, -1, &font, r2, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r2.Width;
+ origin.Y += 13;
+
+ setWidth((int)origin.X-posX);
+ setHeight((int)origin.Y - posY);
+
+ ::delete strBrush;
+ return 0;
+}
+
+bool ServentData::checkDown(int x, int y){
+ if (
+ (x > posX)
+ && (x < posX + getWidth())
+ && (y > posY)
+ && (y < posY + getHeight())
+ ){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+THREAD_PROC GUIDataUpdate(ThreadInfo *thread){
+ int i;
+
+ // set GUI thread status to running
+ thread->finish = false;
+
+ while(thread->active){
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83\8d\83b\83N
+ ChannelDataLock.on();
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82Ì\8dX\90V\83t\83\89\83O\82ð\91S\82ÄFALSE\82É\82·\82é
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ // Servent\82Ì\8dX\90V\83t\83\89\83O\82ðFALSE\82É\82·\82é
+ ServentData *sv = cd->getServentDataTop();
+ while(sv){
+ sv->setEnableFlg(FALSE);
+ sv = sv->getNextData();
+ }
+ cd->setEnableFlg(FALSE);
+ cd = cd->getNextData();
+ }
+
+ Channel *c = chanMgr->channel;
+ // \8c»\8dÝ\91¶\8dÝ\82·\82é\83`\83\83\83\93\83l\83\8b\95ª\83\8b\81[\83v
+ while(c){
+ // \8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\8e\9d\82Á\82Ä\82¢\82é\82©
+ cd = channelDataTop;
+ // \94\8c©\83t\83\89\83OFALSE
+ bool bFoundFlg = FALSE;
+ while(cd){
+ if (cd->getChannelId() == c->channel_id){
+ //\8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ª\82 \82é\82Ì\82Å\81A\82»\82Ì\82Ü\82Ü\8dX\90V
+ cd->setData(c);
+ // \8dX\90V\83t\83\89\83OTRUE
+ cd->setEnableFlg(TRUE);
+ // \94\8c©\83t\83\89\83OTRUE
+ bFoundFlg = TRUE;
+ // \83\8b\81[\83v\97£\92E
+ break;
+ }
+ // \8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87\81A\8e\9f\82Ì\83f\81[\83^\82ð\83`\83F\83b\83N
+ cd = cd->getNextData();
+ }
+
+ // \90V\82µ\82¢\83`\83\83\83\93\83l\83\8b\82Ì\8fê\8d\87\81A\90V\8bK\83f\81[\83^\8dì\90¬
+ if (!bFoundFlg){
+ // \90V\8bK\83f\81[\83^\8dì\90¬
+ cd = ::new ChannelData();
+ // \83f\81[\83^\8dX\90V
+ cd->setData(c);
+ // \8dX\90V\83t\83\89\83OTRUE
+ cd->setEnableFlg(TRUE);
+
+ // \90V\8bK\83f\81[\83^\82ð\83\8a\83X\83g\82Ì\90æ\93ª\82É\93ü\82ê\82é
+ cd->setNextData(channelDataTop);
+ channelDataTop = cd;
+ }
+ // \8e\9f\82Ì\83`\83\83\83\93\83l\83\8b\82ð\8eæ\93¾
+ c = c->next;
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\82ª\82È\82\82È\82Á\82Ä\82¢\82é\8fê\8d\87\82Ì\8f\88\97\9d
+ cd = channelDataTop;
+ ChannelData *prev = NULL;
+ while(cd){
+ // \83f\81[\83^\82ð\8dX\90V\82µ\82È\82©\82Á\82½\82©
+ if (cd->getEnableFlg() == FALSE){
+ // \83`\83\83\83\93\83l\83\8b\82ª\82È\82\82È\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c
+ ChannelData *next;
+ next = cd->getNextData();
+ if (!prev){
+ // \90æ\93ª\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+ channelDataTop = next;
+ } else {
+ // \93r\92\86\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+ prev->setNextData(next);
+ }
+ // \8e\9f\82Ì\83f\81[\83^\82Ö
+ cd = next;
+ } else {
+ // \83f\81[\83^\8dX\90V\8dÏ\81F\8e\9f\82Ì\83f\81[\83^\82Ö
+ prev = cd;
+ cd = cd->getNextData();
+ }
+ }
+
+ Servent *s = servMgr->servents;
+ while(s){
+ // \8f\89\8aú\89»
+ ChanHitList *chl;
+ bool infoFlg = false;
+ bool relay = true;
+ bool firewalled = false;
+ unsigned int numRelays = 0;
+ int vp_ver = 0;
+ char ver_ex_prefix[2] = {' ',' '};
+ int ver_ex_number = 0;
+ // \92¼\89º\83z\83X\83g\8fî\95ñ\83`\83F\83b\83N
+ unsigned int totalRelays = 0;
+ unsigned int totalListeners = 0;
+
+ ChanHit hitData;
+ // \8eó\90M\92\86\82©
+ if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){
+ // \83z\83X\83g\8fî\95ñ\83\8d\83b\83N
+ chanMgr->hitlistlock.on();
+ // \92¼\89º\83z\83X\83g\82ª\8eó\90M\82µ\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\8eæ\93¾
+ chl = chanMgr->findHitListByID(s->chanID);
+ // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\82©
+ if (chl){
+ // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\8fê\8d\87
+ ChanHit *hit = chl->hit;
+ //\81@\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\91S\91\96\8d¸\82µ\82Ä
+ while(hit){
+ // ID\82ª\93¯\82¶\82à\82Ì\82Å\82 \82ê\82Î
+ if (hit->servent_id == s->servent_id){
+ // \83g\81[\83^\83\8b\83\8a\83\8c\81[\82Æ\83g\81[\83^\83\8b\83\8a\83X\83i\81[\82ð\89Á\8eZ
+ totalRelays += hit->numRelays;
+ totalListeners += hit->numListeners;
+ // \92¼\89º\82Å\82 \82ê\82Î
+ if (hit->numHops == 1){
+ // \8fî\95ñ\82ð\88ê\92U\95Û\91¶
+ infoFlg = true;
+ hitData.relay = hit->relay;
+ hitData.firewalled = hit->firewalled;
+ hitData.numRelays = hit->numRelays;
+ hitData.version_vp = hit->version_vp;
+ hitData.version_ex_prefix[0] = hit->version_ex_prefix[0];
+ hitData.version_ex_prefix[1] = hit->version_ex_prefix[1];
+ hitData.version_ex_number = hit->version_ex_number;
+ }
+ }
+ // \8e\9f\82ð\83`\83F\83b\83N
+ hit = hit->next;
+ }
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82©\82çServent\82ð\8c\9f\8dõ
+ bool bFoundFlg = FALSE;
+ cd = channelDataTop;
+ while(cd){
+ ServentData *sv = cd->findServentData(s->servent_id);
+ // ServentData\82ª\82 \82ê\82Î
+ if (sv){
+ // \83f\81[\83^\90Ý\92è
+ sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+ sv->setEnableFlg(TRUE);
+ bFoundFlg = TRUE;
+ break;
+ }
+ cd = cd->getNextData();
+ }
+ // ServentData\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87
+ if (!bFoundFlg){
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\92T\82·
+ cd = channelDataTop;
+ while(cd){
+ // \83`\83\83\83\93\83l\83\8bID\82ª\93¯\82¶\82©
+ if (cd->getChannelId() == s->channel_id){
+ // \83f\81[\83^\90Ý\92è
+ ServentData *sv = ::new ServentData();
+ sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+ sv->setEnableFlg(TRUE);
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ÉServentData\92Ç\89Á
+ cd->addServentData(sv);
+ // \83z\83X\83g\96¼\82ð\8eæ\93¾\82·\82é
+ IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip);
+ ThreadInfo t;
+ t.func = GetHostName;
+ t.data = (void*)id;
+ sys->startThread(&t);
+ // \83\8b\81[\83v\8fI\97¹
+ break;
+ }
+ // \8e\9f\82Ì\83f\81[\83^\82Ö
+ cd = cd->getNextData();
+ }
+ }
+ // \83z\83X\83g\8fî\95ñ\83A\83\93\83\8d\83b\83N
+ chanMgr->hitlistlock.off();
+ }
+ s = s->next;
+ }
+
+ // \8dX\90V\82µ\82Ä\82¢\82È\82¢ServentData\82ð\8dí\8f\9c
+ cd = channelDataTop;
+ while(cd){
+ cd->deleteDisableServents();
+ cd = cd->getNextData();
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83A\83\93\83\8d\83b\83N
+ ChannelDataLock.off();
+
+ // \95`\89æ\8dX\90V
+ if (guiWnd){
+ MakeBack(guiWnd);
+ }
+
+ // 0.1\95b\81~10\82Å1\95b\91Ò\82¿
+ for(i=0; i<10; i++)
+ {
+ if (!thread->active)
+ break;
+ sys->sleep(100);
+ }
+
+ if (gbGetFile && (sys->getTime() > gtGetFile)){
+ gbGetFile = false;
+ gtiGetFile.func = GetInternetFile;
+ gtiGetFile.data = NULL;
+ sys->startThread(>iGetFile);
+ }
+ else if (gbStart && (sys->getTime() > gtStartTime)){
+ gbStart = false;
+ SendMessage(guiWnd, WM_START, 0, 0);
+ gtiStart.func = FestivalStart;
+ gtiStart.data = NULL;
+ sys->startThread(>iStart);
+ }
+ }
+
+ // set GUI thread status to terminated
+ thread->finish = true;
+
+ return 0;
+}
+
+ChannelData *findChannelData(int channel_id){
+ ChannelData *cd = channelDataTop;
+
+ while(cd){
+ if (cd->getChannelId() == channel_id){
+ return cd;
+ }
+ cd = cd->getNextData();
+ }
+
+ return NULL;
+}
+
+
+void PopupChannelMenu(int channel_id){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ ChannelData *cd = findChannelData(channel_id);
+
+ if (cd == NULL){
+ return;
+ }
+
+ info.wID = 1001;
+ info.dwTypeData = "\90Ø\92f";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ info.wID = 1000;
+ info.dwTypeData = "\8dÄ\90¶";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ info.wID = 1002;
+ info.dwTypeData = "\8dÄ\90Ú\91±";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ info.wID = 1003;
+ info.dwTypeData = "\83L\81[\83v";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!cd->getOpenFlg()){
+ info.wID = 1004;
+ info.dwTypeData = "\92¼\89º\95\\8e¦";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1005;
+ info.dwTypeData = "\92¼\89º\89B\95Á";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ cd = findChannelData(channel_id);
+
+ if (cd == NULL){
+ return;
+ }
+
+ Channel *c = chanMgr->findChannelByChannelID(channel_id);
+
+ if (c == NULL){
+ return;
+ }
+
+ switch(dwID){
+ case 1000: // \8dÄ\90¶
+ chanMgr->playChannel(c->info);
+ break;
+
+ case 1001: // \90Ø\92f
+ c->thread.active = false;
+ c->thread.finish = true;
+ break;
+
+ case 1002: // \8dÄ\90Ú\91±
+ c->bump = true;
+ break;
+
+ case 1003: // \83L\81[\83v
+ if (!c->stayConnected){
+ c->stayConnected = true;
+ } else {
+ c->stayConnected = false;
+ }
+ break;
+
+ case 1004: // \92¼\89º\95\\8e¦
+ cd->setOpenFlg(TRUE);
+ MakeBack(guiWnd);
+ break;
+
+ case 1005: // \92¼\89º\89B\95Á
+ cd->setOpenFlg(FALSE);
+ MakeBack(guiWnd);
+ break;
+ }
+}
+
+void PopupServentMenu(int servent_id){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ ServentData *sd = NULL;
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ sd = cd->findServentData(servent_id);
+ if (sd){
+ break;
+ }
+ cd = cd->getNextData();
+ }
+
+ if (cd == NULL || sd == NULL){
+ return;
+ }
+
+ info.wID = 1001;
+ info.dwTypeData = "\90Ø\92f";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+// InsertMenuItem(hMenu, -1, true, &separator);
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ cd = channelDataTop;
+ while(cd){
+ sd = cd->findServentData(servent_id);
+ if (sd){
+ break;
+ }
+ cd = cd->getNextData();
+ }
+
+ if (cd == NULL || sd == NULL){
+ return;
+ }
+
+ Servent *s = servMgr->findServentByServentID(servent_id);
+
+ if (s == NULL){
+ return;
+ }
+
+ switch(dwID){
+ case 1001: // \90Ø\92f
+ s->thread.active = false;
+ break;
+
+ }
+}
+
+void PopupOtherMenu(){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ if (!gbDispTop){
+ info.wID = 1101;
+ info.dwTypeData = "\8dÅ\91O\96Ê\95\\8e¦";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1102;
+ info.dwTypeData = "\8dÅ\91O\96Ê\89ð\8f\9c";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!gbAllOpen){
+ info.wID = 1103;
+ info.dwTypeData = "\91S\92¼\89º\93W\8aJ";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1104;
+ info.dwTypeData = "\91S\92¼\89º\89B\95Á";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!servMgr->autoServe){
+ info.wID = 1105;
+ info.dwTypeData = "\97L\8cø";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1106;
+ info.dwTypeData = "\96³\8cø";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ ChannelData *cd = channelDataTop;
+
+ switch(dwID){
+ case 1101: // \8dÅ\91O\96Ê\95\\8e¦
+ gbDispTop = true;
+ ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ break;
+
+ case 1102: // \8dÅ\91O\96Ê\89ð\8f\9c
+ gbDispTop = false;
+ ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ break;
+
+ case 1103: // \91S\92¼\89º\93W\8aJ
+ gbAllOpen = true;
+ while(cd){
+ cd->setOpenFlg(true);
+ cd = cd->getNextData();
+ }
+ break;
+
+ case 1104: // \91S\92¼\89º\89B\95Á
+ gbAllOpen = false;
+ while(cd){
+ cd->setOpenFlg(false);
+ cd = cd->getNextData();
+ }
+ break;
+
+ case 1105: // \97L\8cø
+ servMgr->autoServe = true;
+ break;
+
+ case 1106: // \96³\8cø
+ servMgr->autoServe = false;
+ break;
+
+ }
+}
+
+void WmCreateProc(HWND hwnd){
+ if (backImage){
+ ::delete backImage;
+ }
+ _bstr_t bstr("back.jpg");
+ backImage = ::new Image(bstr);
+
+ MakeBack(hwnd, 800, 600);
+
+ guiThread.func = GUIDataUpdate;
+ if (!sys->startThread(&guiThread)){
+ MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR);
+ PostMessage(hwnd,WM_DESTROY,0,0);
+ }
+ if (guiFlg){
+ SetWindowPlacement(hwnd, &winPlace);
+ }
+
+ if (img_idle){
+ ::delete img_idle;
+ ::delete img_connect;
+ ::delete img_conn_ok;
+ ::delete img_conn_full;
+ ::delete img_conn_over;
+ ::delete img_conn_ok_skip;
+ ::delete img_conn_full_skip;
+ ::delete img_conn_over_skip;
+ ::delete img_error;
+ ::delete img_broad_ok;
+ ::delete img_broad_full;
+ }
+ bstr = L"ST_IDLE.bmp";
+ img_idle = ::new Image(bstr);
+ bstr = L"ST_CONNECT.bmp";
+ img_connect = ::new Image(bstr);
+ bstr = L"ST_CONN_OK.bmp";
+ img_conn_ok = ::new Image(bstr);
+ bstr = L"ST_CONN_FULL.bmp";
+ img_conn_full = ::new Image(bstr);
+ bstr = L"ST_CONN_OVER.bmp";
+ img_conn_over = ::new Image(bstr);
+ bstr = L"ST_CONN_OK_SKIP.bmp";
+ img_conn_ok_skip = ::new Image(bstr);
+ bstr = L"ST_CONN_FULL_SKIP.bmp";
+ img_conn_full_skip = ::new Image(bstr);
+ bstr = L"ST_CONN_OVER_SKIP.bmp";
+ img_conn_over_skip = ::new Image(bstr);
+ bstr = L"ST_ERROR.bmp";
+ img_error = ::new Image(bstr);
+ bstr = L"ST_BROAD_OK.bmp";
+ img_broad_ok = ::new Image(bstr);
+ bstr = L"ST_BROAD_FULL.bmp";
+ img_broad_full = ::new Image(bstr);
+}
+
+void WmPaintProc(HWND hwnd){
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ if (backGra){
+ MakeBackLock.on();
+ hdc = BeginPaint(hwnd, &paint);
+ RECT *rcRect; // \95`\89æ\94Í\88Í
+ rcRect = &(paint.rcPaint);
+ LONG width = rcRect->right - rcRect->left + 1;
+ LONG height = rcRect->bottom - rcRect->top + 1;
+
+ Graphics g2(hdc);
+ Rect r(rcRect->left, rcRect->top, width, height);
+ g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel);
+ EndPaint(hwnd, &paint);
+ MakeBackLock.off();
+ }
+}
+
+void WmSizeProc(HWND hwnd, LPARAM lParam){
+ UINT width = LOWORD(lParam);
+ UINT height = HIWORD(lParam);
+
+ MakeBack(hwnd, width, height);
+
+}
+
+void WmLButtonDownProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+
+ ChannelDataLock.on();
+ cd = channelDataTop;
+ while(cd){
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(TRUE);
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+ int sx = cd->getPosX() + cd->getWidth();
+ int sy = cd->getPosY();
+ int index = 0;
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if ( ( (!cd->getOpenFlg())
+ && (sx + index*14 < x)
+ && (x < sx + (index+1)*14)
+ && (sy < y)
+ && (y < sy + 14) )
+ || sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+ ){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ index++;
+ }
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+}
+
+void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+
+ ChannelDataLock.on();
+ cd = channelDataTop;
+ while(cd){
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ if (!(cd->getOpenFlg())){
+ changeFlg = TRUE;
+ cd->setOpenFlg(TRUE);
+ } else {
+ changeFlg = TRUE;
+ cd->setOpenFlg(FALSE);
+ }
+ cd->setSelected(TRUE);
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+/* int sx = cd->getPosX() + cd->getWidth();
+ int sy = cd->getPosY();
+ int index = 0;
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if ( ( (!cd->getOpenFlg())
+ && (sx + index*14 < x)
+ && (x < sx + (index+1)*14)
+ && (sy < y)
+ && (y < sy + 14) )
+ || sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+ ){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ index++;
+ }*/
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+}
+
+void WmRButtonDownProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+ bool channel_selected = FALSE;
+ bool servent_selected = FALSE;
+ int channel_id = 0;
+ int servent_id = 0;
+
+ cd = channelDataTop;
+ while(cd){
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(TRUE);
+ channel_id = cd->getChannelId();
+ channel_selected = TRUE;
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ servent_id = sd->getServentId();
+ servent_selected = TRUE;
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ }
+ cd = cd->getNextData();
+ }
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+
+ if (channel_selected){
+ PopupChannelMenu(channel_id);
+ } else if (servent_selected){
+ PopupServentMenu(servent_id);
+ } else {
+ PopupOtherMenu();
+ }
+}
+
+LRESULT CALLBACK GUIProc (HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ switch(message){
+ case WM_CREATE: // \83E\83B\83\93\83h\83E\8dì\90¬
+ WmCreateProc(hwnd);
+ break;
+
+ case WM_PAINT: // \95`\89æ
+ WmPaintProc(hwnd);
+ break;
+
+ case WM_SIZE: // \83T\83C\83Y\95Ï\8dX
+ WmSizeProc(hwnd,lParam);
+ break;
+
+ case WM_LBUTTONDOWN: // \8d¶\83{\83^\83\93\89\9f\82·
+ WmLButtonDownProc(hwnd,lParam);
+ break;
+
+ case WM_RBUTTONDOWN: // \89E\83{\83^\83\93\89\9f\82·
+ WmRButtonDownProc(hwnd,lParam);
+ break;
+
+ case WM_LBUTTONDBLCLK: // \8d¶\83_\83u\83\8b\83N\83\8a\83b\83N
+ WmLButtonDblclkProc(hwnd,lParam);
+ break;
+
+ case WM_ERASEBKGND: // \94w\8ci\8fÁ\8b\8e
+ return TRUE; // \94w\8ci\82Í\8fÁ\82³\82È\82¢
+
+ case WM_CLOSE:
+ //if (backImage){
+ // ::delete backImage;
+ // backImage = NULL;
+ //}
+ GetWindowPlacement(hwnd, &winPlace);
+ guiFlg = true;
+ DestroyWindow( hwnd );
+ break;
+ case WM_DESTROY:
+ GetWindowPlacement(hwnd, &winPlace);
+ guiFlg = true;
+ guiThread.active = false;
+
+ // wait until GUI thread terminated,
+ // and then dispose background image.
+ while (1)
+ {
+ if (guiThread.finish)
+ break;
+ }
+ if (backImage)
+ {
+ ::delete backImage;
+ backImage = NULL;
+ }
+
+ guiWnd = NULL;
+ break;
+ case WM_START:
+ ghStart = ::CreateWindow(szWindowClass3,
+ "Peercast-IM@S",
+ WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX),
+ 0,
+ 0,
+ 400,
+ 300,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+ ::ShowWindow(ghStart, SW_SHOWNORMAL);
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+Gdiplus::Image *data1 = NULL;
+Gdiplus::Image *data2 = NULL;
+Gdiplus::Bitmap *startBmp = NULL;
+Gdiplus::Graphics *startGra = NULL;
+WLock MakeStartLock;
+
+LRESULT CALLBACK StartProc (HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ SolidBrush b(Color::Black);
+ bstr_t bstr;
+
+ switch(message){
+ case WM_CREATE:
+ startBmp = ::new Bitmap(400,300);
+ startGra = ::new Graphics(startBmp);
+ bstr = L"data1.jpg";
+ data1 = ::new Image(bstr);
+ bstr = L"data2.jpg";
+ data2 = ::new Image(bstr);
+ // \8d\95\82Å\93h\82è\82Â\82Ô\82µ
+ startGra->FillRectangle(&b, 0, 0, 400, 300);
+ break;
+ case WM_PAINT:
+ if (startGra){
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ MakeStartLock.on();
+ hdc = BeginPaint(hwnd, &paint);
+ RECT *rcRect;
+ rcRect = &(paint.rcPaint);
+ LONG width = rcRect->right - rcRect->left + 1;
+ LONG height = rcRect->bottom - rcRect->top + 1;
+
+ Graphics g2(hdc);
+ Rect r(rcRect->left, rcRect->top, width, height);
+ g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel);
+ EndPaint(hwnd, &paint);
+ MakeStartLock.off();
+ }
+ break;
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_CLOSE:
+ DestroyWindow(ghStart);
+ if (startBmp){
+ ::delete startBmp;
+ }
+ if (startGra){
+ ::delete startGra;
+ }
+ if (data1){
+ ::delete data1;
+ }
+ if (data2){
+ ::delete data2;
+ }
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+THREAD_PROC FestivalStart(ThreadInfo *thread){
+
+ while(startGra==NULL){
+ sys->sleep(100);
+ }
+
+ sys->sleep(1000);
+
+ MakeStartLock.on();
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",40);
+ StringFormat format;
+ format.SetAlignment(StringAlignmentCenter);
+ startGra->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ PointF origin(199.0f,49.0f);
+ RectF rect(0,0,400,100);
+ LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\91æ\82Q\89ñ", -1, &font, origin, &format, &b1);
+ origin.Y += 50;
+ LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\83A\83C\83h\83\8b\83}\83X\83^\81[", -1, &font, origin, &format, &b2);
+ origin.Y += 50;
+ LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\83t\83@\83\93\8a´\8eÓ\8dÕ", -1, &font, origin, &format, &b3);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(3000);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ for (int i=1; i<=10; i++){
+ ColorMatrix mtx = {
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+ ImageAttributes att;
+
+ MakeStartLock.on();
+ att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
+ startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(100);
+ }
+
+ sys->sleep(2000);
+
+ MakeStartLock.on();
+ INT style = FontStyleBold;
+ Font font2(L"\82l\82r \82o\83S\83V\83b\83N",70,style,UnitPoint);
+ PointF origin2(199.0f,99.0f);
+ SolidBrush bs(Color::Black);
+ startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs);
+ Font font3(L"\82l\82r \82o\83S\83V\83b\83N",70,style,UnitPoint);
+ LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal);
+ startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(5000);
+
+ SendMessage(ghStart, WM_CLOSE, 0, 0);
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : gui.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GUI_H
+#define _GUI_H
+
+#include "sys.h"
+#include "gdiplus.h"
+#include "channel.h"
+
+extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type);
+
+extern String iniFileName;
+extern HWND guiWnd;
+extern int logID;
+
+enum
+{
+ WM_INITSETTINGS = WM_USER,
+ WM_GETPORTNUMBER,
+ WM_PLAYCHANNEL,
+ WM_TRAYICON,
+ WM_SHOWGUI,
+ WM_SHOWMENU,
+ WM_PROCURL,
+ WM_START
+
+};
+
+class IdData
+{
+private:
+ int channel_id;
+ int servent_id;
+ unsigned int ip_addr;
+
+public:
+ IdData(int cid, int sid, unsigned int ip){
+ channel_id = cid;
+ servent_id = sid;
+ ip_addr = ip;
+ }
+
+ int getChannelId(){return channel_id;};
+ int getServentId(){return servent_id;};
+ unsigned int getIpAddr(){return ip_addr;};
+};
+
+class ServentData
+{
+private:
+ int servent_id;
+ int type;
+// unsigned int tnum;
+ int status;
+// String agent;
+ Host host;
+ String hostname;
+// unsigned int syncpos;
+// char *typeStr;
+// char *statusStr;
+// bool infoFlg;
+// bool relay;
+// bool firewalled;
+ unsigned int totalRelays;
+ unsigned int totalListeners;
+// int vp_ver;
+// char ver_ex_prefix[2];
+// int ver_ex_number;
+
+ bool EnableFlg;
+ bool infoFlg;
+ ServentData *next;
+ ChanHit chanHit;
+ bool selected;
+ int posX;
+ int posY;
+ int width;
+ int height;
+
+ unsigned int lastSkipTime;
+ unsigned int lastSkipCount;
+
+public:
+ ServentData(){
+ next = NULL;
+ EnableFlg = false;
+ infoFlg = false;
+
+ posX = 0;
+ posY = 0;
+ width = 0;
+ selected = false;
+
+ }
+ void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg);
+ bool getInfoFlg(){return infoFlg;}
+ ChanHit *getChanHit(){return &chanHit;};
+ int getStatus(){return status;};
+ Host getHost(){return host;};
+
+ int getServentId(){return servent_id;};
+
+ bool getEnableFlg(){return EnableFlg;};
+ void setEnableFlg(bool f){EnableFlg = f;};
+ ServentData *getNextData(){return next;};
+ void setNextData(ServentData *s){next = s;};
+ bool getSelected(){return selected;};
+ void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}};
+ int getWidth(){return width;};
+ void setWidth(int w){width = w;};
+ int getHeight(){return height;};
+ void setHeight(int h){height = h;};
+ String getName(){return hostname;};
+ void setName(String n){hostname = n;};
+
+ int drawServent(Gdiplus::Graphics *g, int x, int y);
+
+ bool checkDown(int x, int y);
+
+};
+
+class ChannelData {
+
+private:
+ int channel_id;
+ char name[257];
+ int bitRate;
+ unsigned int lastPlayStart;
+ int status;
+ int totalListeners;
+ int totalRelays;
+ int localListeners;
+ int localRelays;
+ bool stayConnected;
+ ChanHit chDisp;
+ bool bTracker;
+ unsigned int lastSkipTime;
+ unsigned int skipCount;
+
+ bool EnableFlg;
+ ChannelData *next;
+
+ int posX;
+ int posY;
+ int width;
+ int height;
+ bool selected;
+ ServentData *serventDataTop;
+ bool openFlg;
+
+public:
+ ChannelData(){
+ EnableFlg = FALSE;
+ next = NULL;
+ posX = 0;
+ posY = 0;
+ width = 0;
+ height = 0;
+ selected = FALSE;
+ serventDataTop = NULL;
+ openFlg = FALSE;
+ }
+ int drawChannel(Gdiplus::Graphics *g, int x, int y);
+
+ void setData(Channel *);
+ int getChannelId(){return channel_id;};
+ char* getName(){return &(name[0]);};
+ int getBitRate(){return bitRate;};
+ bool isStayConnected(){return stayConnected;};
+ bool isTracker(){return bTracker;};
+ int getStatus(){return status;};
+ unsigned int getLastSkipTime(){return lastSkipTime;};
+
+ int getTotalListeners(){return totalListeners;};
+ int getTotalRelays(){return totalRelays;};
+ int getLocalListeners(){return localListeners;};
+ int getLocalRelays(){return localRelays;};
+
+ bool getEnableFlg(){return EnableFlg;};
+ void setEnableFlg(bool flg){EnableFlg = flg;};
+ ChannelData *getNextData(){return next;};
+ void setNextData(ChannelData* cd){next = cd;};
+
+ int getPosX(){return posX;};
+ void setPosX(int x){posX = x;}
+ int getPosY(){return posY;};
+ void setPosY(int y){posY = y;};
+ int getWidth(){return width;};
+ void setWidth(int w){width = w;};
+ int getHeight(){return height;};
+ void setHeight(int h){height = h;};
+ bool isSelected(){return selected;};
+ void setSelected(bool sel){selected = sel;};
+ bool getOpenFlg(){return openFlg;};
+ void setOpenFlg(bool b){openFlg = b;};
+
+ ServentData* getServentDataTop(){return serventDataTop;};
+ ServentData* findServentData(int servent_id);
+ void addServentData(ServentData *sd);
+ void deleteDisableServents();
+
+ bool setName(int servent_id, String name);
+ int getServentCount();
+
+ bool checkDown(int x, int y);
+};
+
+
+
+#endif
\ No newline at end of file
--- /dev/null
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Simple.rc
+//
+#define IDC_MYICON 2
+#define IDD_MAINWINDOW 101
+#define IDD_SIMPLE_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDS_APP_TITLE 103
+#define IDM_ABOUT 104
+#define IDM_EXIT 105
+#define IDS_HELLO 106
+#define IDI_SIMPLE 107
+#define IDI_SMALL 108
+#define IDC_SIMPLE 109
+#define IDI_SMALL2 109
+#define IDR_MAINFRAME 128
+#define IDR_TRAYMENU 130
+#define IDR_VERMENU 133
+#define IDD_CHANINFO 136
+#define IDR_LTRAYMENU 137
+#define IDC_LIST1 1000
+#define IDC_BUTTON7 1001
+#define IDC_ABOUTVER 1002
+#define IDC_CHECK1 1003
+#define IDC_EDIT1 1004
+#define IDC_LIST2 1005
+#define IDC_EDIT_PLAYING 1005
+#define IDC_COMBO1 1006
+#define IDC_EDIT_MESSAGE 1006
+#define IDC_CHECK2 1007
+#define IDC_EDIT_NAME 1007
+#define IDC_BUTTON1 1008
+#define IDC_EDIT_DESC 1008
+#define IDC_DETAILS 1009
+#define IDC_MAXRELAYS 1009
+#define IDC_LIST3 1010
+#define IDC_PLAY 1010
+#define IDC_CONTACT 1011
+#define IDC_EDIT2 1012
+#define IDC_FORMAT 1013
+#define IDC_EDIT_GENRE 1014
+#define IDC_KEEP 1015
+#define IDC_EDIT_STATUS 1016
+#define IDC_GROUPBOX_RELAY 1016
+#define IDC_EDIT_LISTENERS 1017
+#define IDC_STATIC_CONNECTION 1017
+#define IDC_LIST4 1018
+#define IDC_EDIT_HOSTS 1018
+#define IDC_STATIC_LOG 1018
+#define IDC_BUTTON4 1019
+#define IDC_BUTTON5 1020
+#define IDC_BUTTON6 1021
+#define IDC_EDIT3 1025
+#define IDC_EDIT5 1027
+#define IDC_LOGDEBUG 1037
+#define IDC_LOGNETWORK 1038
+#define IDC_LOGERRORS 1039
+#define IDC_CHECK9 1041
+#define IDC_BUTTON8 1043
+#define IDC_BUTTON10 1046
+#define IDC_BUTTON11 1047
+#define IDC_LOGCHANNELS 1050
+#define IDC_BUTTON2 1056
+#define IDC_EDIT4 1058
+#define IDC_BUTTON3 1059
+#define IDC_EDIT9 1060
+#define IDC_CHECK11 1061
+#define IDC_BUTTON9 1062
+#define IDM_SETTINGS_GUI 32771
+#define ID_POPUP_ABOUT 32779
+#define ID_POPUP_EXIT_CONFIRM 32781
+#define ID_POPUP_EXIT_NO 32782
+#define ID_POPUP_SETTINGS 32785
+#define ID_POPUP_CONNECTIONS 32786
+#define ID_POPUP_SHOWGUI 32788
+#define ID_POPUP_ALLCHANNELS 32791
+#define ID_POPUP_FAVORITES_EDIT 32792
+#define ID_POPUP_ADVANCED_INFORMATION 32793
+#define ID_POPUP_ADVANCED_SAVESETTINGS 32794
+#define ID_POPUP_UPGRADE 32795
+#define ID_POPUP_HELP 32796
+#define ID_POPUP_ADVANCED_VIEWLOG 32797
+#define ID_POPUP_FAVORITES_PLAYALL 32798
+#define ID_POPUP_ADVANCED_ALLCHANNELS 32799
+#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800
+#define ID_POPUP_ADVANCED_BROADCAST 32801
+#define ID_FIND_CHANNELS 32808
+#define ID_POPUP_SHOWMESSAGES_PEERCAST 32814
+#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815
+#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816
+#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817
+#define ID_POPUP_YELLOWPAGES 32818
+#define ID_POPUP_ADVANCED_SHOWGUI 32819
+#define ID_POPUP_YELLOWPAGES1 32820
+#define ID_POPUP_YELLOWPAGES2 32821
+#define ID_POPUP_SAVE_GUI_POS 32823
+#define ID_POPUP_KEEP_DOWNSTREAMS 32825
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 142
+#define _APS_NEXT_COMMAND_VALUE 32826
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : asf.h
+// Date: 10-apr-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ASF_H
+#define _ASF_H
+
+
+#include "stream.h"
+
+// -----------------------------------
+class MSID
+{
+public:
+
+ void read(Stream &in)
+ {
+ data1 = in.readLong();
+ data2 = in.readShort();
+ data3 = in.readShort();
+ in.read(data4,8);
+ }
+
+ void write(Stream &out)
+ {
+ out.writeLong(data1);
+ out.writeShort(data2);
+ out.writeShort(data3);
+ out.write(data4,8);
+ }
+
+
+ void toString(String &s)
+ {
+ sprintf(s.data,"%X-%X-%X-%02X%02X%02X%02X%02X%02X%02X%02X",
+ data1,data2,data3,
+ data4[0],data4[1],data4[2],data4[3],
+ data4[4],data4[5],data4[6],data4[7]);
+ }
+
+ int operator==(const MSID& msid) const{return !memcmp(this, &msid, sizeof(MSID));}
+
+ unsigned int data1;
+ unsigned short data2,data3;
+ unsigned char data4[8];
+
+};
+
+
+
+
+// -----------------------------------
+const MSID headObjID=
+ {0x75B22630, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID dataObjID=
+ {0x75B22636, 0x668E, 0x11CF, 0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C};
+const MSID filePropObjID=
+ {0x8CABDCA1, 0xA947, 0x11CF, 0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65};
+const MSID streamPropObjID=
+ {0xB7DC0791, 0xA9B7, 0x11CF, 0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65};
+
+const MSID audioStreamObjID=
+ {0xF8699E40, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+const MSID videoStreamObjID=
+ {0xBC19EFC0, 0x5B4D, 0x11CF, 0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B};
+
+const MSID streamBitrateObjID=
+ {0x7BF875CE, 0x468D, 0x11D1, 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2};
+
+
+// -----------------------------------
+class ASFObject
+{
+public:
+
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_HEAD_OBJECT,
+ T_DATA_OBJECT,
+ T_FILE_PROP,
+ T_STREAM_PROP,
+ T_STREAM_BITRATE
+ };
+
+ int getTotalLen()
+ {
+ return 24+dataLen;
+ }
+
+ unsigned int readHead(Stream &in)
+ {
+ id.read(in);
+
+ lenLo = in.readLong();
+ lenHi = in.readLong();
+
+ type = T_UNKNOWN;
+ if (id == headObjID)
+ type = T_HEAD_OBJECT;
+ else if (id == dataObjID)
+ type = T_DATA_OBJECT;
+ else if (id == filePropObjID)
+ type = T_FILE_PROP;
+ else if (id == streamPropObjID)
+ type = T_STREAM_PROP;
+ else if (id == streamBitrateObjID)
+ type = T_STREAM_BITRATE;
+
+ String str;
+ id.toString(str);
+ LOG_DEBUG("ASF: %s (%s)= %d : %d\n",str.data,getTypeName(),lenLo,lenHi);
+
+
+ dataLen = 0;
+
+ return lenLo-24;
+ }
+
+ void readData(Stream &in,int len)
+ {
+ dataLen = len;
+
+ if ((dataLen > sizeof(data)) || (lenHi))
+ throw StreamException("ASF object too big");
+
+ in.read(data,dataLen);
+ }
+
+
+ void write(Stream &out)
+ {
+ id.write(out);
+ out.writeLong(lenLo);
+ out.writeLong(lenHi);
+ if (dataLen)
+ out.write(data,dataLen);
+ }
+
+ const char *getTypeName()
+ {
+ switch(type)
+ {
+ case T_HEAD_OBJECT:
+ return "ASF_Header_Object";
+ case T_DATA_OBJECT:
+ return "ASF_Data_Object";
+ case T_FILE_PROP:
+ return "ASF_File_Properties_Object";
+ case T_STREAM_PROP:
+ return "ASF_Stream_Properties_Object";
+ case T_STREAM_BITRATE:
+ return "ASF_Stream_Bitrate_Properties_Object";
+ default:
+ return "Unknown_Object";
+ }
+ }
+
+ char data[8192];
+ MSID id;
+ unsigned int lenLo,lenHi,dataLen;
+ TYPE type;
+};
+// -----------------------------------
+class ASFStream
+{
+public:
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_AUDIO,
+ T_VIDEO
+ };
+
+ void read(Stream &in)
+ {
+ MSID sid;
+ sid.read(in);
+
+ if (sid == videoStreamObjID)
+ type = T_VIDEO;
+ else if (sid == audioStreamObjID)
+ type = T_AUDIO;
+ else
+ type = T_UNKNOWN;
+
+ in.skip(32);
+ id = in.readShort()&0x7f;
+ }
+
+
+ const char *getTypeName()
+ {
+ switch(type)
+ {
+ case T_VIDEO:
+ return "Video";
+ case T_AUDIO:
+ return "Audio";
+ }
+ return "Unknown";
+ }
+
+ void reset()
+ {
+ id = 0;
+ bitrate = 0;
+ type = T_UNKNOWN;
+ }
+
+ unsigned int id;
+ int bitrate;
+ TYPE type;
+};
+
+// -----------------------------------
+class ASFInfo
+{
+public:
+ enum
+ {
+ MAX_STREAMS = 128
+ };
+
+ ASFInfo()
+ {
+ numPackets = 0;
+ packetSize = 0;
+ flags = 0;
+ bitrate=0;
+ for(int i=0; i<MAX_STREAMS; i++)
+ streams[i].reset();
+ }
+
+ unsigned int packetSize,numPackets,flags,bitrate;
+
+ ASFStream streams[MAX_STREAMS];
+};
+
+// -----------------------------------
+class ASFChunk
+{
+public:
+
+ void read(Stream &in)
+ {
+ type = in.readShort();
+ len = in.readShort();
+ seq = in.readLong();
+ v1 = in.readShort();
+ v2 = in.readShort();
+
+ dataLen = len-8;
+ if (dataLen > sizeof(data))
+ throw StreamException("ASF chunk too big");
+ in.read(data,dataLen);
+ }
+
+ void write(Stream &out)
+ {
+ out.writeShort(type);
+ out.writeShort(len);
+ out.writeLong(seq);
+ out.writeShort(v1);
+ out.writeShort(v2);
+ out.write(data,dataLen);
+ }
+
+ unsigned int seq,dataLen;
+ unsigned short type,len,v1,v2;
+ unsigned char data[8192];
+};
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : atom.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ATOM_H
+#define _ATOM_H
+
+#include "stream.h"
+
+#include "id.h"
+
+// ------------------------------------------------
+class AtomStream
+{
+public:
+ AtomStream(Stream &s) : io(s),numChildren(0),numData(0)
+ {}
+
+ void checkData(int d)
+ {
+ if (numData != d)
+ throw StreamException("Bad atom data");
+ }
+
+ void writeParent(ID4 id,int nc)
+ {
+ io.writeID4(id);
+ io.writeInt(nc|0x80000000);
+ }
+
+ void writeInt(ID4 id,int d)
+ {
+ io.writeID4(id);
+ io.writeInt(4);
+ io.writeInt(d);
+ }
+
+ void writeID4(ID4 id,ID4 d)
+ {
+ io.writeID4(id);
+ io.writeInt(4);
+ io.writeID4(d);
+ }
+
+ void writeShort(ID4 id,short d)
+ {
+ io.writeID4(id);
+ io.writeInt(2);
+ io.writeShort(d);
+ }
+
+ void writeChar(ID4 id,char d)
+ {
+ io.writeID4(id);
+ io.writeInt(1);
+ io.writeChar(d);
+ }
+
+ void writeBytes(ID4 id,const void *p,int l)
+ {
+ io.writeID4(id);
+ io.writeInt(l);
+ io.write(p,l);
+ }
+
+
+ int writeStream(ID4 id,Stream &in,int l)
+ {
+ io.writeID4(id);
+ io.writeInt(l);
+ in.writeTo(io,l);
+ return (sizeof(int)*2)+l;
+
+ }
+
+ void writeString(ID4 id,const char *p)
+ {
+ writeBytes(id,p,strlen(p)+1);
+ }
+
+ ID4 read(int &numc,int &dlen)
+ {
+ ID4 id = io.readID4();
+
+ unsigned int v = io.readInt();
+ if (v & 0x80000000)
+ {
+ numc = v&0x7fffffff;
+ dlen = 0;
+ }else
+ {
+ numc = 0;
+ dlen = v;
+ }
+
+ numChildren = numc;
+ numData = dlen;
+
+ return id;
+ }
+
+ void skip(int c, int d)
+ {
+ if (d)
+ io.skip(d);
+
+ for(int i=0; i<c; i++)
+ {
+ int numc,data;
+ read(numc,data);
+ skip(numc,data);
+ }
+
+ }
+
+ int readInt()
+ {
+ checkData(4);
+ return io.readInt();
+ }
+ int readID4()
+ {
+ checkData(4);
+ return io.readID4();
+ }
+
+ int readShort()
+ {
+ checkData(2);
+ return io.readShort();
+ }
+ int readChar()
+ {
+ checkData(1);
+ return io.readChar();
+ }
+ int readBytes(void *p,int l)
+ {
+ checkData(l);
+ return io.read(p,l);
+ }
+
+ void readString(char *s,int max,int dlen)
+ {
+ checkData(dlen);
+ readBytes(s,max,dlen);
+ s[max-1] = 0;
+
+ }
+
+ void readBytes(void *s,int max,int dlen)
+ {
+ checkData(dlen);
+ if (max > dlen)
+ readBytes(s,dlen);
+ else
+ {
+ readBytes(s,max);
+ io.skip(dlen-max);
+ }
+ }
+
+ int writeAtoms(ID4 id, Stream &in, int cnt, int data)
+ {
+ int total=0;
+
+ if (cnt)
+ {
+ writeParent(id,cnt);
+ total+=sizeof(int)*2;
+
+ for(int i=0; i<cnt; i++)
+ {
+ AtomStream ain(in);
+ int c,d;
+ ID4 cid = ain.read(c,d);
+ total += writeAtoms(cid,in,c,d);
+ }
+ }else
+ {
+ total += writeStream(id,in,data);
+ }
+
+ return total;
+ }
+
+ bool eof() {return io.eof();}
+
+
+ int numChildren,numData;
+ Stream &io;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : channel.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Channel streaming classes. These do the actual
+// streaming of media between clients.
+//
+// (c) 2002 peercast.org
+//
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "socket.h"
+#include "channel.h"
+#include "gnutella.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "sys.h"
+#include "xml.h"
+#include "http.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+
+#include "mp3.h"
+#include "ogg.h"
+#include "mms.h"
+#include "nsv.h"
+
+#include "icy.h"
+#include "url.h"
+
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+char *Channel::srcTypes[]=
+{
+ "NONE",
+ "PEERCAST",
+ "SHOUTCAST",
+ "ICECAST",
+ "URL"
+};
+// -----------------------------------
+char *Channel::statusMsgs[]=
+{
+ "NONE",
+ "WAIT",
+ "CONNECT",
+ "REQUEST",
+ "CLOSE",
+ "RECEIVE",
+ "BROADCAST",
+ "ABORT",
+ "SEARCH",
+ "NOHOSTS",
+ "IDLE",
+ "ERROR",
+ "NOTFOUND"
+};
+
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info)
+{
+ int len;
+
+ if( info &&
+ info->contentType == ChanInfo::T_RAW &&
+ info->bitrate <= 32 &&
+ (len = strlen(info->name.cstr())) >= 9 &&
+ !memcmp(info->name.cstr(), "index", 5) &&
+ !memcmp(info->name.cstr()+len-4, ".txt", 4))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool isIndexTxt(Channel *ch)
+{
+ if(ch && !ch->isBroadcasting() && isIndexTxt(&ch->info))
+ return true;
+ else
+ return false;
+}
+
+int numMaxRelaysIndexTxt(Channel *ch)
+{
+ return ((servMgr->maxRelaysIndexTxt < 1) ? 1 : servMgr->maxRelaysIndexTxt);
+}
+
+int canStreamIndexTxt(Channel *ch)
+{
+ int ret;
+
+ // \8e©\95ª\82ª\94z\90M\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\8aÖ\8cW\82È\82¢
+ if(!ch || ch->isBroadcasting())
+ return -1;
+
+ ret = numMaxRelaysIndexTxt(ch) - ch->localRelays();
+ if(ret < 0)
+ ret = 0;
+
+ return ret;
+}
+// for PCRaw end.
+
+// -----------------------------------
+void readXMLString(String &str, XML::Node *n, const char *arg)
+{
+ char *p;
+ p = n->findAttr(arg);
+ if (p)
+ {
+ str.set(p,String::T_HTML);
+ str.convertTo(String::T_ASCII);
+ }
+}
+
+int channel_count=1;
+// -----------------------------------------------------------------------------
+// Initialise the channel to its default settings of unallocated and reset.
+// -----------------------------------------------------------------------------
+Channel::Channel()
+{
+ next = NULL;
+ reset();
+ channel_id = channel_count++;
+}
+// -----------------------------------------------------------------------------
+void Channel::endThread(bool flg)
+{
+ if (pushSock)
+ {
+ pushSock->close();
+ delete pushSock;
+ pushSock = NULL;
+ }
+
+ if (sock)
+ {
+ sock->close();
+ sock = NULL;
+ }
+
+ if (sourceData)
+ {
+ delete sourceData;
+ sourceData = NULL;
+ }
+
+ if (flg == true){
+ reset();
+
+ chanMgr->channellock.on();
+ chanMgr->deleteChannel(this);
+ chanMgr->channellock.off();
+
+ sys->endThread(&thread);
+ }
+}
+// -----------------------------------------------------------------------------
+void Channel::resetPlayTime()
+{
+ info.lastPlayStart = sys->getTime();
+}
+// -----------------------------------------------------------------------------
+void Channel::setStatus(STATUS s)
+{
+ if (s != status)
+ {
+ bool wasPlaying = isPlaying();
+
+ status = s;
+
+ if (isPlaying())
+ {
+ info.status = ChanInfo::S_PLAY;
+ resetPlayTime();
+ }else
+ {
+ if (wasPlaying)
+ info.lastPlayEnd = sys->getTime();
+ info.status = ChanInfo::S_UNKNOWN;
+ }
+
+ if (isBroadcasting())
+ {
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (!chl)
+ chanMgr->addHitList(info);
+ }
+
+ peercastApp->channelUpdate(&info);
+
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Reset channel and make it available
+// -----------------------------------------------------------------------------
+void Channel::reset()
+{
+ sourceHost.init();
+ remoteID.clear();
+
+ streamIndex = 0;
+
+ lastIdleTime = 0;
+
+ info.init();
+
+ mount.clear();
+ bump = false;
+ stayConnected = false;
+
+ icyMetaInterval = 0;
+ streamPos = 0;
+ skipCount = 0; //JP-EX
+ lastSkipTime = 0;
+
+ insertMeta.init();
+
+ headPack.init();
+
+ sourceStream = NULL;
+
+ rawData.init();
+ rawData.accept = ChanPacket::T_HEAD|ChanPacket::T_DATA;
+
+ setStatus(S_NONE);
+ type = T_NONE;
+
+ readDelay = false;
+ sock = NULL;
+ pushSock = NULL;
+
+ sourceURL.clear();
+ sourceData = NULL;
+
+ lastTrackerUpdate = 0;
+ lastMetaUpdate = 0;
+
+ srcType = SRC_NONE;
+
+
+ startTime = 0;
+ syncTime = 0;
+
+ channel_id = 0;
+ finthread = NULL;
+
+ trackerHit.init();
+}
+
+// -----------------------------------
+void Channel::newPacket(ChanPacket &pack)
+{
+ if (pack.type != ChanPacket::T_PCP)
+ {
+ rawData.writePacket(pack,true);
+ }
+}
+
+
+// -----------------------------------
+bool Channel::checkIdle()
+{
+ return ( (info.getUptime() > chanMgr->prefetchTime) && (localListeners() == 0) && (!stayConnected) && (status != S_BROADCASTING));
+}
+
+// -----------------------------------
+bool Channel::isFull()
+{
+ // for PCRaw (relay) start.
+ if(isIndexTxt(this))
+ {
+ int ret = canStreamIndexTxt(this);
+
+ if(ret > 0)
+ return false;
+ else if(ret == 0)
+ return true;
+ }
+ // for PCRaw (relay) end.
+
+ return chanMgr->maxRelaysPerChannel ? localRelays() >= chanMgr->maxRelaysPerChannel : false;
+}
+// -----------------------------------
+int Channel::localRelays()
+{
+ return servMgr->numStreams(info.id,Servent::T_RELAY,true);
+}
+// -----------------------------------
+int Channel::localListeners()
+{
+ return servMgr->numStreams(info.id,Servent::T_DIRECT,true);
+}
+
+// -----------------------------------
+int Channel::totalRelays()
+{
+ int tot = 0;
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (chl)
+ tot += chl->numHits();
+ return tot;
+}
+// -----------------------------------
+int Channel::totalListeners()
+{
+ int tot = localListeners();
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (chl)
+ tot += chl->numListeners();
+ return tot;
+}
+
+
+
+
+// -----------------------------------
+void Channel::startGet()
+{
+ srcType = SRC_PEERCAST;
+ type = T_RELAY;
+ info.srcProtocol = ChanInfo::SP_PCP;
+
+
+ sourceData = new PeercastSource();
+
+ startStream();
+}
+// -----------------------------------
+void Channel::startURL(const char *u)
+{
+ sourceURL.set(u);
+
+ srcType = SRC_URL;
+ type = T_BROADCAST;
+ stayConnected = true;
+
+ resetPlayTime();
+
+ sourceData = new URLSource(u);
+
+ startStream();
+
+}
+// -----------------------------------
+void Channel::startStream()
+{
+ thread.data = this;
+ thread.func = stream;
+ if (!sys->startThread(&thread))
+ reset();
+}
+
+// -----------------------------------
+void Channel::sleepUntil(double time)
+{
+ double sleepTime = time - (sys->getDTime()-startTime);
+
+// LOG("sleep %g",sleepTime);
+ if (sleepTime > 0)
+ {
+ if (sleepTime > 60) sleepTime = 60;
+
+ double sleepMS = sleepTime*1000;
+
+ sys->sleep((int)sleepMS);
+ }
+}
+
+
+// -----------------------------------
+void Channel::checkReadDelay(unsigned int len)
+{
+ if (readDelay)
+ {
+ unsigned int time = (len*1000)/((info.bitrate*1024)/8);
+ sys->sleep(time);
+ }
+
+
+}
+
+
+// -----------------------------------
+THREAD_PROC Channel::stream(ThreadInfo *thread)
+{
+// thread->lock();
+
+ Channel *ch = (Channel *)thread->data;
+
+ LOG_CHANNEL("Channel started");
+
+ while (thread->active && !peercastInst->isQuitting && !thread->finish)
+ {
+ ChanHitList *chl = chanMgr->findHitList(ch->info);
+ if (!chl)
+ chanMgr->addHitList(ch->info);
+
+ ch->sourceData->stream(ch);
+
+ LOG_CHANNEL("Channel stopped");
+ ch->rawData.init();
+
+ if (!ch->stayConnected)
+ {
+ thread->active = false;
+ break;
+ }else
+ {
+ if (!ch->info.lastPlayEnd)
+ ch->info.lastPlayEnd = sys->getTime();
+
+ unsigned int diff = (sys->getTime()-ch->info.lastPlayEnd) + 5;
+
+ LOG_DEBUG("Channel sleeping for %d seconds",diff);
+ for(unsigned int i=0; i<diff; i++)
+ {
+ if (!thread->active || peercastInst->isQuitting){
+ thread->active = false;
+ break;
+ }
+ sys->sleep(1000);
+ }
+ }
+ }
+
+ LOG_DEBUG("thread.active = %d, thread.finish = %d",
+ ch->thread.active, ch->thread.finish);
+
+ if (!thread->finish){
+ ch->endThread(false);
+
+ if (!ch->finthread){
+ ch->finthread = new ThreadInfo();
+ ch->finthread->func = waitFinish;
+ ch->finthread->data = ch;
+ sys->startThread(ch->finthread);
+ }
+ } else {
+ ch->endThread(true);
+ }
+ return 0;
+}
+
+// -----------------------------------
+THREAD_PROC Channel::waitFinish(ThreadInfo *thread)
+{
+ Channel *ch = (Channel*)thread->data;
+ LOG_DEBUG("Wait channel finish");
+
+ while(!(ch->thread.finish) && !thread->finish){
+ sys->sleep(1000);
+ }
+
+ if (ch->thread.finish){
+ LOG_DEBUG("channel finish");
+ ch->endThread(true);
+ } else {
+ LOG_DEBUG("channel restart");
+ }
+
+ delete thread;
+ return 0;
+}
+
+// -----------------------------------
+bool Channel::acceptGIV(ClientSocket *givSock)
+{
+ if (!pushSock)
+ {
+ pushSock = givSock;
+ return true;
+ }else
+ return false;
+}
+// -----------------------------------
+void Channel::connectFetch()
+{
+ sock = sys->createSocket();
+
+ if (!sock)
+ throw StreamException("Can`t create socket");
+
+ if (sourceHost.tracker || sourceHost.yp)
+ {
+ sock->setReadTimeout(30000);
+ sock->setWriteTimeout(30000);
+ LOG_CHANNEL("Channel using longer timeouts");
+ } else {
+ sock->setReadTimeout(5000);
+ sock->setWriteTimeout(5000);
+ }
+
+ sock->open(sourceHost.host);
+
+ sock->connect();
+}
+
+// -----------------------------------
+int Channel::handshakeFetch()
+{
+ char idStr[64];
+ info.id.toStr(idStr);
+
+ char sidStr[64];
+ servMgr->sessionID.toStr(sidStr);
+
+ sock->writeLineF("GET /channel/%s HTTP/1.0",idStr);
+ sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+ sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+ sock->writeLine("");
+
+ HTTP http(*sock);
+
+ int r = http.readResponse();
+
+ LOG_CHANNEL("Got response: %d",r);
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(PCX_HS_POS))
+ streamPos = atoi(arg);
+ else
+ Servent::readICYHeader(http, info, NULL);
+
+ LOG_CHANNEL("Channel fetch: %s",http.cmdLine);
+ }
+
+ if ((r != 200) && (r != 503))
+ return r;
+
+ if (!servMgr->keepDownstreams) {
+ if (rawData.getLatestPos() > streamPos)
+ rawData.init();
+ }
+
+ AtomStream atom(*sock);
+
+ String agent;
+
+ Host rhost = sock->host;
+
+ if (info.srcProtocol == ChanInfo::SP_PCP)
+ {
+ // don`t need PCP_CONNECT here
+ Servent::handshakeOutgoingPCP(atom,rhost,remoteID,agent,sourceHost.yp|sourceHost.tracker);
+ }
+
+ if (r == 503) return 503;
+ return 0;
+
+}
+
+// -----------------------------------
+void PeercastSource::stream(Channel *ch)
+{
+ int numYPTries=0;
+ int numYPTries2=0;
+ bool next_yp = false;
+ bool tracker_check = (ch->trackerHit.host.ip != 0);
+ int connFailCnt = 0;
+
+ ch->lastStopTime = 0;
+ ch->bumped = false;
+
+ while (ch->thread.active)
+ {
+ ch->skipCount = 0; //JP-EX
+ ch->lastSkipTime = 0;
+
+ ChanHitList *chl = NULL;
+
+ ch->sourceHost.init();
+
+ if (connFailCnt >= 3 && (ch->localListeners() == 0) && (!ch->stayConnected) && !ch->isBroadcasting()) {
+ ch->lastIdleTime = sys->getTime();
+ ch->setStatus(Channel::S_IDLE);
+ ch->skipCount = 0;
+ ch->lastSkipTime = 0;
+ break;
+ }
+
+ if (!servMgr->keepDownstreams && !ch->bumped) {
+ ch->trackerHit.lastContact = sys->getTime() - 30 + (rand() % 30);
+ }
+
+ ch->setStatus(Channel::S_SEARCHING);
+ LOG_CHANNEL("Channel searching for hit..");
+ do
+ {
+
+ if (ch->pushSock)
+ {
+ ch->sock = ch->pushSock;
+ ch->pushSock = NULL;
+ ch->sourceHost.host = ch->sock->host;
+ break;
+ }
+
+ chanMgr->hitlistlock.on();
+
+ chl = chanMgr->findHitList(ch->info);
+ if (chl)
+ {
+ ChanHitSearch chs;
+
+ // find local hit
+ if (!ch->sourceHost.host.ip){
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_RELAY_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use local hit");
+ }
+ }
+
+ // else find global hit
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = MIN_RELAY_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use global hit");
+ }
+ }
+
+
+ // else find local tracker
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ LOG_DEBUG("use local tracker");
+ }
+ }
+
+ // find tracker
+ unsigned int ctime = sys->getTime();
+ if (!ch->sourceHost.host.ip && tracker_check && ch->trackerHit.host.ip){
+ if (ch->trackerHit.lastContact + 30 < ctime){
+ ch->sourceHost = ch->trackerHit;
+ ch->trackerHit.lastContact = ctime;
+ LOG_DEBUG("use saved tracker");
+ }
+ }
+
+ // else find global tracker
+ if (!ch->sourceHost.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (chl->pickSourceHits(chs)){
+ ch->sourceHost = chs.best[0];
+ tracker_check = true;
+ ch->trackerHit = chs.best[0];
+ LOG_DEBUG("use global tracker");
+ }
+ }
+ }
+
+ chanMgr->hitlistlock.off();
+
+ if (servMgr->keepDownstreams && ch->lastStopTime && ch->lastStopTime < sys->getTime() - 7) {
+ ch->lastStopTime = 0;
+ LOG_DEBUG("------------ disconnect all downstreams");
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+
+ // no trackers found so contact YP
+ if (!tracker_check && !ch->sourceHost.host.ip)
+ {
+ next_yp = false;
+ if (servMgr->rootHost.isEmpty())
+ goto yp2;
+
+ if (numYPTries >= 3)
+ goto yp2;
+
+ if ((!servMgr->rootHost2.isEmpty()) && (numYPTries > numYPTries2))
+ goto yp2;
+
+ unsigned int ctime=sys->getTime();
+ if ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY)
+ {
+ ch->sourceHost.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+ ch->sourceHost.yp = true;
+ chanMgr->lastYPConnect=ctime;
+ numYPTries++;
+ }
+ if (numYPTries < 3)
+ next_yp = true;
+ }
+
+yp2:
+ // no trackers found so contact YP2
+ if (!tracker_check && !ch->sourceHost.host.ip)
+ {
+// next_yp = false;
+ if (servMgr->rootHost2.isEmpty())
+ goto yp0;
+
+ if (numYPTries2 >= 3)
+ goto yp0;
+
+ unsigned int ctime=sys->getTime();
+ if ((ctime-chanMgr->lastYPConnect2) > MIN_YP_RETRY)
+ {
+ ch->sourceHost.host.fromStrName(servMgr->rootHost2.cstr(),DEFAULT_PORT);
+ ch->sourceHost.yp = true;
+ chanMgr->lastYPConnect2=ctime;
+ numYPTries2++;
+ }
+ if (numYPTries2 < 3)
+ next_yp = true;
+ }
+yp0:
+ if (!tracker_check && !ch->sourceHost.host.ip && !next_yp) break;
+
+ sys->sleepIdle();
+
+ }while((ch->sourceHost.host.ip==0) && (ch->thread.active));
+
+ if (!ch->sourceHost.host.ip)
+ {
+ LOG_ERROR("Channel giving up");
+ ch->setStatus(Channel::S_ERROR);
+ break;
+ }
+
+ if (ch->sourceHost.yp)
+ {
+ LOG_CHANNEL("Channel contacting YP, try %d",numYPTries);
+ }else
+ {
+ LOG_CHANNEL("Channel found hit");
+ numYPTries=0;
+ numYPTries2=0;
+ }
+
+ if (ch->sourceHost.host.ip)
+ {
+ bool isTrusted = ch->sourceHost.tracker | ch->sourceHost.yp;
+
+
+ //if (ch->sourceHost.tracker)
+ // peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Contacting tracker, please wait...");
+
+ char ipstr[64];
+ ch->sourceHost.host.toStr(ipstr);
+
+ char *type = "";
+ if (ch->sourceHost.tracker)
+ type = "(tracker)";
+ else if (ch->sourceHost.yp)
+ type = "(YP)";
+
+ int error=-1;
+ int got503 = 0;
+ try
+ {
+ ch->setStatus(Channel::S_CONNECTING);
+ ch->sourceHost.lastContact = sys->getTime();
+
+ if (!ch->sock)
+ {
+ LOG_CHANNEL("Channel connecting to %s %s",ipstr,type);
+ ch->connectFetch();
+ }
+
+ error = ch->handshakeFetch();
+ if (error == 503) {
+ got503 = 1;
+ error = 0;
+ }
+ if (error)
+ throw StreamException("Handshake error");
+ if (ch->sourceHost.tracker) connFailCnt = 0;
+
+ if (servMgr->autoMaxRelaySetting) //JP-EX
+ {
+ double setMaxRelays = ch->info.bitrate?servMgr->maxBitrateOut/(ch->info.bitrate*1.3):0;
+ if ((unsigned int)setMaxRelays == 0)
+ servMgr->maxRelays = 1;
+ else if ((unsigned int)setMaxRelays > servMgr->autoMaxRelaySetting)
+ servMgr->maxRelays = servMgr->autoMaxRelaySetting;
+ else
+ servMgr->maxRelays = (unsigned int)setMaxRelays;
+ }
+
+ ch->sourceStream = ch->createSource();
+
+ error = ch->readStream(*ch->sock,ch->sourceStream);
+ if (error)
+ throw StreamException("Stream error");
+
+ error = 0; // no errors, closing normally.
+// ch->setStatus(Channel::S_CLOSING);
+ ch->setStatus(Channel::S_IDLE);
+
+ LOG_CHANNEL("Channel closed normally");
+ }catch(StreamException &e)
+ {
+ ch->setStatus(Channel::S_ERROR);
+ LOG_ERROR("Channel to %s %s : %s",ipstr,type,e.msg);
+ if (!servMgr->allowConnectPCST) //JP-EX
+ {
+ if (ch->info.srcProtocol == ChanInfo::SP_PEERCAST)
+ ch->thread.active = false;
+ }
+ //if (!ch->sourceHost.tracker || ((error != 503) && ch->sourceHost.tracker))
+ if (!ch->sourceHost.tracker || (!got503 && ch->sourceHost.tracker))
+ chanMgr->deadHit(ch->sourceHost);
+ if (ch->sourceHost.tracker && error == -1) {
+ LOG_ERROR("can't connect to tracker");
+ connFailCnt++;
+ }
+ }
+
+ unsigned int ctime = sys->getTime();
+ if (ch->rawData.lastWriteTime) {
+ ch->lastStopTime = ch->rawData.lastWriteTime;
+ if (isIndexTxt(ch) && ctime - ch->lastStopTime < 60)
+ ch->lastStopTime = ctime;
+ }
+
+ if (tracker_check && ch->sourceHost.tracker)
+ ch->trackerHit.lastContact = ctime - 30 + (rand() % 30);
+
+ // broadcast source host
+ if (!error && ch->sourceHost.host.ip) { // if closed normally
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ ch->sourceHost.writeAtoms(atom, ch->info.id);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+ LOG_DEBUG("stream: broadcast sourceHost");
+ }
+
+ // broadcast quit to any connected downstream servents
+ if (!servMgr->keepDownstreams || (ch->sourceHost.tracker && !got503) || !error) {
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_OFFAIR);
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,ch->info.id,ch->remoteID,noID,Servent::T_RELAY);
+ LOG_DEBUG("------------ broadcast quit to all downstreams");
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+
+
+ if (ch->sourceStream)
+ {
+ try
+ {
+ if (!error)
+ {
+ ch->sourceStream->updateStatus(ch);
+ ch->sourceStream->flush(*ch->sock);
+ }
+ }catch(StreamException &)
+ {}
+ ChannelStream *cs = ch->sourceStream;
+ ch->sourceStream = NULL;
+ cs->kill();
+ delete cs;
+ }
+
+ if (ch->sock)
+ {
+ ch->sock->close();
+ delete ch->sock;
+ ch->sock = NULL;
+ }
+
+ if (error == 404)
+ {
+ LOG_ERROR("Channel not found");
+ //if (!next_yp){
+ if ((ch->sourceHost.yp && !next_yp) || ch->sourceHost.tracker) {
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(ch->info);
+ if (hl){
+ hl->clearHits(true);
+ }
+ chanMgr->hitlistlock.off();
+
+ if(!isIndexTxt(&ch->info)) // for PCRaw (popup)
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+ return;
+ }
+ }
+
+
+ }
+
+ ch->lastIdleTime = sys->getTime();
+ ch->setStatus(Channel::S_IDLE);
+ ch->skipCount = 0; //JP-EX
+ ch->lastSkipTime = 0;
+ while ((ch->checkIdle()) && (ch->thread.active))
+ {
+ sys->sleepIdle();
+ }
+
+ sys->sleepIdle();
+ }
+
+}
+// -----------------------------------
+void Channel::startICY(ClientSocket *cs, SRC_TYPE st)
+{
+ srcType = st;
+ type = T_BROADCAST;
+ cs->setReadTimeout(0); // stay connected even when theres no data coming through
+ sock = cs;
+ info.srcProtocol = ChanInfo::SP_HTTP;
+
+ streamIndex = ++chanMgr->icyIndex;
+
+ sourceData = new ICYSource();
+ startStream();
+}
+
+// -----------------------------------
+static char *nextMetaPart(char *str,char delim)
+{
+ while (*str)
+ {
+ if (*str == delim)
+ {
+ *str++ = 0;
+ return str;
+ }
+ str++;
+ }
+ return NULL;
+}
+// -----------------------------------
+static void copyStr(char *to,char *from,int max)
+{
+ char c;
+ while ((c=*from++) && (--max))
+ if (c != '\'')
+ *to++ = c;
+
+ *to = 0;
+}
+
+// -----------------------------------
+void Channel::processMp3Metadata(char *str)
+{
+ ChanInfo newInfo = info;
+
+ char *cmd=str;
+ while (cmd)
+ {
+ char *arg = nextMetaPart(cmd,'=');
+ if (!arg)
+ break;
+
+ char *next = nextMetaPart(arg,';');
+
+ if (strcmp(cmd,"StreamTitle")==0)
+ {
+ newInfo.track.title.setUnquote(arg,String::T_ASCII);
+ newInfo.track.title.convertTo(String::T_UNICODE);
+
+ }else if (strcmp(cmd,"StreamUrl")==0)
+ {
+ newInfo.track.contact.setUnquote(arg,String::T_ASCII);
+ newInfo.track.contact.convertTo(String::T_UNICODE);
+ }
+
+
+ cmd = next;
+ }
+
+ updateInfo(newInfo);
+}
+
+// -----------------------------------
+XML::Node *ChanHit::createXML()
+{
+ // IP
+ char ipStr[64];
+ host.toStr(ipStr);
+
+ 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\"",
+ ipStr,
+ numHops,
+ numListeners,
+ numRelays,
+ upTime,
+ firewalled?1:0,
+ relay?1:0,
+ direct?1:0,
+ cin?1:0,
+ stable?1:0,
+ version,
+ sys->getTime()-time,
+ tracker
+ );
+
+}
+
+// -----------------------------------
+XML::Node *ChanHitList::createXML(bool addHits)
+{
+ XML::Node *hn = new XML::Node("hits hosts=\"%d\" listeners=\"%d\" relays=\"%d\" firewalled=\"%d\" closest=\"%d\" furthest=\"%d\" newest=\"%d\"",
+ numHits(),
+ numListeners(),
+ numRelays(),
+ numFirewalled(),
+ closestHit(),
+ furthestHit(),
+ sys->getTime()-newestHit()
+ );
+
+ if (addHits)
+ {
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ hn->add(h->createXML());
+ h = h->next;
+ }
+ }
+
+ return hn;
+}
+
+// -----------------------------------
+XML::Node *Channel::createRelayXML(bool showStat)
+{
+ const char *ststr;
+ ststr = getStatusStr();
+ if (!showStat)
+ if ((status == S_RECEIVING) || (status == S_BROADCASTING))
+ ststr = "OK";
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+
+ return new XML::Node("relay listeners=\"%d\" relays=\"%d\" hosts=\"%d\" status=\"%s\"",
+ localListeners(),
+ localRelays(),
+ (chl!=NULL)?chl->numHits():0,
+ ststr
+ );
+}
+
+// -----------------------------------
+void ChanMeta::fromXML(XML &xml)
+{
+ MemoryStream tout(data,MAX_DATALEN);
+ xml.write(tout);
+
+ len = tout.pos;
+}
+// -----------------------------------
+void ChanMeta::fromMem(void *p, int l)
+{
+ len = l;
+ memcpy(data,p,len);
+}
+// -----------------------------------
+void ChanMeta::addMem(void *p, int l)
+{
+ if ((len+l) <= MAX_DATALEN)
+ {
+ memcpy(data+len,p,l);
+ len += l;
+ }
+}
+// -----------------------------------
+void Channel::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+ unsigned int ctime = sys->getTime();
+
+ if (((ctime-lastTrackerUpdate) > 30) || (force))
+ {
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack));
+
+ AtomStream atom(mem);
+
+ ChanHit hit;
+
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ if (!chl)
+ throw StreamException("Broadcast channel has no hitlist");
+
+ int numListeners = totalListeners();
+ int numRelays = totalRelays();
+
+ unsigned int oldp = rawData.getOldestPos();
+ unsigned int newp = rawData.getLatestPos();
+
+ hit.initLocal(numListeners,numRelays,info.numSkips,info.getUptime(),isPlaying(), false, 0, this, oldp,newp);
+ hit.tracker = true;
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ROOT);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,11);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeParent(PCP_CHAN,4);
+ atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+ atom.writeBytes(PCP_CHAN_BCID,chanMgr->broadcastID.id,16);
+ info.writeInfoAtoms(atom);
+ info.writeTrackAtoms(atom);
+ hit.writeAtoms(atom,info.id);
+
+
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+ GnuID noID;
+ noID.clear();
+ int cnt = servMgr->broadcastPacket(pack,noID,servMgr->sessionID,svID,Servent::T_COUT);
+
+ if (cnt)
+ {
+ LOG_DEBUG("Sent tracker update for %s to %d client(s)",info.name.cstr(),cnt);
+ lastTrackerUpdate = ctime;
+ }
+ }
+}
+
+// -----------------------------------
+bool Channel::sendPacketUp(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did)
+{
+ if ( isActive()
+ && (!cid.isSet() || info.id.isSame(cid))
+ && (!sid.isSet() || !remoteID.isSame(sid))
+ && sourceStream
+ )
+ return sourceStream->sendPacket(pack,did);
+
+ return false;
+}
+
+// -----------------------------------
+void Channel::updateInfo(ChanInfo &newInfo)
+{
+ if (info.update(newInfo))
+ {
+ if (isBroadcasting())
+ {
+ unsigned int ctime = sys->getTime();
+ if ((ctime-lastMetaUpdate) > 30)
+ {
+ lastMetaUpdate = ctime;
+
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack));
+
+ AtomStream atom(mem);
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_RELAYS);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeBytes(PCP_BCST_CHANID,info.id.id,16);
+ atom.writeParent(PCP_CHAN,3);
+ atom.writeBytes(PCP_CHAN_ID,info.id.id,16);
+ info.writeInfoAtoms(atom);
+ info.writeTrackAtoms(atom);
+
+ pack.len = mem.pos;
+ pack.type = ChanPacket::T_PCP;
+ GnuID noID;
+ noID.clear();
+ servMgr->broadcastPacket(pack,info.id,servMgr->sessionID,noID,Servent::T_RELAY);
+
+ broadcastTrackerUpdate(noID);
+ }
+ }
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+ if (chl)
+ chl->info = info;
+
+ peercastApp->channelUpdate(&info);
+
+ }
+
+}
+// -----------------------------------
+ChannelStream *Channel::createSource()
+{
+// if (servMgr->relayBroadcast)
+// chanMgr->broadcastRelays(NULL,chanMgr->minBroadcastTTL,chanMgr->maxBroadcastTTL);
+
+
+ ChannelStream *source=NULL;
+
+ if (info.srcProtocol == ChanInfo::SP_PEERCAST)
+ {
+ LOG_CHANNEL("Channel is Peercast");
+ if (servMgr->allowConnectPCST) //JP-EX
+ source = new PeercastStream();
+ else
+ throw StreamException("Channel is not allowed");
+ }
+ else if (info.srcProtocol == ChanInfo::SP_PCP)
+ {
+ LOG_CHANNEL("Channel is PCP");
+ PCPStream *pcp = new PCPStream(remoteID);
+ source = pcp;
+ }
+ else if (info.srcProtocol == ChanInfo::SP_MMS)
+ {
+ LOG_CHANNEL("Channel is MMS");
+ source = new MMSStream();
+ }else
+ {
+ switch(info.contentType)
+ {
+ case ChanInfo::T_MP3:
+ LOG_CHANNEL("Channel is MP3 - meta: %d",icyMetaInterval);
+ source = new MP3Stream();
+ break;
+ case ChanInfo::T_NSV:
+ LOG_CHANNEL("Channel is NSV");
+ source = new NSVStream();
+ break;
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ throw StreamException("Channel is WMA/WMV - but not MMS");
+ break;
+ case ChanInfo::T_OGG:
+ case ChanInfo::T_OGM:
+ LOG_CHANNEL("Channel is OGG");
+ source = new OGGStream();
+ break;
+ default:
+ LOG_CHANNEL("Channel is Raw");
+ source = new RawStream();
+ break;
+ }
+ }
+
+ source->parent = this;
+
+ return source;
+}
+// ------------------------------------------
+void ChannelStream::updateStatus(Channel *ch)
+{
+ ChanPacket pack;
+ if (getStatus(ch,pack))
+ {
+ if (!ch->isBroadcasting())
+ {
+ GnuID noID;
+ noID.clear();
+ int cnt = chanMgr->broadcastPacketUp(pack,ch->info.id,servMgr->sessionID,noID);
+ LOG_CHANNEL("Sent channel status update to %d clients",cnt);
+ }
+ }
+}
+
+// ------------------------------------------
+bool ChannelStream::getStatus(Channel *ch,ChanPacket &pack)
+{
+ unsigned int ctime = sys->getTime();
+
+ ChanHitList *chl = chanMgr->findHitListByID(ch->info.id);
+
+ if (!chl)
+ return false;
+
+/* int newLocalListeners = ch->localListeners();
+ int newLocalRelays = ch->localRelays();
+
+ if (
+ (
+ (numListeners != newLocalListeners)
+ || (numRelays != newLocalRelays)
+ || (ch->isPlaying() != isPlaying)
+ || (servMgr->getFirewall() != fwState)
+ || (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+ )
+ && ((ctime-lastUpdate) > 10)
+ )
+ {
+
+ numListeners = newLocalListeners;
+ numRelays = newLocalRelays;
+ isPlaying = ch->isPlaying();
+ fwState = servMgr->getFirewall();
+ lastUpdate = ctime;
+
+ ChanHit hit;
+
+ hit.initLocal(ch->localListeners(),ch->localRelays(),ch->info.numSkips,ch->info.getUptime(),isPlaying, ch->isFull(), ch->info.bitrate, ch);
+ hit.tracker = ch->isBroadcasting();*/
+
+ int newLocalListeners = ch->localListeners();
+ int newLocalRelays = ch->localRelays();
+
+ if ((ch->isPlaying() == isPlaying)){
+ if ((ctime-lastUpdate) < 10){
+ return false;
+ }
+
+ if ((ctime-lastCheckTime) < 10){
+ return false;
+ }
+ lastCheckTime = ctime;
+ }
+
+ unsigned int oldp = ch->rawData.getOldestPos();
+ unsigned int newp = ch->rawData.getLatestPos();
+
+ ChanHit hit;
+
+// LOG_DEBUG("isPlaying-------------------------------------- %d %d", ch->isPlaying(), isPlaying);
+
+ hit.initLocal(newLocalListeners,newLocalRelays,ch->info.numSkips,ch->info.getUptime(),ch->isPlaying(), ch->isFull(), ch->info.bitrate, ch, oldp, newp);
+ hit.tracker = ch->isBroadcasting();
+
+ if ( (((ctime-lastUpdate)>chanMgr->hostUpdateInterval) && chanMgr->hostUpdateInterval)
+ || (newLocalListeners != numListeners)
+ || (newLocalRelays != numRelays)
+ || (ch->isPlaying() != isPlaying)
+ || (servMgr->getFirewall() != fwState)
+ || (ch->chDisp.relay != hit.relay)
+ || (ch->chDisp.relayfull != hit.relayfull)
+ || (ch->chDisp.chfull != hit.chfull)
+ || (ch->chDisp.ratefull != hit.ratefull)
+ ){
+ numListeners = newLocalListeners;
+ numRelays = newLocalRelays;
+ isPlaying = ch->isPlaying();
+ fwState = servMgr->getFirewall();
+ lastUpdate = ctime;
+
+ ch->chDisp = hit;
+
+ if ((numRelays) && ((servMgr->getFirewall() == ServMgr::FW_OFF) && (servMgr->autoRelayKeep!=0))) //JP-EX
+ ch->stayConnected = true;
+
+ if ((!numRelays && !numListeners) && (servMgr->autoRelayKeep==2)) //JP-EX
+ ch->stayConnected = false;
+
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream atom(pmem);
+
+ GnuID noID;
+ noID.clear();
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,11);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeBytes(PCP_BCST_CHANID,ch->info.id.id,16);
+ hit.writeAtoms(atom,noID);
+
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+ return true;
+ }else
+ return false;
+}
+// -----------------------------------
+bool Channel::checkBump()
+{
+ if (!isBroadcasting() && (!sourceHost.tracker))
+ if (rawData.lastWriteTime && ((sys->getTime() - rawData.lastWriteTime) > 30))
+ {
+ LOG_ERROR("Channel Auto bumped");
+ bump = true;
+ }
+
+ if (bump)
+ {
+ bump = false;
+ return true;
+ }else
+ return false;
+}
+
+// -----------------------------------
+int Channel::readStream(Stream &in,ChannelStream *source)
+{
+ //sys->sleep(300);
+
+ int error = 0;
+
+ info.numSkips = 0;
+
+ source->readHeader(in,this);
+
+ peercastApp->channelStart(&info);
+
+ rawData.lastWriteTime = 0;
+
+ bool wasBroadcasting=false;
+
+ unsigned int receiveStartTime = 0;
+
+ try
+ {
+ while (thread.active && !peercastInst->isQuitting)
+ {
+ if (checkIdle())
+ {
+ LOG_DEBUG("Channel idle");
+ break;
+ }
+
+ if (checkBump())
+ {
+ LOG_DEBUG("Channel bumped");
+ error = -1;
+ bumped = true;
+ break;
+ }
+
+ if (in.eof())
+ {
+ LOG_DEBUG("Channel eof");
+ break;
+ }
+
+ if (in.readReady())
+ {
+ error = source->readPacket(in,this);
+
+ if (error)
+ break;
+
+ //if (rawData.writePos > 0)
+ if (rawData.lastWriteTime > 0)
+ {
+ if (isBroadcasting())
+ {
+ if ((sys->getTime()-lastTrackerUpdate) >= chanMgr->hostUpdateInterval)
+ {
+ GnuID noID;
+ noID.clear();
+ broadcastTrackerUpdate(noID);
+ }
+ wasBroadcasting = true;
+
+ }else
+ {
+/* if (status != Channel::S_RECEIVING){
+ receiveStartTime = sys->getTime();
+ } else if (receiveStartTime && receiveStartTime + 10 > sys->getTime()){
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(info);
+ if (hl){
+ hl->clearHits(true);
+ }
+ chanMgr->hitlistlock.off();
+ receiveStartTime = 0;
+ }*/
+ setStatus(Channel::S_RECEIVING);
+ bumped = false;
+ }
+ source->updateStatus(this);
+ }
+ }
+
+ source->flush(in);
+
+ sys->sleepIdle();
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("readStream: %s",e.msg);
+ error = -1;
+ }
+
+ if (!servMgr->keepDownstreams) {
+ if (status == Channel::S_RECEIVING){
+ chanMgr->hitlistlock.on();
+ ChanHitList *hl = chanMgr->findHitList(info);
+ if (hl){
+ hl->clearHits(false);
+ }
+ chanMgr->hitlistlock.off();
+ }
+ }
+
+// setStatus(S_CLOSING);
+ setStatus(S_IDLE);
+
+ if (wasBroadcasting)
+ {
+ GnuID noID;
+ noID.clear();
+ broadcastTrackerUpdate(noID,true);
+ }
+
+ peercastApp->channelStop(&info);
+
+ source->readEnd(in,this);
+
+ return error;
+}
+
+// -----------------------------------
+void PeercastStream::readHeader(Stream &in,Channel *ch)
+{
+ if (in.readTag() != 'PCST')
+ throw StreamException("Not PeerCast stream");
+
+}
+// -----------------------------------
+void PeercastStream::readEnd(Stream &,Channel *)
+{
+
+}
+// -----------------------------------
+int PeercastStream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ {
+
+ pack.readPeercast(in);
+
+ MemoryStream mem(pack.data,pack.len);
+
+ switch(pack.type)
+ {
+ case ChanPacket::T_HEAD:
+ // update sync pos
+ ch->headPack = pack;
+ pack.pos = ch->streamPos;
+ ch->newPacket(pack);
+ ch->streamPos+=pack.len;
+ break;
+ case ChanPacket::T_DATA:
+ pack.pos = ch->streamPos;
+ ch->newPacket(pack);
+ ch->streamPos+=pack.len;
+ break;
+ case ChanPacket::T_META:
+ ch->insertMeta.fromMem(pack.data,pack.len);
+ {
+ if (pack.len)
+ {
+ XML xml;
+ xml.read(mem);
+ XML::Node *n = xml.findNode("channel");
+ if (n)
+ {
+ ChanInfo newInfo = ch->info;
+ newInfo.updateFromXML(n);
+ ChanHitList *chl = chanMgr->findHitList(ch->info);
+ if (chl)
+ newInfo.updateFromXML(n);
+ ch->updateInfo(newInfo);
+ }
+ }
+ }
+ break;
+#if 0
+ case ChanPacket::T_SYNC:
+ {
+ unsigned int s = mem.readLong();
+ if ((s-ch->syncPos) != 1)
+ {
+ LOG_CHANNEL("Ch.%d SKIP: %d to %d (%d)",ch->index,ch->syncPos,s,ch->info.numSkips);
+ if (ch->syncPos)
+ {
+ ch->info.numSkips++;
+ if (ch->info.numSkips>50)
+ throw StreamException("Bumped - Too many skips");
+ }
+ }
+
+ ch->syncPos = s;
+ }
+ break;
+#endif
+
+ }
+
+ }
+ return 0;
+}
+
+// -----------------------------------
+void ChannelStream::readRaw(Stream &in, Channel *ch)
+{
+ ChanPacket pack;
+
+ const int readLen = 8192;
+
+ pack.init(ChanPacket::T_DATA,pack.data,readLen,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos+=pack.len;
+
+}
+// ------------------------------------------
+void RawStream::readHeader(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int RawStream::readPacket(Stream &in,Channel *ch)
+{
+ readRaw(in,ch);
+ return 0;
+}
+
+// ------------------------------------------
+void RawStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+
+// -----------------------------------
+void ChanPacket::init(ChanPacketv &p)
+{
+ type = p.type;
+ len = p.len;
+ pos = p.pos;
+ sync = p.sync;
+ skip = p.skip;
+ memcpy(data, p.data, len);
+}
+// -----------------------------------
+void ChanPacket::init(TYPE t, const void *p, unsigned int l,unsigned int _pos)
+{
+ type = t;
+ if (l > MAX_DATALEN)
+ throw StreamException("Packet data too large");
+ len = l;
+ memcpy(data,p,len);
+ pos = _pos;
+ skip = false;
+}
+// -----------------------------------
+void ChanPacket::writeRaw(Stream &out)
+{
+ out.write(data,len);
+}
+// -----------------------------------
+void ChanPacket::writePeercast(Stream &out)
+{
+ unsigned int tp = 0;
+ switch (type)
+ {
+ case T_HEAD: tp = 'HEAD'; break;
+ case T_META: tp = 'META'; break;
+ case T_DATA: tp = 'DATA'; break;
+ }
+
+ if (type != T_UNKNOWN)
+ {
+ out.writeTag(tp);
+ out.writeShort(len);
+ out.writeShort(0);
+ out.write(data,len);
+ }
+}
+// -----------------------------------
+void ChanPacket::readPeercast(Stream &in)
+{
+ unsigned int tp = in.readTag();
+
+ switch (tp)
+ {
+ case 'HEAD': type = T_HEAD; break;
+ case 'DATA': type = T_DATA; break;
+ case 'META': type = T_META; break;
+ default: type = T_UNKNOWN;
+ }
+ len = in.readShort();
+ in.readShort();
+ if (len > MAX_DATALEN)
+ throw StreamException("Bad ChanPacket");
+ in.read(data,len);
+}
+// -----------------------------------
+int ChanPacketBuffer::copyFrom(ChanPacketBuffer &buf, unsigned int reqPos)
+{
+ lock.on();
+ buf.lock.on();
+
+ firstPos = 0;
+ lastPos = 0;
+ safePos = 0;
+ readPos = 0;
+
+ for(unsigned int i=buf.firstPos; i<=buf.lastPos; i++)
+ {
+ //ChanPacket *src = &buf.packets[i%MAX_PACKETS];
+ ChanPacketv *src = &buf.packets[i%MAX_PACKETS];
+ if (src->type & accept)
+ {
+ if (src->pos >= reqPos)
+ {
+ lastPos = writePos;
+ //packets[writePos++] = *src;
+ packets[writePos++].init(*src);
+ }
+ }
+
+ }
+
+
+ buf.lock.off();
+ lock.off();
+ return lastPos-firstPos;
+}
+
+// -----------------------------------
+bool ChanPacketBuffer::findPacket(unsigned int spos, ChanPacket &pack)
+{
+ if (writePos == 0)
+ return false;
+
+ lock.on();
+
+ unsigned int fpos = getStreamPos(firstPos);
+ if (spos < fpos)
+ spos = fpos;
+
+
+ for(unsigned int i=firstPos; i<=lastPos; i++)
+ {
+ //ChanPacket &p = packets[i%MAX_PACKETS];
+ ChanPacketv &p = packets[i%MAX_PACKETS];
+ if (p.pos >= spos)
+ {
+ pack.init(p);
+ lock.off();
+ return true;
+ }
+ }
+
+ lock.off();
+ return false;
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getLatestPos()
+{
+ if (!writePos)
+ return 0;
+ else
+ return getStreamPos(lastPos);
+
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getOldestPos()
+{
+ if (!writePos)
+ return 0;
+ else
+ return getStreamPos(firstPos);
+}
+
+// -----------------------------------
+unsigned int ChanPacketBuffer::findOldestPos(unsigned int spos)
+{
+ unsigned int min = getStreamPos(safePos);
+ unsigned int max = getStreamPos(lastPos);
+
+ if (min > spos)
+ return min;
+
+ if (max < spos)
+ return max;
+
+ return spos;
+}
+
+// -----------------------------------
+unsigned int ChanPacketBuffer::getStreamPos(unsigned int index)
+{
+ return packets[index%MAX_PACKETS].pos;
+}
+// -----------------------------------
+unsigned int ChanPacketBuffer::getStreamPosEnd(unsigned int index)
+{
+ return packets[index%MAX_PACKETS].pos+packets[index%MAX_PACKETS].len;
+}
+// -----------------------------------
+bool ChanPacketBuffer::writePacket(ChanPacket &pack, bool updateReadPos)
+{
+ if (pack.len)
+ {
+ if (servMgr->keepDownstreams) {
+ unsigned int lpos = getLatestPos();
+ unsigned int diff = pack.pos - lpos;
+ if (packets[lastPos%MAX_PACKETS].type == ChanPacket::T_HEAD) lpos = 0;
+ if (lpos && (diff == 0 || diff > 0xfff00000)) {
+ LOG_DEBUG("* latest pos=%d, pack pos=%d", getLatestPos(), pack.pos);
+ return false;
+ }
+ }
+
+ if (willSkip()) // too far behind
+ {
+ lastSkipTime = sys->getTime();
+ return false;
+ }
+
+ lock.on();
+
+ pack.sync = writePos;
+ packets[writePos%MAX_PACKETS].init(pack);
+
+// LOG_DEBUG("packet.len = %d",pack.len);
+
+
+ lastPos = writePos;
+ writePos++;
+
+ if (writePos >= MAX_PACKETS)
+ firstPos = writePos-MAX_PACKETS;
+ else
+ firstPos = 0;
+
+ if (writePos >= NUM_SAFEPACKETS)
+ safePos = writePos - NUM_SAFEPACKETS;
+ else
+ safePos = 0;
+
+ if (updateReadPos)
+ readPos = writePos;
+
+ lastWriteTime = sys->getTime();
+
+ lock.off();
+ return true;
+ }
+
+ return false;
+}
+// -----------------------------------
+void ChanPacketBuffer::readPacket(ChanPacket &pack)
+{
+
+ unsigned int tim = sys->getTime();
+
+ if (readPos < firstPos)
+ throw StreamException("Read too far behind");
+
+ while (readPos >= writePos)
+ {
+ sys->sleepIdle();
+ if ((sys->getTime() - tim) > 30)
+ throw TimeoutException();
+ }
+ lock.on();
+ pack.init(packets[readPos%MAX_PACKETS]);
+ readPos++;
+ lock.off();
+
+ sys->sleepIdle();
+
+}
+// -----------------------------------
+bool ChanPacketBuffer::willSkip()
+{
+ return ((writePos-readPos) >= MAX_PACKETS);
+}
+
+// -----------------------------------
+void Channel::getStreamPath(char *str)
+{
+ char idStr[64];
+
+ getIDStr(idStr);
+
+ sprintf(str,"/stream/%s%s",idStr,info.getTypeExt(info.contentType));
+}
+
+
+
+// -----------------------------------
+void ChanMgr::startSearch(ChanInfo &info)
+{
+ searchInfo = info;
+ clearHitLists();
+ numFinds = 0;
+ lastHit = 0;
+// lastSearch = 0;
+ searchActive = true;
+}
+// -----------------------------------
+void ChanMgr::quit()
+{
+ LOG_DEBUG("ChanMgr is quitting..");
+ closeAll();
+}
+// -----------------------------------
+int ChanMgr::numIdleChannels()
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->thread.active)
+ if (ch->status == Channel::S_IDLE)
+ cnt++;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+void ChanMgr::closeOldestIdle()
+{
+ unsigned int idleTime = (unsigned int)-1;
+ Channel *ch = channel,*oldest=NULL;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->thread.active)
+ if (ch->status == Channel::S_IDLE)
+ if (ch->lastIdleTime < idleTime)
+ {
+ oldest = ch;
+ idleTime = ch->lastIdleTime;
+ }
+ ch=ch->next;
+ }
+
+ if (oldest)
+ oldest->thread.active = false;
+}
+
+// -----------------------------------
+void ChanMgr::closeAll()
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->thread.active)
+ ch->thread.shutdown();
+ ch=ch->next;
+ }
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByNameID(ChanInfo &info)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.matchNameID(info))
+ return ch;
+ ch=ch->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Channel *ChanMgr::findChannelByName(const char *n)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (stricmp(ch->info.name,n)==0)
+ return ch;
+ ch=ch->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByIndex(int index)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ {
+ if (cnt == index)
+ return ch;
+ cnt++;
+ }
+ ch=ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByMount(const char *str)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (strcmp(ch->mount,str)==0)
+ return ch;
+ ch=ch->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByID(GnuID &id)
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.id.isSame(id))
+ return ch;
+ ch=ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findChannelByChannelID(int id)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive()){
+ if (ch->channel_id == id){
+ return ch;
+ }
+ }
+ ch = ch->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+int ChanMgr::findChannels(ChanInfo &info, Channel **chlist, int max)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->info.match(info))
+ {
+ chlist[cnt++] = ch;
+ if (cnt >= max)
+ break;
+ }
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanMgr::findChannelsByStatus(Channel **chlist, int max, Channel::STATUS status)
+{
+ int cnt=0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->status == status)
+ {
+ chlist[cnt++] = ch;
+ if (cnt >= max)
+ break;
+ }
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+Channel *ChanMgr::createRelay(ChanInfo &info, bool stayConnected)
+{
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ {
+ c->stayConnected = stayConnected;
+ c->startGet();
+ return c;
+ }
+ return NULL;
+}
+// -----------------------------------
+Channel *ChanMgr::findAndRelay(ChanInfo &info)
+{
+ char idStr[64];
+ info.id.toStr(idStr);
+ LOG_CHANNEL("Searching for: %s (%s)",idStr,info.name.cstr());
+
+ if(!isIndexTxt(&info)) // for PCRaw (popup)
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Finding channel...");
+
+
+ Channel *c = NULL;
+
+ WLockBlock wb(&(chanMgr->channellock));
+
+ wb.on();
+
+ c = findChannelByNameID(info);
+
+ if (!c)
+ {
+ c = chanMgr->createChannel(info,NULL);
+ if (c)
+ {
+ c->setStatus(Channel::S_SEARCHING);
+ c->startGet();
+ }
+ } else if (!(c->thread.active)){
+ c->thread.active = true;
+ c->thread.finish = false;
+ if (c->finthread){
+ c->finthread->finish = true;
+ c->finthread = NULL;
+ }
+ if (c->status != Channel::S_CONNECTING && c->status != Channel::S_SEARCHING){
+ c->setStatus(Channel::S_SEARCHING);
+ c->startGet();
+ }
+ }
+
+ wb.off();
+
+ for(int i=0; i<600; i++) // search for 1 minute.
+ {
+
+
+ wb.on();
+ c = findChannelByNameID(info);
+
+ if (!c)
+ {
+// peercastApp->notifyMessage(ServMgr::NT_PEERCAST,"Channel not found");
+ return NULL;
+ }
+
+
+ if (c->isPlaying() && (c->info.contentType!=ChanInfo::T_UNKNOWN))
+ break;
+
+ wb.off();
+
+ sys->sleep(100);
+ }
+
+ return c;
+}
+// -----------------------------------
+ChanMgr::ChanMgr()
+{
+ channel = NULL;
+
+ hitlist = NULL;
+
+ currFindAndPlayChannel.clear();
+
+ broadcastMsg.clear();
+ broadcastMsgInterval=10;
+
+ broadcastID.generate(PCP_BROADCAST_FLAGS);
+
+ deadHitAge = 600;
+
+ icyIndex = 0;
+ icyMetaInterval = 8192;
+ maxRelaysPerChannel = 1;
+
+ searchInfo.init();
+
+ minBroadcastTTL = 1;
+ maxBroadcastTTL = 7;
+
+ pushTimeout = 60; // 1 minute
+ pushTries = 5; // 5 times
+ maxPushHops = 8; // max 8 hops away
+ maxUptime = 0; // 0 = none
+
+ prefetchTime = 10; // n seconds
+
+ hostUpdateInterval = 120; // 2 minutes
+
+ bufferTime = 5;
+
+ autoQuery = 0;
+ lastQuery = 0;
+
+ lastYPConnect = 0;
+ lastYPConnect2 = 0;
+
+}
+
+// -----------------------------------
+bool ChanMgr::writeVariable(Stream &out, const String &var, int index)
+{
+ char buf[1024];
+ if (var == "numHitLists")
+ sprintf(buf,"%d",numHitLists());
+
+ else if (var == "numChannels")
+ sprintf(buf,"%d",numChannels());
+ else if (var == "djMessage")
+ strcpy(buf,broadcastMsg.cstr());
+ else if (var == "icyMetaInterval")
+ sprintf(buf,"%d",icyMetaInterval);
+ else if (var == "maxRelaysPerChannel")
+ sprintf(buf,"%d",maxRelaysPerChannel);
+ else if (var == "hostUpdateInterval")
+ sprintf(buf,"%d",hostUpdateInterval);
+ else if (var == "broadcastID")
+ broadcastID.toStr(buf);
+ else
+ return false;
+
+
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+bool Channel::writeVariable(Stream &out, const String &var, int index)
+{
+ char buf[1024];
+
+ buf[0]=0;
+
+ String utf8;
+
+ if (var == "name")
+ {
+ utf8 = info.name;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+
+ }else if (var == "bitrate")
+ {
+ sprintf(buf,"%d",info.bitrate);
+
+ }else if (var == "srcrate")
+ {
+ if (sourceData)
+ {
+ unsigned int tot = sourceData->getSourceRate();
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+ }else
+ strcpy(buf,"0");
+
+ }else if (var == "genre")
+ {
+ utf8 = info.genre;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "desc")
+ {
+ utf8 = info.desc;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "comment")
+ {
+ utf8 = info.comment;
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+ }else if (var == "uptime")
+ {
+ String uptime;
+ if (info.lastPlayStart)
+ uptime.setFromStopwatch(sys->getTime()-info.lastPlayStart);
+ else
+ uptime.set("-");
+ strcpy(buf,uptime.cstr());
+ }
+ else if (var == "type")
+ sprintf(buf,"%s",ChanInfo::getTypeStr(info.contentType));
+ else if (var == "ext")
+ sprintf(buf,"%s",ChanInfo::getTypeExt(info.contentType));
+ else if (var == "proto") {
+ switch(info.contentType) {
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ sprintf(buf, "mms://");
+ break;
+ default:
+ sprintf(buf, "http://");
+ }
+ }
+ else if (var == "localRelays")
+ sprintf(buf,"%d",localRelays());
+ else if (var == "localListeners")
+ sprintf(buf,"%d",localListeners());
+
+ else if (var == "totalRelays")
+ sprintf(buf,"%d",totalRelays());
+ else if (var == "totalListeners")
+ sprintf(buf,"%d",totalListeners());
+
+ else if (var == "status")
+ sprintf(buf,"%s",getStatusStr());
+ else if (var == "keep")
+ sprintf(buf,"%s",stayConnected?"Yes":"No");
+ else if (var == "id")
+ info.id.toStr(buf);
+ else if (var.startsWith("track."))
+ {
+
+ if (var == "track.title")
+ utf8 = info.track.title;
+ else if (var == "track.artist")
+ utf8 = info.track.artist;
+ else if (var == "track.album")
+ utf8 = info.track.album;
+ else if (var == "track.genre")
+ utf8 = info.track.genre;
+ else if (var == "track.contactURL")
+ utf8 = info.track.contact;
+
+ utf8.convertTo(String::T_UNICODESAFE);
+ strcpy(buf,utf8.cstr());
+
+ }else if (var == "contactURL")
+ sprintf(buf,"%s",info.url.cstr());
+ else if (var == "streamPos")
+ sprintf(buf,"%d",streamPos);
+ else if (var == "sourceType")
+ strcpy(buf,getSrcTypeStr());
+ else if (var == "sourceProtocol")
+ strcpy(buf,ChanInfo::getProtocolStr(info.srcProtocol));
+ else if (var == "sourceURL")
+ {
+ if (sourceURL.isEmpty())
+ sourceHost.host.toStr(buf);
+ else
+ strcpy(buf,sourceURL.cstr());
+ }
+ else if (var == "headPos")
+ sprintf(buf,"%d",headPack.pos);
+ else if (var == "headLen")
+ sprintf(buf,"%d",headPack.len);
+ else if (var == "numHits")
+ {
+ ChanHitList *chl = chanMgr->findHitListByID(info.id);
+ int numHits = 0;
+ if (chl){
+// numHits = chl->numHits();
+ ChanHit *hit;
+ hit = chl->hit;
+ while(hit){
+ numHits++;
+ hit = hit->next;
+ }
+ }
+ sprintf(buf,"%d",numHits);
+ } else if (var == "isBroadcast")
+ strcpy(buf, (type == T_BROADCAST) ? "1":"0");
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastTrackerUpdate(GnuID &svID, bool force)
+{
+ Channel *c = channel;
+ while(c)
+ {
+ if ( c->isActive() && c->isBroadcasting() )
+ c->broadcastTrackerUpdate(svID,force);
+ c=c->next;
+ }
+}
+
+
+// -----------------------------------
+int ChanMgr::broadcastPacketUp(ChanPacket &pack,GnuID &chanID, GnuID &srcID, GnuID &destID)
+{
+ int cnt=0;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->sendPacketUp(pack,chanID,srcID,destID))
+ cnt++;
+ c=c->next;
+ }
+
+ return cnt;
+}
+
+// -----------------------------------
+void ChanMgr::broadcastRelays(Servent *serv, int minTTL, int maxTTL)
+{
+ //if ((servMgr->getFirewall() == ServMgr::FW_OFF) || servMgr->serverHost.localIP())
+ {
+
+ Host sh = servMgr->serverHost;
+ bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+ bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+ bool stable = servMgr->totalStreams>0;
+
+
+ GnuPacket hit;
+
+ int numChans=0;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->isPlaying())
+ {
+
+ bool tracker = c->isBroadcasting();
+
+ int ttl = (c->info.getUptime() / servMgr->relayBroadcast); // 1 hop per N seconds
+
+ if (ttl < minTTL)
+ ttl = minTTL;
+
+ if (ttl > maxTTL)
+ ttl = maxTTL;
+
+ if (hit.initHit(sh,c,NULL,push,busy,stable,tracker,ttl))
+ {
+ int numOut=0;
+ numChans++;
+ if (serv)
+ {
+ serv->outputPacket(hit,false);
+ numOut++;
+ }
+
+ LOG_NETWORK("Sent channel to %d servents, TTL %d",numOut,ttl);
+
+ }
+ }
+ c=c->next;
+ }
+ //if (numChans)
+ // LOG_NETWORK("Sent %d channels to %d servents",numChans,numOut);
+ }
+}
+// -----------------------------------
+void ChanMgr::setUpdateInterval(unsigned int v)
+{
+ hostUpdateInterval = v;
+}
+
+
+// -----------------------------------
+// message check
+#if 0
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+ atom.writeParent(PCP_BCST,3);
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeParent(PCP_MESG,1);
+ atom.writeString(PCP_MESG_DATA,msg.cstr());
+
+ mem.len = mem.pos;
+ mem.rewind();
+ pack.len = mem.len;
+
+ GnuID noID;
+ noID.clear();
+
+ BroadcastState bcs;
+ PCPStream::readAtom(atom,bcs);
+ //int cnt = servMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+ //int cnt = servMgr->broadcastPacketDown(pack,noID,servMgr->sessionID);
+ //int cnt = chanMgr->broadcastPacketUp(pack,noID,servMgr->sessionID);
+ //LOG_DEBUG("Sent message to %d clients",cnt);
+#endif
+// -----------------------------------
+void ChanMgr::setBroadcastMsg(String &msg)
+{
+ if (!msg.isSame(broadcastMsg))
+ {
+ broadcastMsg = msg;
+
+ Channel *c = channel;
+ while(c)
+ {
+ if (c->isActive() && c->isBroadcasting())
+ {
+ ChanInfo newInfo = c->info;
+ newInfo.comment = broadcastMsg;
+ c->updateInfo(newInfo);
+ }
+ c=c->next;
+ }
+
+ }
+}
+
+
+// -----------------------------------
+void ChanMgr::clearHitLists()
+{
+
+// LOG_DEBUG("clearHitLists HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ while (hitlist)
+ {
+ peercastApp->delChannel(&hitlist->info);
+
+ ChanHitList *next = hitlist->next;
+
+ delete hitlist;
+
+ hitlist = next;
+ }
+// LOG_DEBUG("clearHitLists HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+Channel *ChanMgr::deleteChannel(Channel *delchan)
+{
+ lock.on();
+
+ Channel *ch = channel,*prev=NULL,*next=NULL;
+
+ while (ch)
+ {
+ if (ch == delchan)
+ {
+ Channel *next = ch->next;
+ if (prev)
+ prev->next = next;
+ else
+ channel = next;
+
+ if (delchan->sourceStream){
+ delchan->sourceStream->parent = NULL;
+ }
+
+ delete delchan;
+
+ break;
+ }
+ prev = ch;
+ ch=ch->next;
+ }
+
+
+ lock.off();
+ return next;
+}
+
+// -----------------------------------
+Channel *ChanMgr::createChannel(ChanInfo &info, const char *mount)
+{
+ lock.on();
+
+ Channel *nc=NULL;
+
+ nc = new Channel();
+
+ nc->next = channel;
+ channel = nc;
+
+
+ nc->info = info;
+ nc->info.lastPlayStart = 0;
+ nc->info.lastPlayEnd = 0;
+ nc->info.status = ChanInfo::S_UNKNOWN;
+ if (mount)
+ nc->mount.set(mount);
+ nc->setStatus(Channel::S_WAIT);
+ nc->type = Channel::T_ALLOCATED;
+ nc->info.createdTime = sys->getTime();
+
+ LOG_CHANNEL("New channel created");
+
+ lock.off();
+ return nc;
+}
+// -----------------------------------
+int ChanMgr::pickHits(ChanHitSearch &chs)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->pickHits(chs))
+ {
+ chl->info.id;
+ return 1;
+ }
+ chl = chl->next;
+ }
+ return 0;
+}
+
+// -----------------------------------
+ChanHitList *ChanMgr::findHitList(ChanInfo &info)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.matchNameID(info))
+ return chl;
+
+ chl = chl->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::findHitListByID(GnuID &id)
+{
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.id.isSame(id))
+ return chl;
+ chl = chl->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+int ChanMgr::numHitLists()
+{
+ int num=0;
+ ChanHitList *chl = hitlist;
+ while(chl)
+ {
+ if (chl->isUsed())
+ num++;
+ chl = chl->next;
+ }
+ return num;
+}
+// -----------------------------------
+ChanHitList *ChanMgr::addHitList(ChanInfo &info)
+{
+ ChanHitList *chl = new ChanHitList();
+
+
+ chl->next = hitlist;
+ hitlist = chl;
+
+ chl->used = true;
+ chl->info = info;
+ chl->info.createdTime = sys->getTime();
+ peercastApp->addChannel(&chl->info);
+
+
+ return chl;
+}
+// -----------------------------------
+void ChanMgr::clearDeadHits(bool clearTrackers)
+{
+ unsigned int interval;
+
+ if (servMgr->isRoot)
+ interval = 1200; // mainly for old 0.119 clients
+ else
+ interval = hostUpdateInterval+120;
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = hitlist,*prev = NULL;
+ while (chl)
+ {
+ if (chl->isUsed())
+ {
+ if (chl->clearDeadHits(interval,clearTrackers) == 0)
+ {
+ if (!isBroadcasting(chl->info.id))
+ {
+ if (!chanMgr->findChannelByID(chl->info.id))
+ {
+ peercastApp->delChannel(&chl->info);
+
+ ChanHitList *next = chl->next;
+ if (prev)
+ prev->next = next;
+ else
+ hitlist = next;
+
+ delete chl;
+ chl = next;
+ continue;
+ }
+ }
+ }
+ }
+ prev = chl;
+ chl = chl->next;
+ }
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+bool ChanMgr::isBroadcasting(GnuID &id)
+{
+ Channel *ch = findChannelByID(id);
+ if (ch)
+ return ch->isBroadcasting();
+
+ return false;
+}
+// -----------------------------------
+bool ChanMgr::isBroadcasting()
+{
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ if (ch->isBroadcasting())
+ return true;
+
+ ch = ch->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+int ChanMgr::numChannels()
+{
+ int tot = 0;
+ Channel *ch = channel;
+ while (ch)
+ {
+ if (ch->isActive())
+ tot++;
+ ch = ch->next;
+ }
+ return tot;
+}
+
+// -----------------------------------
+void ChanMgr::deadHit(ChanHit &hit)
+{
+ ChanHitList *chl = findHitListByID(hit.chanID);
+ if (chl)
+ chl->deadHit(hit);
+}
+// -----------------------------------
+void ChanMgr::delHit(ChanHit &hit)
+{
+ ChanHitList *chl = findHitListByID(hit.chanID);
+ if (chl)
+ chl->delHit(hit);
+}
+
+// -----------------------------------
+void ChanMgr::addHit(Host &h,GnuID &id,bool tracker)
+{
+ ChanHit hit;
+ hit.init();
+ hit.host = h;
+ hit.rhost[0] = h;
+ hit.rhost[1].init();
+ hit.tracker = tracker;
+ hit.recv = true;
+ hit.chanID = id;
+ addHit(hit);
+}
+// -----------------------------------
+ChanHit *ChanMgr::addHit(ChanHit &h)
+{
+ if (searchActive)
+ lastHit = sys->getTime();
+
+ ChanHitList *hl=NULL;
+
+ hl = findHitListByID(h.chanID);
+
+ if (!hl)
+ {
+ ChanInfo info;
+ info.id = h.chanID;
+ hl = addHitList(info);
+ }
+
+ if (hl)
+ {
+ return hl->addHit(h);
+ }else
+ return NULL;
+}
+
+// -----------------------------------
+class ChanFindInfo : public ThreadInfo
+{
+public:
+ ChanInfo info;
+ bool keep;
+};
+// -----------------------------------
+THREAD_PROC findAndPlayChannelProc(ThreadInfo *th)
+{
+ ChanFindInfo *cfi = (ChanFindInfo *)th;
+
+ ChanInfo info;
+ info = cfi->info;
+
+
+ Channel *ch = chanMgr->findChannelByNameID(info);
+
+ chanMgr->currFindAndPlayChannel = info.id;
+
+ if (!ch)
+ ch = chanMgr->findAndRelay(info);
+
+ if (ch)
+ {
+ // check that a different channel hasn`t be selected already.
+ if (chanMgr->currFindAndPlayChannel.isSame(ch->info.id))
+ chanMgr->playChannel(ch->info);
+
+ if (cfi->keep)
+ ch->stayConnected = cfi->keep;
+ }
+
+ delete cfi;
+ return 0;
+}
+// -----------------------------------
+void ChanMgr::findAndPlayChannel(ChanInfo &info, bool keep)
+{
+ ChanFindInfo *cfi = new ChanFindInfo;
+ cfi->info = info;
+ cfi->keep = keep;
+ cfi->func = findAndPlayChannelProc;
+
+
+ sys->startThread(cfi);
+}
+// -----------------------------------
+void ChanMgr::playChannel(ChanInfo &info)
+{
+
+ char str[128],fname[256],idStr[128];
+
+ sprintf(str,"http://localhost:%d",servMgr->serverHost.port);
+ info.id.toStr(idStr);
+
+ PlayList::TYPE type;
+
+
+ if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+ {
+ type = PlayList::T_ASX;
+ // WMP seems to have a bug where it doesn`t re-read asx files if they have the same name
+ // so we prepend the channel id to make it unique - NOTE: should be deleted afterwards.
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/%s.asx",servMgr->modulePath,idStr);
+ }else
+ sprintf(fname,"%s/%s.asx",peercastApp->getPath(),idStr);
+ }else if (info.contentType == ChanInfo::T_OGM)
+ {
+ type = PlayList::T_RAM;
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/play.ram",servMgr->modulePath);
+ }else
+ sprintf(fname,"%s/play.ram",peercastApp->getPath());
+
+ }else
+ {
+ type = PlayList::T_SCPLS;
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ sprintf(fname,"%s/play.pls",servMgr->modulePath);
+ }else
+ sprintf(fname,"%s/play.pls",peercastApp->getPath());
+ }
+
+
+ PlayList *pls = new PlayList(type,1);
+ pls->addChannel(str,info);
+
+
+ LOG_DEBUG("Writing %s",fname);
+ FileStream file;
+ file.openWriteReplace(fname);
+ pls->write(file);
+ file.close();
+
+
+ LOG_DEBUG("Executing: %s",fname);
+ sys->executeFile(fname);
+ delete pls;
+
+}
+
+// -----------------------------------
+ChanHitList::ChanHitList()
+{
+ info.init();
+ lastHitTime = 0;
+ used = false;
+ hit = NULL;
+}
+// -----------------------------------
+ChanHitList::~ChanHitList()
+{
+ chanMgr->hitlistlock.on();
+ while (hit)
+ hit = deleteHit(hit);
+ chanMgr->hitlistlock.off();
+}
+// -----------------------------------
+void ChanHit::pickNearestIP(Host &h)
+{
+ for(int i=0; i<2; i++)
+ {
+ if (h.classType() == rhost[i].classType())
+ {
+ host = rhost[i];
+ break;
+ }
+ }
+}
+
+// -----------------------------------
+void ChanHit::init()
+{
+ host.init();
+
+ rhost[0].init();
+ rhost[1].init();
+
+ next = NULL;
+
+ numListeners = 0;
+ numRelays = 0;
+
+ dead = tracker = firewalled = stable = yp = false;
+ recv = cin = direct = relay = true;
+ relayfull = chfull = ratefull = false;
+ direct = 0;
+ numHops = 0;
+ time = upTime = 0;
+ lastContact = 0;
+
+ version = 0;
+ version_vp = 0;
+
+ version_ex_prefix[0] = ' ';
+ version_ex_prefix[1] = ' ';
+ version_ex_number = 0;
+
+ status = 0;
+
+ sessionID.clear();
+ chanID.clear();
+
+
+ oldestPos = newestPos = 0;
+ uphost.init();
+ uphostHops = 0;
+}
+
+// -----------------------------------
+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)
+{
+ init();
+ firewalled = (servMgr->getFirewall() != ServMgr::FW_OFF);
+ numListeners = numl;
+ numRelays = numr;
+ upTime = uptm;
+ stable = servMgr->totalStreams>0;
+ sessionID = servMgr->sessionID;
+ recv = connected;
+
+ direct = !servMgr->directFull();
+// relay = !servMgr->relaysFull();
+ cin = !servMgr->controlInFull();
+
+ relayfull = servMgr->relaysFull();
+ chfull = isFull;
+
+ Channel *c = chanMgr->channel;
+ int noRelay = 0;
+ unsigned int needRate = 0;
+ unsigned int allRate = 0;
+ while(c){
+ if (c->isPlaying()){
+ allRate += c->info.bitrate * c->localRelays();
+ if ((c != ch) && (c->localRelays() == 0)){
+ if(!isIndexTxt(c)) // for PCRaw (relay)
+ noRelay++;
+ needRate+=c->info.bitrate;
+ }
+ }
+ c = c->next;
+ }
+ int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+ if (ch->localRelays()){
+ if (noRelay > diff){
+ noRelay = diff;
+ }
+ } else {
+ noRelay = 0;
+ needRate = 0;
+ }
+
+ // for PCRaw (relay) start.
+ bool force_off = false;
+
+ if(isIndexTxt(ch))
+ force_off = true;
+ // for PCRaw (relay) end.
+
+// ratefull = servMgr->bitrateFull(needRate+bitrate);
+ ratefull = (servMgr->maxBitrateOut < allRate + needRate + ch->info.bitrate);
+
+ //relay = (!relayfull) && (!chfull) && (!ratefull) && ((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays);
+ relay = (!relayfull || force_off) && (!chfull) && (!ratefull)
+ && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) < servMgr->maxRelays) || force_off); // for PCRaw (relay) (force_off)
+
+/* if (relayfull){
+ LOG_DEBUG("Reject by relay full");
+ }
+ if (chfull){
+ LOG_DEBUG("Reject by channel full");
+ }
+ if (ratefull){
+ LOG_DEBUG("Reject by rate: Max=%d Now=%d Need=%d ch=%d", servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+ }*/
+
+ host = servMgr->serverHost;
+
+ version = PCP_CLIENT_VERSION;
+ version_vp = PCP_CLIENT_VERSION_VP;
+#ifdef VERSION_EX
+ strncpy(version_ex_prefix, PCP_CLIENT_VERSION_EX_PREFIX,2);
+ version_ex_number = PCP_CLIENT_VERSION_EX_NUMBER;
+#else
+ version_ex_prefix[0] = ' ';
+ version_ex_prefix[1] = ' ';
+ version_ex_number = 0;
+#endif
+
+ status = ch->status;
+
+ rhost[0] = Host(host.ip,host.port);
+ rhost[1] = Host(ClientSocket::getIP(NULL),host.port);
+
+ if (firewalled)
+ rhost[0].port = 0;
+
+ oldestPos = oldp;
+ newestPos = newp;
+
+ uphost.ip = ch->sourceHost.host.ip;
+ uphost.port = ch->sourceHost.host.port;
+ uphostHops = 1;
+}
+
+// -----------------------------------
+void ChanHit::writeAtoms(AtomStream &atom,GnuID &chanID)
+{
+ bool addChan=chanID.isSet();
+ bool uphostdata=(uphost.ip != 0);
+
+ int fl1 = 0;
+ if (recv) fl1 |= PCP_HOST_FLAGS1_RECV;
+ if (relay) fl1 |= PCP_HOST_FLAGS1_RELAY;
+ if (direct) fl1 |= PCP_HOST_FLAGS1_DIRECT;
+ if (cin) fl1 |= PCP_HOST_FLAGS1_CIN;
+ if (tracker) fl1 |= PCP_HOST_FLAGS1_TRACKER;
+ if (firewalled) fl1 |= PCP_HOST_FLAGS1_PUSH;
+
+ atom.writeParent(PCP_HOST,13 + (addChan?1:0) + (uphostdata?3:0) + (version_ex_number?2:0));
+
+ if (addChan)
+ atom.writeBytes(PCP_HOST_CHANID,chanID.id,16);
+ atom.writeBytes(PCP_HOST_ID,sessionID.id,16);
+ atom.writeInt(PCP_HOST_IP,rhost[0].ip);
+ atom.writeShort(PCP_HOST_PORT,rhost[0].port);
+ atom.writeInt(PCP_HOST_IP,rhost[1].ip);
+ atom.writeShort(PCP_HOST_PORT,rhost[1].port);
+ atom.writeInt(PCP_HOST_NUML,numListeners);
+ atom.writeInt(PCP_HOST_NUMR,numRelays);
+ atom.writeInt(PCP_HOST_UPTIME,upTime);
+ atom.writeInt(PCP_HOST_VERSION,version);
+ atom.writeInt(PCP_HOST_VERSION_VP,version_vp);
+ if (version_ex_number){
+ atom.writeBytes(PCP_HOST_VERSION_EX_PREFIX,version_ex_prefix,2);
+ atom.writeShort(PCP_HOST_VERSION_EX_NUMBER,version_ex_number);
+ }
+ atom.writeChar(PCP_HOST_FLAGS1,fl1);
+ atom.writeInt(PCP_HOST_OLDPOS,oldestPos);
+ atom.writeInt(PCP_HOST_NEWPOS,newestPos);
+ if (uphostdata){
+ atom.writeInt(PCP_HOST_UPHOST_IP,uphost.ip);
+ atom.writeInt(PCP_HOST_UPHOST_PORT,uphost.port);
+ atom.writeInt(PCP_HOST_UPHOST_HOPS,uphostHops);
+ }
+}
+// -----------------------------------
+bool ChanHit::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "rhost0")
+ {
+ if (servMgr->enableGetName) //JP-EX s
+ {
+ char buf2[256];
+ if (firewalled)
+ {
+ if (numRelays==0)
+ strcpy(buf,"<font color=red>");
+ else
+ strcpy(buf,"<font color=orange>");
+ }
+ else {
+ if (!relay){
+ if (numRelays==0){
+ strcpy(buf,"<font color=purple>");
+ } else {
+ strcpy(buf,"<font color=blue>");
+ }
+ } else {
+ strcpy(buf,"<font color=green>");
+ }
+ }
+
+ rhost[0].toStr(buf2);
+ strcat(buf,buf2);
+
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,rhost[0].ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ strcat(buf,"</font>");
+ } //JP-EX e
+ else
+ rhost[0].toStr(buf);
+ }
+ else if (var == "rhost1")
+ rhost[1].toStr(buf);
+ else if (var == "numHops")
+ sprintf(buf,"%d",numHops);
+ else if (var == "numListeners")
+ sprintf(buf,"%d",numListeners);
+ else if (var == "numRelays")
+ sprintf(buf,"%d",numRelays);
+ else if (var == "uptime")
+ {
+ String timeStr;
+ timeStr.setFromStopwatch(upTime);
+ strcpy(buf,timeStr.cstr());
+ }else if (var == "update")
+ {
+ String timeStr;
+ if (timeStr)
+ timeStr.setFromStopwatch(sys->getTime()-time);
+ else
+ timeStr.set("-");
+ strcpy(buf,timeStr.cstr());
+ }else if (var == "isFirewalled"){
+ sprintf(buf,"%d",firewalled?1:0);
+ }else if (var == "version"){
+ sprintf(buf,"%d",version);
+ }else if (var == "agent"){
+ if (version){
+ if (version_ex_number){
+ sprintf(buf, "v0.%d(%c%c%04d)", version, version_ex_prefix[0], version_ex_prefix[1], version_ex_number);
+ } else if (version_vp){
+ sprintf(buf,"v0.%d(VP%04d)", version, version_vp);
+ } else {
+ sprintf(buf,"v0.%d", version);
+ }
+ } else {
+ strcpy(buf, "0");
+ }
+ }
+ else if (var == "check")
+ {
+ char buf2[256];
+ strcpy(buf, "<a href=\"#\" onclick=\"checkip('");
+ rhost[0].IPtoStr(buf2);
+ strcat(buf, buf2);
+ strcat(buf, "')\">_</a>");
+ }
+ else if (var == "uphost") // tree
+ uphost.toStr(buf);
+ else if (var == "uphostHops") // tree
+ sprintf(buf,"%d",uphostHops);
+ else if (var == "canRelay") // tree
+ sprintf(buf, "%d",relay);
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+
+// -----------------------------------
+int ChanHitList::getTotalListeners()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ cnt+=h->numListeners;
+ h=h->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalRelays()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ cnt+=h->numRelays;
+ h=h->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::getTotalFirewalled()
+{
+ int cnt=0;
+ ChanHit *h = hit;
+ while (h)
+ {
+ if (h->host.ip)
+ if (h->firewalled)
+ cnt++;
+ h=h->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::contactTrackers(bool connected, int numl, int nums, int uptm)
+{
+ return 0;
+}
+
+void ChanHitList::clearHits(bool flg)
+{
+ ChanHit *c = hit, *prev = NULL;
+
+ while(c){
+ if (flg || (c->numHops != 0)){
+ ChanHit *next = c->next;
+ if (prev)
+ prev->next = next;
+ else
+ hit = next;
+
+ delete c;
+ c = next;
+ } else {
+ prev = c;
+ c = c->next;
+ }
+ }
+}
+
+// -----------------------------------
+ChanHit *ChanHitList::deleteHit(ChanHit *ch)
+{
+ ChanHit *c = hit,*prev=NULL;
+ while (c)
+ {
+ if (c == ch)
+ {
+ ChanHit *next = c->next;
+ if (prev)
+ prev->next = next;
+ else
+ hit = next;
+
+ delete c;
+
+ return next;
+ }
+ prev=c;
+ c=c->next;
+ }
+
+ return NULL;
+}
+// -----------------------------------
+ChanHit *ChanHitList::addHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ char uphostStr[64];
+ h.uphost.toStr(uphostStr);
+ if (h.uphost.ip){
+ LOG_DEBUG("Add hit: F%dT%dR%d %s/%s <- %s(%d)",h.firewalled,h.tracker,h.relay,ip0str,ip1str,uphostStr, h.uphostHops);
+ } else {
+ LOG_DEBUG("Add hit: F%dT%dR%d %s/%s",h.firewalled,h.tracker,h.relay,ip0str,ip1str);
+ }
+
+ // dont add our own hits
+ if (servMgr->sessionID.isSame(h.sessionID))
+ return NULL;
+
+
+ lastHitTime = sys->getTime();
+ h.time = lastHitTime;
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if ((ch->rhost[0].ip == h.rhost[0].ip) && (ch->rhost[0].port == h.rhost[0].port))
+ if (((ch->rhost[1].ip == h.rhost[1].ip) && (ch->rhost[1].port == h.rhost[1].port)) || (!ch->rhost[1].isValid()))
+ {
+ if (!ch->dead)
+ {
+ if (ch->numHops > 0 && h.numHops == 0)
+ // downstream hit recieved as RelayHost
+ return ch;
+ ChanHit *next = ch->next;
+ *ch = h;
+ ch->next = next;
+ return ch;
+ }
+ }
+ ch=ch->next;
+ }
+
+ // clear hits with same session ID (IP may have changed)
+ if (h.sessionID.isSet())
+ {
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->sessionID.isSame(h.sessionID))
+ {
+ ch = deleteHit(ch);
+ continue;
+ }
+ ch=ch->next;
+ }
+ }
+
+
+ // else add new hit
+ {
+ ChanHit *ch = new ChanHit();
+ *ch = h;
+ ch->chanID = info.id;
+ ch->next = hit;
+ hit = ch;
+ return ch;
+ }
+
+ return NULL;
+}
+
+
+// -----------------------------------
+int ChanHitList::clearDeadHits(unsigned int timeout, bool clearTrackers)
+{
+ int cnt=0;
+ unsigned int ctime = sys->getTime();
+
+// LOG_DEBUG("clearDeadHits HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ {
+ if (ch->dead || ((ctime-ch->time) > timeout) && (clearTrackers || (!clearTrackers & !ch->tracker)))
+ {
+// ch = deleteHit(ch);
+
+ if (ch->firewalled){
+// LOG_DEBUG("kickKeepTime = %d, %d", servMgr->kickKeepTime, ctime-ch->time);
+ if ( (servMgr->kickKeepTime == 0) || ((ctime-ch->time) > servMgr->kickKeepTime) ){
+ ch = deleteHit(ch);
+ } else {
+ ch->numHops = 0;
+ ch->numListeners = 0;
+ ch = ch->next;
+ }
+ } else {
+ ch = deleteHit(ch);
+ }
+
+ continue;
+ }else
+ cnt++;
+ }
+ ch = ch->next;
+ }
+// LOG_DEBUG("clearDeadHits HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+ return cnt;
+}
+
+
+// -----------------------------------
+void ChanHitList::deadHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ LOG_DEBUG("Dead hit: %s/%s",ip0str,ip1str);
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+ {
+ ch->dead = true;
+ }
+ ch = ch->next;
+ }
+}
+// -----------------------------------
+void ChanHitList::delHit(ChanHit &h)
+{
+ char ip0str[64],ip1str[64];
+ h.rhost[0].toStr(ip0str);
+ h.rhost[1].toStr(ip1str);
+ LOG_DEBUG("Del hit: %s/%s",ip0str,ip1str);
+
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip)
+ if (ch->rhost[0].isSame(h.rhost[0]) && ch->rhost[1].isSame(h.rhost[1]))
+ {
+ ch=deleteHit(ch);
+ continue;
+ }
+ ch = ch->next;
+ }
+}
+// -----------------------------------
+int ChanHitList::numHits()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead && ch->numHops)
+ cnt++;
+ ch = ch->next;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numListeners()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead && ch->numHops)
+ cnt += ch->numListeners;
+ ch=ch->next;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numRelays()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ cnt += ch->numRelays;
+ ch=ch->next;
+ }
+
+ return cnt;
+}
+
+// -----------------------------------
+int ChanHitList::numTrackers()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if ((ch->host.ip && !ch->dead) && (ch->tracker))
+ cnt++;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::numFirewalled()
+{
+ int cnt=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ cnt += ch->firewalled?1:0;
+ ch=ch->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+int ChanHitList::closestHit()
+{
+ unsigned int hop=10000;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->numHops < hop)
+ hop = ch->numHops;
+ ch=ch->next;
+ }
+
+ return hop;
+}
+// -----------------------------------
+int ChanHitList::furthestHit()
+{
+ unsigned int hop=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->numHops > hop)
+ hop = ch->numHops;
+ ch=ch->next;
+ }
+
+ return hop;
+}
+// -----------------------------------
+unsigned int ChanHitList::newestHit()
+{
+ unsigned int time=0;
+ ChanHit *ch = hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ if (ch->time > time)
+ time = ch->time;
+ ch=ch->next;
+ }
+
+ return time;
+}
+// -----------------------------------
+int ChanHitList::pickHits(ChanHitSearch &chs)
+{
+ ChanHit best,*bestP=NULL;
+ best.init();
+ best.numHops = 255;
+ best.time = 0;
+
+ unsigned int ctime = sys->getTime();
+
+ ChanHit *c = hit;
+ while (c)
+ {
+ if (c->host.ip && !c->dead)
+ {
+ if (!chs.excludeID.isSame(c->sessionID))
+ if ((chs.waitDelay==0) || ((ctime-c->lastContact) >= chs.waitDelay))
+ if ((c->numHops<=best.numHops)) // (c->time>=best.time))
+ if (c->relay || (!c->relay && chs.useBusyRelays))
+ if (c->cin || (!c->cin && chs.useBusyControls))
+ {
+
+ if (chs.trackersOnly && c->tracker)
+ {
+ if (chs.matchHost.ip)
+ {
+ if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[1]; // use lan ip
+ }
+ }else if (c->firewalled == chs.useFirewalled)
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[0]; // use wan ip
+ }
+ }else if (!chs.trackersOnly && !c->tracker)
+ {
+ if (chs.matchHost.ip)
+ {
+ if ((c->rhost[0].ip == chs.matchHost.ip) && c->rhost[1].isValid())
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[1]; // use lan ip
+ }
+ }else if (c->firewalled == chs.useFirewalled && (!bestP || !bestP->relay))
+ {
+ bestP = c;
+ best = *c;
+ best.host = best.rhost[0]; // use wan ip
+ }
+ }
+ }
+ }
+ c=c->next;
+ }
+
+ if (bestP)
+ {
+ if (chs.numResults < ChanHitSearch::MAX_RESULTS)
+ {
+ if (chs.waitDelay)
+ bestP->lastContact = ctime;
+ chs.best[chs.numResults++] = best;
+ return 1;
+ }
+
+ }
+
+ return 0;
+}
+
+
+// -----------------------------------
+int ChanHitList::pickSourceHits(ChanHitSearch &chs)
+{
+ if (pickHits(chs) && chs.best[0].numHops == 0) return 1;
+ return 0;
+}
+
+
+// -----------------------------------
+const char *ChanInfo::getTypeStr(TYPE t)
+{
+ switch (t)
+ {
+ case T_RAW: return "RAW";
+
+ case T_MP3: return "MP3";
+ case T_OGG: return "OGG";
+ case T_OGM: return "OGM";
+ case T_WMA: return "WMA";
+
+ case T_MOV: return "MOV";
+ case T_MPG: return "MPG";
+ case T_NSV: return "NSV";
+ case T_WMV: return "WMV";
+
+ case T_PLS: return "PLS";
+ case T_ASX: return "ASX";
+
+ default: return "UNKNOWN";
+ }
+}
+// -----------------------------------
+const char *ChanInfo::getProtocolStr(PROTOCOL t)
+{
+ switch (t)
+ {
+ case SP_PEERCAST: return "PEERCAST";
+ case SP_HTTP: return "HTTP";
+ case SP_FILE: return "FILE";
+ case SP_MMS: return "MMS";
+ case SP_PCP: return "PCP";
+ default: return "UNKNOWN";
+ }
+}
+// -----------------------------------
+ChanInfo::PROTOCOL ChanInfo::getProtocolFromStr(const char *str)
+{
+ if (stricmp(str,"PEERCAST")==0)
+ return SP_PEERCAST;
+ else if (stricmp(str,"HTTP")==0)
+ return SP_HTTP;
+ else if (stricmp(str,"FILE")==0)
+ return SP_FILE;
+ else if (stricmp(str,"MMS")==0)
+ return SP_MMS;
+ else if (stricmp(str,"PCP")==0)
+ return SP_PCP;
+ else
+ return SP_UNKNOWN;
+}
+
+// -----------------------------------
+const char *ChanInfo::getTypeExt(TYPE t)
+{
+ switch(t)
+ {
+ case ChanInfo::T_OGM:
+ case ChanInfo::T_OGG:
+ return ".ogg";
+ case ChanInfo::T_MP3:
+ return ".mp3";
+ case ChanInfo::T_MOV:
+ return ".mov";
+ case ChanInfo::T_NSV:
+ return ".nsv";
+ case ChanInfo::T_WMV:
+ return ".wmv";
+ case ChanInfo::T_WMA:
+ return ".wma";
+ default:
+ return "";
+ }
+}
+// -----------------------------------
+ChanInfo::TYPE ChanInfo::getTypeFromStr(const char *str)
+{
+ if (stricmp(str,"MP3")==0)
+ return T_MP3;
+ else if (stricmp(str,"OGG")==0)
+ return T_OGG;
+ else if (stricmp(str,"OGM")==0)
+ return T_OGM;
+ else if (stricmp(str,"RAW")==0)
+ return T_RAW;
+ else if (stricmp(str,"NSV")==0)
+ return T_NSV;
+ else if (stricmp(str,"WMA")==0)
+ return T_WMA;
+ else if (stricmp(str,"WMV")==0)
+ return T_WMV;
+ else if (stricmp(str,"PLS")==0)
+ return T_PLS;
+ else if (stricmp(str,"M3U")==0)
+ return T_PLS;
+ else if (stricmp(str,"ASX")==0)
+ return T_ASX;
+ else
+ return T_UNKNOWN;
+}
+// -----------------------------------
+bool ChanInfo::matchNameID(ChanInfo &inf)
+{
+ if (inf.id.isSet())
+ if (id.isSame(inf.id))
+ return true;
+
+ if (!inf.name.isEmpty())
+ if (name.contains(inf.name))
+ return true;
+
+ return false;
+}
+// -----------------------------------
+bool ChanInfo::match(ChanInfo &inf)
+{
+ bool matchAny=true;
+
+ if (inf.status != S_UNKNOWN)
+ {
+ if (status != inf.status)
+ return false;
+ }
+
+ if (inf.bitrate != 0)
+ {
+ if (bitrate == inf.bitrate)
+ return true;
+ matchAny = false;
+ }
+
+ if (inf.id.isSet())
+ {
+ if (id.isSame(inf.id))
+ return true;
+ matchAny = false;
+ }
+
+ if (inf.contentType != T_UNKNOWN)
+ {
+ if (contentType == inf.contentType)
+ return true;
+ matchAny = false;
+ }
+
+ if (!inf.name.isEmpty())
+ {
+ if (name.contains(inf.name))
+ return true;
+ matchAny = false;
+ }
+
+ if (!inf.genre.isEmpty())
+ {
+ if (genre.contains(inf.genre))
+ return true;
+ matchAny = false;
+ }
+
+ return matchAny;
+}
+// -----------------------------------
+bool TrackInfo::update(TrackInfo &inf)
+{
+ bool changed = false;
+
+ if (!contact.isSame(inf.contact))
+ {
+ contact = inf.contact;
+ changed = true;
+ }
+
+ if (!title.isSame(inf.title))
+ {
+ title = inf.title;
+ changed = true;
+ }
+
+ if (!artist.isSame(inf.artist))
+ {
+ artist = inf.artist;
+ changed = true;
+ }
+
+ if (!album.isSame(inf.album))
+ {
+ album = inf.album;
+ changed = true;
+ }
+
+ if (!genre.isSame(inf.genre))
+ {
+ genre = inf.genre;
+ changed = true;
+ }
+
+
+ return changed;
+}
+
+
+// -----------------------------------
+bool ChanInfo::update(ChanInfo &info)
+{
+ bool changed = false;
+
+
+
+ // check valid id
+ if (!info.id.isSet())
+ return false;
+
+ // only update from chaninfo that has full name etc..
+ if (info.name.isEmpty())
+ return false;
+
+ // check valid broadcaster key
+ if (bcID.isSet())
+ {
+ if (!bcID.isSame(info.bcID))
+ {
+ LOG_ERROR("ChanInfo BC key not valid");
+ return false;
+ }
+ }else
+ {
+ bcID = info.bcID;
+ }
+
+
+
+ if (bitrate != info.bitrate)
+ {
+ bitrate = info.bitrate;
+ changed = true;
+ }
+
+ if (contentType != info.contentType)
+ {
+ contentType = info.contentType;
+ changed = true;
+ }
+
+ if (!desc.isSame(info.desc)) //JP-EX
+ {
+ desc = info.desc;
+ changed = true;
+ }
+
+ if (!name.isSame(info.name))
+ {
+ name = info.name;
+ changed = true;
+ }
+
+ if (!comment.isSame(info.comment))
+ {
+ comment = info.comment;
+ changed = true;
+ }
+
+ if (!genre.isSame(info.genre))
+ {
+ genre = info.genre;
+ changed = true;
+ }
+
+ if (!url.isSame(info.url))
+ {
+ url = info.url;
+ changed = true;
+ }
+
+ if (track.update(info.track))
+ changed = true;
+
+
+ return changed;
+}
+// -----------------------------------
+void ChanInfo::initNameID(const char *n)
+{
+ init();
+ id.fromStr(n);
+ if (!id.isSet())
+ name.set(n);
+}
+
+// -----------------------------------
+void ChanInfo::init()
+{
+ status = S_UNKNOWN;
+ name.clear();
+ bitrate = 0;
+ contentType = T_UNKNOWN;
+ srcProtocol = SP_UNKNOWN;
+ id.clear();
+ url.clear();
+ genre.clear();
+ comment.clear();
+ track.clear();
+ lastPlayStart = 0;
+ lastPlayEnd = 0;
+ numSkips = 0;
+ bcID.clear();
+ createdTime = 0;
+}
+// -----------------------------------
+void ChanInfo::readTrackXML(XML::Node *n)
+{
+ track.clear();
+ readXMLString(track.title,n,"title");
+ readXMLString(track.contact,n,"contact");
+ readXMLString(track.artist,n,"artist");
+ readXMLString(track.album,n,"album");
+ readXMLString(track.genre,n,"genre");
+}
+// -----------------------------------
+unsigned int ChanInfo::getUptime()
+{
+ // calculate uptime and cap if requested by settings.
+ unsigned int upt;
+ upt = lastPlayStart?(sys->getTime()-lastPlayStart):0;
+ if (chanMgr->maxUptime)
+ if (upt > chanMgr->maxUptime)
+ upt = chanMgr->maxUptime;
+ return upt;
+}
+// -----------------------------------
+unsigned int ChanInfo::getAge()
+{
+ return sys->getTime()-createdTime;
+}
+
+// ------------------------------------------
+void ChanInfo::readTrackAtoms(AtomStream &atom,int numc)
+{
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+ if (id == PCP_CHAN_TRACK_TITLE)
+ {
+ atom.readString(track.title.data,sizeof(track.title.data),d);
+ }else if (id == PCP_CHAN_TRACK_CREATOR)
+ {
+ atom.readString(track.artist.data,sizeof(track.artist.data),d);
+ }else if (id == PCP_CHAN_TRACK_URL)
+ {
+ atom.readString(track.contact.data,sizeof(track.contact.data),d);
+ }else if (id == PCP_CHAN_TRACK_ALBUM)
+ {
+ atom.readString(track.album.data,sizeof(track.album.data),d);
+ }else
+ atom.skip(c,d);
+ }
+}
+// ------------------------------------------
+void ChanInfo::readInfoAtoms(AtomStream &atom,int numc)
+{
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+ if (id == PCP_CHAN_INFO_NAME)
+ {
+ atom.readString(name.data,sizeof(name.data),d);
+ }else if (id == PCP_CHAN_INFO_BITRATE)
+ {
+ bitrate = atom.readInt();
+ }else if (id == PCP_CHAN_INFO_GENRE)
+ {
+ atom.readString(genre.data,sizeof(genre.data),d);
+ }else if (id == PCP_CHAN_INFO_URL)
+ {
+ atom.readString(url.data,sizeof(url.data),d);
+ }else if (id == PCP_CHAN_INFO_DESC)
+ {
+ atom.readString(desc.data,sizeof(desc.data),d);
+ }else if (id == PCP_CHAN_INFO_COMMENT)
+ {
+ atom.readString(comment.data,sizeof(comment.data),d);
+ }else if (id == PCP_CHAN_INFO_TYPE)
+ {
+ char type[16];
+ atom.readString(type,sizeof(type),d);
+ contentType = ChanInfo::getTypeFromStr(type);
+ }else
+ atom.skip(c,d);
+ }
+}
+
+// -----------------------------------
+void ChanInfo::writeInfoAtoms(AtomStream &atom)
+{
+ atom.writeParent(PCP_CHAN_INFO,7);
+ atom.writeString(PCP_CHAN_INFO_NAME,name.cstr());
+ atom.writeInt(PCP_CHAN_INFO_BITRATE,bitrate);
+ atom.writeString(PCP_CHAN_INFO_GENRE,genre.cstr());
+ atom.writeString(PCP_CHAN_INFO_URL,url.cstr());
+ atom.writeString(PCP_CHAN_INFO_DESC,desc.cstr());
+ atom.writeString(PCP_CHAN_INFO_COMMENT,comment.cstr());
+ atom.writeString(PCP_CHAN_INFO_TYPE,getTypeStr(contentType));
+
+}
+// -----------------------------------
+void ChanInfo::writeTrackAtoms(AtomStream &atom)
+{
+ atom.writeParent(PCP_CHAN_TRACK,4);
+ atom.writeString(PCP_CHAN_TRACK_TITLE,track.title.cstr());
+ atom.writeString(PCP_CHAN_TRACK_CREATOR,track.artist.cstr());
+ atom.writeString(PCP_CHAN_TRACK_URL,track.contact.cstr());
+ atom.writeString(PCP_CHAN_TRACK_ALBUM,track.album.cstr());
+}
+
+
+// -----------------------------------
+XML::Node *ChanInfo::createChannelXML()
+{
+ char idStr[64];
+
+ String nameUNI = name;
+ nameUNI.convertTo(String::T_UNICODESAFE);
+
+ String urlUNI = url;
+ urlUNI.convertTo(String::T_UNICODESAFE);
+
+ String genreUNI = genre;
+ genreUNI.convertTo(String::T_UNICODESAFE);
+
+ String descUNI = desc;
+ descUNI.convertTo(String::T_UNICODESAFE);
+
+ String commentUNI;
+ commentUNI = comment;
+ commentUNI.convertTo(String::T_UNICODESAFE);
+
+
+ id.toStr(idStr);
+
+
+ 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\"",
+ nameUNI.cstr(),
+ idStr,
+ bitrate,
+ getTypeStr(contentType),
+ genreUNI.cstr(),
+ descUNI.cstr(),
+ urlUNI.cstr(),
+ getUptime(),
+ commentUNI.cstr(),
+ numSkips,
+ getAge(),
+ bcID.getFlags()
+ );
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createQueryXML()
+{
+ char buf[512];
+ char idStr[64];
+
+
+ String nameHTML = name;
+ nameHTML.convertTo(String::T_HTML);
+ String genreHTML = genre;
+ genreHTML.convertTo(String::T_HTML);
+
+ buf[0]=0;
+ if (!nameHTML.isEmpty())
+ {
+ strcat(buf," name=\"");
+ strcat(buf,nameHTML.cstr());
+ strcat(buf,"\"");
+ }
+
+ if (!genreHTML.isEmpty())
+ {
+ strcat(buf," genre=\"");
+ strcat(buf,genreHTML.cstr());
+ strcat(buf,"\"");
+ }
+
+ if (id.isSet())
+ {
+ id.toStr(idStr);
+ strcat(buf," id=\"");
+ strcat(buf,idStr);
+ strcat(buf,"\"");
+ }
+
+
+ return new XML::Node("channel %s",buf);
+}
+
+// -----------------------------------
+XML::Node *ChanInfo::createRelayChannelXML()
+{
+ char idStr[64];
+
+ id.toStr(idStr);
+
+
+ return new XML::Node("channel id=\"%s\" uptime=\"%d\" skips=\"%d\" age=\"%d\"",
+ idStr,
+ getUptime(),
+ numSkips,
+ getAge()
+ );
+}// -----------------------------------
+XML::Node *ChanInfo::createTrackXML()
+{
+ String titleUNI = track.title;
+ titleUNI.convertTo(String::T_UNICODESAFE);
+
+ String artistUNI = track.artist;
+ artistUNI.convertTo(String::T_UNICODESAFE);
+
+ String albumUNI = track.album;
+ albumUNI.convertTo(String::T_UNICODESAFE);
+
+ String genreUNI = track.genre;
+ genreUNI.convertTo(String::T_UNICODESAFE);
+
+ String contactUNI = track.contact;
+ contactUNI.convertTo(String::T_UNICODESAFE);
+
+
+
+ return new XML::Node("track title=\"%s\" artist=\"%s\" album=\"%s\" genre=\"%s\" contact=\"%s\"",
+ titleUNI.cstr(),
+ artistUNI.cstr(),
+ albumUNI.cstr(),
+ genreUNI.cstr(),
+ contactUNI.cstr()
+ );
+}
+
+// -----------------------------------
+void ChanInfo::init(XML::Node *n)
+{
+ init();
+
+ updateFromXML(n);
+}
+// -----------------------------------
+void ChanInfo::updateFromXML(XML::Node *n)
+{
+ String typeStr,idStr;
+
+ readXMLString(name,n,"name");
+ readXMLString(genre,n,"genre");
+ readXMLString(url,n,"url");
+ readXMLString(desc,n,"desc");
+
+
+ int br = n->findAttrInt("bitrate");
+ if (br)
+ bitrate = br;
+
+ readXMLString(typeStr,n,"type");
+ if (!typeStr.isEmpty())
+ contentType = getTypeFromStr(typeStr.cstr());
+
+
+ readXMLString(idStr,n,"id");
+ if (!idStr.isEmpty())
+ id.fromStr(idStr.cstr());
+
+ readXMLString(comment,n,"comment");
+
+ XML::Node *tn = n->findNode("track");
+ if (tn)
+ readTrackXML(tn);
+
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *n, GnuID &cid, TYPE tp, int br)
+{
+ init();
+
+ name.set(n);
+ bitrate = br;
+ contentType = tp;
+ id = cid;
+}
+
+// -----------------------------------
+void ChanInfo::init(const char *fn)
+{
+ init();
+
+ if (fn)
+ name.set(fn);
+}
+// -----------------------------------
+void PlayList::readASX(Stream &in)
+{
+ LOG_DEBUG("Reading ASX");
+ XML xml;
+
+ try
+ {
+ xml.read(in);
+ }catch(StreamException &) {} // TODO: eof is NOT handled properly in sockets - always get error at end
+
+ if (xml.root)
+ {
+ XML::Node *n = xml.root->child;
+ while (n)
+ {
+ if (stricmp("entry",n->getName())==0)
+ {
+ XML::Node *rf = n->findNode("ref");
+ if (rf)
+ {
+ char *hr = rf->findAttr("href");
+ if (hr)
+ {
+ addURL(hr,"");
+ //LOG("asx url %s",hr);
+ }
+
+ }
+ }
+ n=n->sibling;
+ }
+ }
+}
+// -----------------------------------
+void PlayList::readSCPLS(Stream &in)
+{
+ char tmp[256];
+ while (in.readLine(tmp,sizeof(tmp)))
+ {
+ if (strnicmp(tmp,"file",4)==0)
+ {
+ char *p = strstr(tmp,"=");
+ if (p)
+ addURL(p+1,"");
+ }
+ }
+}
+// -----------------------------------
+void PlayList::readPLS(Stream &in)
+{
+ char tmp[256];
+ while (in.readLine(tmp,sizeof(tmp)))
+ {
+ if (tmp[0] != '#')
+ addURL(tmp,"");
+ }
+}
+// -----------------------------------
+void PlayList::writeSCPLS(Stream &out)
+{
+ out.writeLine("[playlist]");
+ out.writeLine("");
+ out.writeLineF("NumberOfEntries=%d",numURLs);
+
+ for(int i=0; i<numURLs; i++)
+ {
+ out.writeLineF("File%d=%s",i+1,urls[i].cstr());
+ out.writeLineF("Title%d=%s",i+1,titles[i].cstr());
+ out.writeLineF("Length%d=-1",i+1);
+ }
+ out.writeLine("Version=2");
+}
+// -----------------------------------
+void PlayList::writePLS(Stream &out)
+{
+ for(int i=0; i<numURLs; i++)
+ out.writeLineF("%s",urls[i].cstr());
+}
+// -----------------------------------
+void PlayList::writeRAM(Stream &out)
+{
+ for(int i=0; i<numURLs; i++)
+ out.writeLineF("%s",urls[i].cstr());
+}
+
+// -----------------------------------
+void PlayList::writeASX(Stream &out)
+{
+ out.writeLine("<ASX Version=\"3.0\">");
+ for(int i=0; i<numURLs; i++)
+ {
+ out.writeLine("<ENTRY>");
+ out.writeLineF("<REF href = \"%s\" />",urls[i].cstr());
+ out.writeLine("</ENTRY>");
+ }
+ out.writeLine("</ASX>");
+}
+
+
+// -----------------------------------
+void PlayList::addChannel(const char *path, ChanInfo &info)
+{
+ String url;
+
+ char idStr[64];
+
+ info.id.toStr(idStr);
+ char *nid = info.id.isSet()?idStr:info.name.cstr();
+
+ sprintf(url.cstr(),"%s/stream/%s%s",path,nid,ChanInfo::getTypeExt(info.contentType));
+ addURL(url.cstr(),info.name);
+}
+
+// -----------------------------------
+void ChanHitSearch::init()
+{
+ matchHost.init();
+ waitDelay = 0;
+ useFirewalled = false;
+ trackersOnly = false;
+ useBusyRelays = true;
+ useBusyControls = true;
+ excludeID.clear();
+ numResults = 0;
+
+ //seed = sys->getTime();
+ //srand(seed);
+}
+
+int ChanHitSearch::getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl)
+{
+ int cnt = 0;
+ int loop = 1;
+ int index = 0;
+ int prob;
+ int rnd;
+ static int base = 0x400;
+ ChanHit tmpHit[MAX_RESULTS];
+ static WLock seqLock;
+ static unsigned int riSequence = 0;
+
+ //srand(seed);
+ //seed += 11;
+
+ unsigned int seq;
+ seqLock.on();
+ seq = riSequence++;
+ riSequence &= 0xffffff;
+ seqLock.off();
+
+ ChanHit *hit = chl->hit;
+
+ while(hit){
+ if (hit->host.ip && !hit->dead){
+ if (
+ (!exID.isSame(hit->sessionID))
+// && (hit->relay)
+ && (!hit->tracker)
+ && (!hit->firewalled)
+ && (hit->numHops != 0)
+ ){
+ if ( (hit->rhost[0].ip == host1.ip)
+ && hit->rhost[1].isValid()
+ && (host2.ip != hit->rhost[1].ip)
+ ){
+ best[0] = *hit;
+ best[0].host = hit->rhost[1];
+ index++;
+ }
+ if ((hit->rhost[0].ip == host2.ip) && hit->rhost[1].isValid()){
+ best[0] = *hit;
+ best[0].host = hit->rhost[1];
+ index++;
+ }
+
+ loop = (index / MAX_RESULTS) + 1;
+ //prob = (float)1 / (float)loop;
+ prob = base / loop;
+ //rnd = (float)rand() / (float)RAND_MAX;
+ rnd = rand() % base;
+ if (hit->numHops == 1){
+ if (tmpHit[index % MAX_RESULTS].numHops == 1){
+ if (rnd < prob){
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ } else {
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ } else {
+ if ((tmpHit[index % MAX_RESULTS].numHops != 1) && (rnd < prob)){
+ tmpHit[index % MAX_RESULTS] = *hit;
+ tmpHit[index % MAX_RESULTS].host = hit->rhost[0];
+ index++;
+ }
+ }
+
+// char tmp[50];
+// hit->host.toStr(tmp);
+// LOG_DEBUG("TEST %s: %f %f", tmp, rnd, prob);
+ }
+ }
+ hit = hit->next;
+ }
+
+ if (index > MAX_RESULTS){
+ cnt = MAX_RESULTS;
+ } else {
+ cnt = index;
+ }
+
+/* int use[MAX_RESULTS];
+ memset(use, 0, sizeof(use));
+ int i;
+ for (i = 0; i < cnt; i++){
+ use[i] = -1;
+ }
+ int r;
+ for (i = 0; i < cnt; i++){
+ do {
+ r = rand();
+// LOG_DEBUG("%d",r);
+ r = r % cnt;
+ if (use[r] == -1){
+ use[r] = i;
+ break;
+ }
+ } while(1);
+ }
+ for (i = 0; i < cnt; i++){
+// LOG_DEBUG("%d", use[i]);
+ best[use[i]] = tmpHit[i];
+ }*/
+
+ int use[MAX_RESULTS];
+ int i;
+ for (i = 0; i < cnt; i++) {
+ use[i] = (i + seq) % cnt;
+ }
+
+ for (i = 0; i < cnt; i++){
+// LOG_DEBUG("%d", use[i]);
+ best[use[i]] = tmpHit[i];
+ }
+// for (i = 0; i < cnt; i++){
+// char tmp[50];
+// best[i].host.toStr(tmp);
+// LOG_DEBUG("Relay info: Hops = %d, %s", best[i].numHops, tmp);
+// }
+
+ return cnt;
+}
--- /dev/null
+// ------------------------------------------------
+// File : channel.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CHANNEL_H
+#define _CHANNEL_H
+
+#include "sys.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "asf.h"
+#include "cstream.h"
+
+class AtomStream;
+class ChanHitSearch;
+
+// --------------------------------------------------
+struct MP3Header
+{
+ int lay;
+ int version;
+ int error_protection;
+ int bitrate_index;
+ int sampling_frequency;
+ int padding;
+ int extension;
+ int mode;
+ int mode_ext;
+ int copyright;
+ int original;
+ int emphasis;
+ int stereo;
+};
+
+// ----------------------------------
+class TrackInfo
+{
+public:
+ void clear()
+ {
+ contact.clear();
+ title.clear();
+ artist.clear();
+ album.clear();
+ genre.clear();
+ }
+
+ void convertTo(String::TYPE t)
+ {
+ contact.convertTo(t);
+ title.convertTo(t);
+ artist.convertTo(t);
+ album.convertTo(t);
+ genre.convertTo(t);
+ }
+
+ bool update(TrackInfo &);
+
+ ::String contact,title,artist,album,genre;
+};
+
+
+
+// ----------------------------------
+class ChanInfo
+{
+public:
+ enum TYPE
+ {
+ T_UNKNOWN,
+
+ T_RAW,
+ T_MP3,
+ T_OGG,
+ T_OGM,
+ T_MOV,
+ T_MPG,
+ T_NSV,
+
+ T_WMA,
+ T_WMV,
+
+ T_PLS,
+ T_ASX
+ };
+
+
+ enum PROTOCOL
+ {
+ SP_UNKNOWN,
+ SP_PEERCAST,
+ SP_HTTP,
+ SP_FILE,
+ SP_MMS,
+ SP_PCP
+ };
+
+
+ enum STATUS
+ {
+ S_UNKNOWN,
+ S_PLAY
+ };
+
+ ChanInfo() {init();}
+
+ void init();
+ void init(const char *);
+ void init(const char *, GnuID &, TYPE, int);
+ void init(XML::Node *);
+ void initNameID(const char *);
+
+ void updateFromXML(XML::Node *);
+
+ void readTrackXML(XML::Node *);
+ void readServentXML(XML::Node *);
+ bool update(ChanInfo &);
+ XML::Node *createQueryXML();
+ XML::Node *createChannelXML();
+ XML::Node *createRelayChannelXML();
+ XML::Node *createTrackXML();
+ bool match(XML::Node *);
+ bool match(ChanInfo &);
+ bool matchNameID(ChanInfo &);
+
+ void writeInfoAtoms(AtomStream &atom);
+ void writeTrackAtoms(AtomStream &atom);
+
+ void readInfoAtoms(AtomStream &,int);
+ void readTrackAtoms(AtomStream &,int);
+
+ unsigned int getUptime();
+ unsigned int getAge();
+ bool isActive() {return id.isSet();}
+ bool isPrivate() {return bcID.getFlags() & 1;}
+ static const char *getTypeStr(TYPE);
+ static const char *getProtocolStr(PROTOCOL);
+ static const char *getTypeExt(TYPE);
+ static TYPE getTypeFromStr(const char *str);
+ static PROTOCOL getProtocolFromStr(const char *str);
+
+ ::String name;
+ GnuID id,bcID;
+ int bitrate;
+ TYPE contentType;
+ PROTOCOL srcProtocol;
+ unsigned int lastPlayStart,lastPlayEnd;
+ unsigned int numSkips;
+ unsigned int createdTime;
+
+ STATUS status;
+
+ TrackInfo track;
+ ::String desc,genre,url,comment;
+
+};
+
+
+// ----------------------------------
+class ChanHit
+{
+public:
+ void init();
+ void initLocal(int numl,int numr,int nums,int uptm,bool,bool,unsigned int,Channel*,unsigned int,unsigned int);
+ XML::Node *createXML();
+
+ void writeAtoms(AtomStream &,GnuID &);
+ bool writeVariable(Stream &, const String &);
+
+ void pickNearestIP(Host &);
+
+ Host host;
+ Host rhost[2];
+ unsigned int numListeners,numRelays,numHops;
+ unsigned int time,upTime,lastContact;
+ unsigned int hitID;
+ GnuID sessionID,chanID;
+ unsigned int version;
+ unsigned int version_vp;
+
+ bool firewalled:1,stable:1,tracker:1,recv:1,yp:1,dead:1,direct:1,relay:1,cin:1;
+ bool relayfull:1,chfull:1,ratefull:1;
+
+ ChanHit *next;
+
+ int status;
+ int servent_id;
+
+ unsigned int oldestPos,newestPos;
+ Host uphost;
+ unsigned int uphostHops;
+
+ char version_ex_prefix[2];
+ unsigned int version_ex_number;
+};
+// ----------------------------------
+class ChanHitList
+{
+public:
+ ChanHitList();
+ ~ChanHitList();
+
+ int contactTrackers(bool,int,int,int);
+
+ ChanHit *addHit(ChanHit &);
+ void delHit(ChanHit &);
+ void deadHit(ChanHit &);
+ void clearHits(bool);
+ int numHits();
+ int numListeners();
+ int numRelays();
+ int numFirewalled();
+ int numTrackers();
+ int closestHit();
+ int furthestHit();
+ unsigned int newestHit();
+
+ int pickHits(ChanHitSearch &);
+ int pickSourceHits(ChanHitSearch &);
+
+ bool isUsed() {return used;}
+ int clearDeadHits(unsigned int,bool);
+ XML::Node *createXML(bool addHits = true);
+
+ ChanHit *deleteHit(ChanHit *);
+
+ int getTotalListeners();
+ int getTotalRelays();
+ int getTotalFirewalled();
+
+ bool used;
+ ChanInfo info;
+ ChanHit *hit;
+ unsigned int lastHitTime;
+ ChanHitList *next;
+
+
+};
+// ----------------------------------
+class ChanHitSearch
+{
+public:
+ enum
+ {
+ MAX_RESULTS = 8
+ };
+
+ ChanHitSearch() { init(); }
+ void init();
+
+ ChanHit best[MAX_RESULTS];
+ Host matchHost;
+ unsigned int waitDelay;
+ bool useFirewalled;
+ bool trackersOnly;
+ bool useBusyRelays,useBusyControls;
+ GnuID excludeID;
+ int numResults;
+ unsigned int seed;
+
+ int getRelayHost(Host host1, Host host2, GnuID exID, ChanHitList *chl);
+};
+
+// ----------------------------------
+class ChanMeta
+{
+public:
+ enum {
+ MAX_DATALEN = 65536
+ };
+
+ void init()
+ {
+ len = 0;
+ cnt = 0;
+ startPos = 0;
+ }
+
+ void fromXML(XML &);
+ void fromMem(void *,int);
+ void addMem(void *,int);
+
+ unsigned int len,cnt,startPos;
+ char data[MAX_DATALEN];
+};
+
+
+
+// ------------------------------------------
+class RawStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+};
+
+// ------------------------------------------
+class PeercastStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+// ------------------------------------------
+class ChannelSource
+{
+public:
+ virtual ~ChannelSource() {}
+ virtual void stream(Channel *) = 0;
+
+ virtual int getSourceRate() {return 0;}
+
+};
+// ------------------------------------------
+class PeercastSource : public ChannelSource
+{
+public:
+
+
+ virtual void stream(Channel *);
+
+};
+
+
+// ----------------------------------
+class Channel
+{
+public:
+
+ enum STATUS
+ {
+ S_NONE,
+ S_WAIT,
+ S_CONNECTING,
+ S_REQUESTING,
+ S_CLOSING,
+ S_RECEIVING,
+ S_BROADCASTING,
+ S_ABORT,
+ S_SEARCHING,
+ S_NOHOSTS,
+ S_IDLE,
+ S_ERROR,
+ S_NOTFOUND
+ };
+
+ enum TYPE
+ {
+ T_NONE,
+ T_ALLOCATED,
+ T_BROADCAST,
+ T_RELAY
+ };
+
+ enum SRC_TYPE
+ {
+ SRC_NONE,
+ SRC_PEERCAST,
+ SRC_SHOUTCAST,
+ SRC_ICECAST,
+ SRC_URL
+ };
+
+
+ Channel();
+ void reset();
+ void endThread(bool flg);
+
+ void startMP3File(char *);
+ void startGet();
+ void startICY(ClientSocket *,SRC_TYPE);
+ void startURL(const char *);
+
+
+ ChannelStream *createSource();
+
+ void resetPlayTime();
+
+ bool notFound()
+ {
+ return (status == S_NOTFOUND);
+ }
+
+ bool isPlaying()
+ {
+ return (status == S_RECEIVING) || (status == S_BROADCASTING);
+ }
+
+ bool isReceiving()
+ {
+ return (status == S_RECEIVING);
+ }
+
+ bool isBroadcasting()
+ {
+ return (status == S_BROADCASTING);
+ }
+
+ bool isFull();
+
+ bool checkBump();
+
+ bool checkIdle();
+ void sleepUntil(double);
+
+ bool isActive()
+ {
+ return type != T_NONE;
+ }
+
+
+ void connectFetch();
+ int handshakeFetch();
+
+ bool isIdle() {return isActive() && (status==S_IDLE);}
+
+ static THREAD_PROC stream(ThreadInfo *);
+
+ static THREAD_PROC waitFinish(ThreadInfo *);
+
+ void setStatus(STATUS s);
+ const char *getSrcTypeStr() {return srcTypes[srcType];}
+ const char *getStatusStr() {return statusMsgs[status];}
+ const char *getName() {return info.name.cstr();}
+ GnuID getID() {return info.id;}
+ int getBitrate() {return info.bitrate; }
+ void getIDStr(char *s) {info.id.toStr(s);}
+ void getStreamPath(char *);
+
+ void broadcastTrackerUpdate(GnuID &,bool = false);
+ bool sendPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+
+ bool writeVariable(Stream &, const String &,int);
+
+ bool acceptGIV(ClientSocket *);
+
+ void updateInfo(ChanInfo &);
+
+ int readStream(Stream &,ChannelStream *);
+
+ void checkReadDelay(unsigned int);
+
+ void processMp3Metadata(char *);
+
+ void readHeader();
+
+ void startStream();
+
+ XML::Node *createRelayXML(bool);
+
+ void newPacket(ChanPacket &);
+
+ int localListeners();
+ int localRelays();
+
+ int totalListeners();
+ int totalRelays();
+
+ ::String mount;
+ ChanMeta insertMeta;
+ ChanPacket headPack;
+
+ ChanPacketBuffer rawData;
+
+ ChannelStream *sourceStream;
+ unsigned int streamIndex;
+
+
+ ChanInfo info;
+ ChanHit sourceHost;
+
+ GnuID remoteID;
+
+
+ ::String sourceURL;
+
+ bool bump,stayConnected;
+ int icyMetaInterval;
+ unsigned int streamPos;
+ unsigned int skipCount; //JP-EX
+ bool readDelay;
+
+ TYPE type;
+ ChannelSource *sourceData;
+
+ SRC_TYPE srcType;
+
+ MP3Header mp3Head;
+ ThreadInfo thread;
+ ThreadInfo *finthread;
+
+ unsigned int lastIdleTime;
+ int status;
+ static char *statusMsgs[],*srcTypes[];
+
+ ClientSocket *sock;
+ ClientSocket *pushSock;
+
+ unsigned int lastTrackerUpdate;
+ unsigned int lastMetaUpdate;
+
+ double startTime,syncTime;
+
+ WEvent syncEvent;
+
+ Channel *next;
+
+ int channel_id;
+ ChanHit chDisp;
+ ChanHit trackerHit;
+ bool bumped;
+ unsigned int lastSkipTime;
+ unsigned int lastStopTime;
+};
+
+// ----------------------------------
+class ChanMgr
+{
+public:
+ enum {
+ MAX_IDLE_CHANNELS = 8, // max. number of channels that can be left idle
+ MAX_METAINT = 8192 // must be at least smaller than ChanPacket data len (ie. about half)
+
+ };
+
+
+ ChanMgr();
+
+ Channel *deleteChannel(Channel *);
+
+ Channel *createChannel(ChanInfo &,const char *);
+ Channel *findChannelByName(const char *);
+ Channel *findChannelByIndex(int);
+ Channel *findChannelByMount(const char *);
+ Channel *findChannelByID(GnuID &);
+ Channel *findChannelByNameID(ChanInfo &);
+ Channel *findPushChannel(int);
+ Channel *findChannelByChannelID(int id);
+
+ void broadcastTrackerSettings();
+ void setUpdateInterval(unsigned int v);
+ void broadcastRelays(Servent *,int,int);
+
+ int broadcastPacketUp(ChanPacket &,GnuID &,GnuID &,GnuID &);
+ void broadcastTrackerUpdate(GnuID &,bool = false);
+
+ bool writeVariable(Stream &, const String &,int);
+
+ int findChannels(ChanInfo &,Channel **,int);
+ int findChannelsByStatus(Channel **,int,Channel::STATUS);
+
+ int numIdleChannels();
+ int numChannels();
+
+ void closeOldestIdle();
+ void closeAll();
+ void quit();
+
+ void addHit(Host &,GnuID &,bool);
+ ChanHit *addHit(ChanHit &);
+ void delHit(ChanHit &);
+ void deadHit(ChanHit &);
+ void setFirewalled(Host &);
+
+ ChanHitList *findHitList(ChanInfo &);
+ ChanHitList *findHitListByID(GnuID &);
+ ChanHitList *addHitList(ChanInfo &);
+
+ void clearHitLists();
+ void clearDeadHits(bool);
+ int numHitLists();
+
+ void setBroadcastMsg(::String &);
+
+ Channel *createRelay(ChanInfo &,bool);
+ Channel *findAndRelay(ChanInfo &);
+ void startSearch(ChanInfo &);
+
+ void playChannel(ChanInfo &);
+ void findAndPlayChannel(ChanInfo &,bool);
+
+ bool isBroadcasting(GnuID &);
+ bool isBroadcasting();
+
+ int pickHits(ChanHitSearch &);
+
+
+
+ Channel *channel;
+ ChanHitList *hitlist;
+
+ GnuID broadcastID;
+
+ ChanInfo searchInfo;
+
+ int numFinds;
+ ::String broadcastMsg;
+ unsigned int broadcastMsgInterval;
+ unsigned int lastHit,lastQuery;
+ unsigned int maxUptime;
+ bool searchActive;
+ unsigned int deadHitAge;
+ int icyMetaInterval;
+ int maxRelaysPerChannel;
+ WLock lock;
+ int minBroadcastTTL,maxBroadcastTTL;
+ int pushTimeout,pushTries,maxPushHops;
+ unsigned int autoQuery;
+ unsigned int prefetchTime;
+ unsigned int lastYPConnect;
+ unsigned int lastYPConnect2;
+ unsigned int icyIndex;
+
+ unsigned int hostUpdateInterval;
+ unsigned int bufferTime;
+
+ GnuID currFindAndPlayChannel;
+
+ WLock channellock;
+ WLock hitlistlock;
+};
+// ----------------------------------
+class PlayList
+{
+public:
+
+ enum TYPE
+ {
+ T_NONE,
+ T_SCPLS,
+ T_PLS,
+ T_ASX,
+ T_RAM,
+ };
+
+ PlayList(TYPE t, int max)
+ {
+ maxURLs = max;
+ numURLs = 0;
+ type = t;
+ urls = new ::String[max];
+ titles = new ::String[max];
+ }
+
+ ~PlayList()
+ {
+ delete [] urls;
+ delete [] titles;
+ }
+
+ void addURL(const char *url, const char *tit)
+ {
+ if (numURLs < maxURLs)
+ {
+ urls[numURLs].set(url);
+ titles[numURLs].set(tit);
+ numURLs++;
+ }
+ }
+ void addChannels(const char *,Channel **,int);
+ void addChannel(const char *,ChanInfo &);
+
+ void writeSCPLS(Stream &);
+ void writePLS(Stream &);
+ void writeASX(Stream &);
+ void writeRAM(Stream &);
+
+ void readSCPLS(Stream &);
+ void readPLS(Stream &);
+ void readASX(Stream &);
+
+ void read(Stream &s)
+ {
+ try
+ {
+ switch (type)
+ {
+ case T_SCPLS: readSCPLS(s); break;
+ case T_PLS: readPLS(s); break;
+ case T_ASX: readASX(s); break;
+ }
+ }catch(StreamException &) {} // keep pls regardless of errors (eof isn`t handled properly in sockets)
+ }
+
+ void write(Stream &s)
+ {
+ switch (type)
+ {
+ case T_SCPLS: writeSCPLS(s); break;
+ case T_PLS: writePLS(s); break;
+ case T_ASX: writeASX(s); break;
+ case T_RAM: writeRAM(s); break;
+ }
+ }
+
+ TYPE type;
+ int numURLs,maxURLs;
+ ::String *urls,*titles;
+};
+
+// ----------------------------------
+
+extern ChanMgr *chanMgr;
+
+// for PCRaw start.
+bool isIndexTxt(ChanInfo *info);
+bool isIndexTxt(Channel *ch);
+int numMaxRelaysIndexTxt(Channel *ch);
+int canStreamIndexTxt(Channel *ch);
+// for PCRaw end
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : common.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#pragma warning (disable: 4996)
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+// ----------------------------------
+class GeneralException
+{
+public:
+ GeneralException(const char *m, int e = 0)
+ {
+ strcpy(msg,m);
+ err=e;
+ }
+ char msg[128];
+ int err;
+};
+
+// -------------------------------------
+class StreamException : public GeneralException
+{
+public:
+ StreamException(const char *m) : GeneralException(m) {}
+ StreamException(const char *m,int e) : GeneralException(m,e) {}
+};
+
+// ----------------------------------
+class SockException : public StreamException
+{
+public:
+ SockException(const char *m="Socket") : StreamException(m) {}
+ SockException(const char *m, int e) : StreamException(m,e) {}
+};
+// ----------------------------------
+class EOFException : public StreamException
+{
+public:
+ EOFException(const char *m="EOF") : StreamException(m) {}
+ EOFException(const char *m, int e) : StreamException(m,e) {}
+};
+
+// ----------------------------------
+class CryptException : public StreamException
+{
+public:
+ CryptException(const char *m="Crypt") : StreamException(m) {}
+ CryptException(const char *m, int e) : StreamException(m,e) {}
+};
+
+
+// ----------------------------------
+class TimeoutException : public StreamException
+{
+public:
+ TimeoutException(const char *m="Timeout") : StreamException(m) {}
+};
+// --------------------------------
+class GnuID
+{
+public:
+ bool isSame(GnuID &gid)
+ {
+ for(int i=0; i<16; i++)
+ if (gid.id[i] != id[i])
+ return false;
+ return true;
+ }
+
+
+ bool isSet()
+ {
+ for(int i=0; i<16; i++)
+ if (id[i] != 0)
+ return true;
+ return false;
+ }
+
+ void clear()
+ {
+ for(int i=0; i<16; i++)
+ id[i] = 0;
+ storeTime = 0;
+ }
+
+
+ void generate(unsigned char = 0);
+ void encode(class Host *, const char *,const char *,unsigned char);
+
+ void toStr(char *);
+ void fromStr(const char *);
+
+ unsigned char getFlags();
+
+ unsigned char id[16];
+ unsigned int storeTime;
+};
+// --------------------------------
+class GnuIDList
+{
+public:
+ GnuIDList(int);
+ ~GnuIDList();
+ void clear();
+ void add(GnuID &);
+ bool contains(GnuID &);
+ int numUsed();
+ unsigned int getOldest();
+
+ GnuID *ids;
+ int maxID;
+};
+
+
+// ----------------------------------
+class Host
+{
+ inline unsigned int ip3()
+ {
+ return (ip>>24);
+ }
+ inline unsigned int ip2()
+ {
+ return (ip>>16)&0xff;
+ }
+ inline unsigned int ip1()
+ {
+ return (ip>>8)&0xff;
+ }
+ inline unsigned int ip0()
+ {
+ return ip&0xff;
+ }
+
+public:
+ Host(){init();}
+ Host(unsigned int i, unsigned short p)
+ {
+ ip = i;
+ port = p;
+ value = 0;
+ }
+
+ void init()
+ {
+ ip = 0;
+ port = 0;
+ value = 0;
+ }
+
+
+ bool isMemberOf(Host &);
+
+ bool isSame(Host &h)
+ {
+ return (h.ip == ip) && (h.port == port);
+ }
+
+ bool classType() {return globalIP();}
+
+ bool globalIP()
+ {
+ // local host
+ if ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1))
+ return false;
+
+ // class A
+ if (ip3() == 10)
+ return false;
+
+ // class B
+ if ((ip3() == 172) && (ip2() >= 16) && (ip2() <= 31))
+ return false;
+
+ // class C
+ if ((ip3() == 192) && (ip2() == 168))
+ return false;
+
+ return true;
+ }
+ bool localIP()
+ {
+ return !globalIP();
+ }
+
+ bool loopbackIP()
+ {
+// return ((ipByte[3] == 127) && (ipByte[2] == 0) && (ipByte[1] == 0) && (ipByte[0] == 1));
+ return ((ip3() == 127) && (ip2() == 0) && (ip1() == 0) && (ip0() == 1));
+ }
+
+ bool isValid()
+ {
+ return (ip != 0);
+ }
+
+
+ bool isSameType(Host &h)
+ {
+ return ( (globalIP() && h.globalIP()) ||
+ (!globalIP() && !h.globalIP()) );
+ }
+
+ void IPtoStr(char *str)
+ {
+ sprintf(str,"%d.%d.%d.%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff);
+ }
+
+ void toStr(char *str)
+ {
+ sprintf(str,"%d.%d.%d.%d:%d",(ip>>24)&0xff,(ip>>16)&0xff,(ip>>8)&0xff,(ip)&0xff,port);
+ }
+
+ void fromStrIP(const char *,int);
+ void fromStrName(const char *,int);
+
+ bool isLocalhost();
+
+
+ union
+ {
+ unsigned int ip;
+// unsigned char ipByte[4];
+ };
+
+ unsigned short port;
+ unsigned int value;
+};
+// ----------------------------------
+#define SWAP2(v) ( ((v&0xff)<<8) | ((v&0xff00)>>8) )
+#define SWAP3(v) (((v&0xff)<<16) | ((v&0xff00)) | ((v&0xff0000)>>16) )
+#define SWAP4(v) (((v&0xff)<<24) | ((v&0xff00)<<8) | ((v&0xff0000)>>8) | ((v&0xff000000)>>24))
+#define TOUPPER(c) ((((c) >= 'a') && ((c) <= 'z')) ? (c)+'A'-'a' : (c))
+#define TONIBBLE(c) ((((c) >= 'A')&&((c) <= 'F')) ? (((c)-'A')+10) : ((c)-'0'))
+#define BYTES_TO_KBPS(n) (float)(((((float)n)*8.0f)/1024.0f))
+
+// ----------------------------------
+inline bool isWhiteSpace(char c)
+{
+ return (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t');
+}
+
+// ----------------------------------
+inline int strToID(char *str)
+{
+ union {
+ int i;
+ char s[8];
+ };
+ strncpy(s,str,4);
+ return i;
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg);
+bool cmpCGIarg(char *str, char *arg, char *value);
+bool hasCGIarg(char *str, char *arg);
+
+// ----------------------------------
+extern void LOG(const char *fmt,...);
+
+extern void LOG_ERROR(const char *fmt,...);
+extern void LOG_DEBUG(const char *fmt,...);
+extern void LOG_NETWORK(const char *fmt,...);
+extern void LOG_CHANNEL(const char *fmt,...);
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : cstream.h
+// Date: 12-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _CSTREAM_H
+#define _CSTREAM_H
+
+// ----------------------------------
+
+class Channel;
+class ChanPacket;
+class ChanPacketv;
+class Stream;
+
+
+// ----------------------------------
+class ChanPacket
+{
+public:
+ enum
+ {
+ MAX_DATALEN = 16384
+ };
+
+ enum TYPE
+ {
+ T_UNKNOWN = 0,
+ T_HEAD = 1,
+ T_DATA = 2,
+ T_META = 4,
+ T_PCP = 16,
+ T_ALL = 0xff
+ };
+
+ ChanPacket()
+ {
+ init();
+ }
+
+ void init()
+ {
+ type = T_UNKNOWN;
+ len = 0;
+ pos = 0;
+ sync = 0;
+ skip = false;
+ }
+ void init(ChanPacketv &p);
+ void init(TYPE t, const void *, unsigned int , unsigned int );
+
+ void writeRaw(Stream &);
+ void writePeercast(Stream &);
+ void readPeercast(Stream &);
+
+
+ unsigned int sync;
+ unsigned int pos;
+ TYPE type;
+ unsigned int len;
+ char data[MAX_DATALEN];
+ bool skip;
+
+};
+// ----------------------------------
+class ChanPacketv
+{
+public:
+ enum {BSIZE = 0x100};
+ ChanPacketv()
+ {
+ init();
+ }
+ ~ChanPacketv()
+ {
+ free();
+ }
+
+ void free()
+ {
+ if (data) {
+ delete [] data;
+ data = NULL;
+ datasize = 0;
+ }
+ }
+ void reset()
+ {
+ free();
+ init();
+ }
+ void init()
+ {
+ type = ChanPacket::T_UNKNOWN;
+ len = 0;
+ pos = 0;
+ sync = 0;
+ skip = false;
+ data = NULL;
+ datasize = 0;
+ }
+ void init(ChanPacket &p)
+ {
+ if (data && (datasize < p.len || datasize > p.len + BSIZE * 4)) {
+ free();
+ data = NULL;
+ datasize = 0;
+ }
+ type = p.type;
+ len = p.len;
+ pos = p.pos;
+ sync = p.sync;
+ skip = p.skip;
+ if (!data) {
+ datasize = (len & ~(BSIZE - 1)) + BSIZE;
+ data = new char[datasize];
+ }
+ memcpy(data, p.data, len);
+ }
+ void init(ChanPacketv &p)
+ {
+ ChanPacket tp;
+ tp.init(p);
+ init(tp);
+ }
+
+ void writeRaw(Stream &);
+ void writePeercast(Stream &);
+ void readPeercast(Stream &);
+
+ unsigned int sync;
+ unsigned int pos;
+ ChanPacket::TYPE type;
+ unsigned int len;
+ char *data;
+ unsigned int datasize;
+ bool skip;
+
+};
+// ----------------------------------
+class ChanPacketBuffer
+{
+public:
+ enum {
+ MAX_PACKETS = 64,
+ NUM_SAFEPACKETS = 60
+ };
+
+ void init()
+ {
+ lock.on();
+ lastPos = firstPos = safePos = 0;
+ readPos = writePos = 0;
+ accept = 0;
+ lastWriteTime = 0;
+ for (int i = 0; i < MAX_PACKETS; i++) packets[i].reset();
+ lock.off();
+
+ lastSkipTime = 0;
+ }
+
+ int copyFrom(ChanPacketBuffer &,unsigned in);
+
+ bool writePacket(ChanPacket &,bool = false);
+ void readPacket(ChanPacket &);
+
+ bool willSkip();
+
+ int numPending() {return writePos-readPos;}
+
+ unsigned int getLatestPos();
+ unsigned int getOldestPos();
+ unsigned int findOldestPos(unsigned int);
+ bool findPacket(unsigned int,ChanPacket &);
+ unsigned int getStreamPos(unsigned int);
+ unsigned int getStreamPosEnd(unsigned int);
+ unsigned int getLastSync();
+
+ //ChanPacket packets[MAX_PACKETS];
+ ChanPacketv packets[MAX_PACKETS];
+ volatile unsigned int lastPos,firstPos,safePos;
+ volatile unsigned int readPos,writePos;
+ unsigned int accept;
+ unsigned int lastWriteTime;
+ WLock lock;
+
+ unsigned int lastSkipTime;
+};
+
+// ----------------------------------
+class ChannelStream
+{
+public:
+ ChannelStream()
+ :numListeners(0)
+ ,numRelays(0)
+ ,isPlaying(false)
+ ,fwState(0)
+ ,lastUpdate(0)
+ ,lastCheckTime(0)
+ ,parent(NULL)
+ {}
+ virtual ~ChannelStream() {}
+
+ void updateStatus(Channel *);
+ bool getStatus(Channel *,ChanPacket &);
+
+ virtual void kill() {}
+ virtual bool sendPacket(ChanPacket &,GnuID &) {return false;}
+ virtual void flush(Stream &) {}
+ virtual void readHeader(Stream &,Channel *)=0;
+ virtual int readPacket(Stream &,Channel *)=0;
+ virtual void readEnd(Stream &,Channel *)=0;
+
+ void readRaw(Stream &,Channel *);
+
+ int numRelays;
+ int numListeners;
+ bool isPlaying;
+ int fwState;
+ unsigned int lastUpdate;
+ unsigned int lastCheckTime;
+
+ Channel *parent;
+};
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : gnutella.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// GnuPacket is a Gnutella protocol packet.
+// GnuStream is a Stream that reads/writes GnuPackets
+//
+//
+// (c) 2002 peercast.org
+//
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "gnutella.h"
+#include "stream.h"
+#include "common.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "stats.h"
+#include <stdlib.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------
+const char *GNU_FUNC_STR(int func)
+{
+ switch (func)
+ {
+ case GNU_FUNC_PING: return "PING"; break;
+ case GNU_FUNC_PONG: return "PONG"; break;
+ case GNU_FUNC_QUERY: return "QUERY"; break;
+ case GNU_FUNC_HIT: return "HIT"; break;
+ case GNU_FUNC_PUSH: return "PUSH"; break;
+ default: return "UNKNOWN"; break;
+ }
+}
+
+// ---------------------------
+const char *GnuStream::getRouteStr(R_TYPE r)
+{
+ switch(r)
+ {
+ case R_PROCESS: return "PROCESS"; break;
+ case R_DEAD: return "DEAD"; break;
+ case R_DISCARD: return "DISCARD"; break;
+ case R_ACCEPTED: return "ACCEPTED"; break;
+ case R_BROADCAST: return "BROADCAST"; break;
+ case R_ROUTE: return "ROUTE"; break;
+ case R_DUPLICATE: return "DUPLICATE"; break;
+ case R_BADVERSION: return "BADVERSION"; break;
+ case R_DROP: return "DROP"; break;
+ default: return "UNKNOWN"; break;
+ }
+}
+// ---------------------------
+void GnuPacket::makeChecksumID()
+{
+ for(unsigned int i=0; i<len; i++)
+ id.id[i%16] += data[i];
+}
+
+// ---------------------------
+void GnuPacket::initPing(int t)
+{
+ func = GNU_FUNC_PING;
+ ttl = t;
+ hops = 0;
+ len = 0;
+
+ id.generate();
+}
+// ---------------------------
+void GnuPacket::initPong(Host &h, bool ownPong, GnuPacket &ping)
+{
+ func = GNU_FUNC_PONG;
+ ttl = ping.hops;
+ hops = 0;
+ len = 14;
+ id = ping.id;
+
+ MemoryStream pk(data,len);
+
+ pk.writeShort(h.port); // port
+ pk.writeLong(SWAP4(h.ip)); // ip
+ if (ownPong)
+ {
+ pk.writeLong(chanMgr->numChannels()); // cnt
+ pk.writeLong(servMgr->totalOutput(false)); // total
+ }else{
+ pk.writeLong(0); // cnt
+ pk.writeLong(0); // total
+ }
+
+
+}
+// ---------------------------
+void GnuPacket::initPush(ChanHit &ch, Host &sh)
+{
+#if 0
+ func = GNU_FUNC_PUSH;
+ ttl = ch.numHops;
+ hops = 0;
+ len = 26;
+ id.generate();
+
+ MemoryStream data(data,len);
+
+ // ID of Hit packet
+ data.write(ch.packetID.id,16);
+
+ // index of channel
+ data.writeLong(ch.index);
+
+ data.writeLong(SWAP4(sh.ip)); // ip
+ data.writeShort(sh.port); // port
+#endif
+}
+
+
+// ---------------------------
+bool GnuPacket::initHit(Host &h, Channel *ch, GnuPacket *query, bool push, bool busy, bool stable, bool tracker, int maxttl)
+{
+ if (!ch)
+ return false;
+
+ func = GNU_FUNC_HIT;
+ hops = 0;
+ id.generate();
+
+ ttl = maxttl;
+
+
+ MemoryStream mem(data,MAX_DATA);
+
+ mem.writeChar(1); // num hits
+ mem.writeShort(h.port); // port
+ mem.writeLong(SWAP4(h.ip)); // ip
+
+ if (query)
+ mem.writeLong(0); // speed - route
+ else
+ mem.writeLong(1); // broadcast
+
+
+ //mem.writeLong(ch->index); // index
+ mem.writeLong(0); // index
+ mem.writeShort(ch->getBitrate()); // bitrate
+ mem.writeShort(ch->localListeners()); // num listeners
+
+ mem.writeChar(0); // no name
+
+ XML xml;
+ XML::Node *cn = ch->info.createChannelXML();
+ cn->add(ch->info.createTrackXML());
+ xml.setRoot(cn);
+ xml.writeCompact(mem);
+
+ mem.writeChar(0); // extra null
+
+
+ // QHD
+ mem.writeLong('PCST'); // vendor ID
+ mem.writeChar(2); // public sector length
+
+ int f1 = 0, f2 = 0;
+
+ f1 = 1 | 4 | 8 | 32 | 64; // use push | busy | stable | broadcast | tracker
+
+ if (push) f2 |= 1;
+ if (busy) f2 |= 4;
+ if (stable) f2 |= 8;
+ if (!query) f2 |= 32;
+ if (tracker) f2 |= 64;
+
+ mem.writeChar(f1);
+ mem.writeChar(f2);
+
+ {
+ // write private sector
+ char pbuf[256];
+ MemoryStream pmem(pbuf,sizeof(pbuf));
+ XML xml;
+ XML::Node *pn = servMgr->createServentXML();
+ xml.setRoot(pn);
+ xml.writeCompact(pmem);
+ pmem.writeChar(0); // add null terminator
+ if (pmem.pos <= 255)
+ {
+ mem.writeChar(pmem.pos);
+ mem.write(pmem.buf,pmem.pos);
+ }else
+ mem.writeChar(0);
+ }
+
+
+ // queryID/not used
+ if (query)
+ mem.write(query->id.id,16);
+ else
+ mem.write(id.id,16);
+
+ len = mem.pos;
+
+ LOG_NETWORK("Created Hit packet: %d bytes",len);
+
+ if (len >= MAX_DATA)
+ return false;
+
+// servMgr->addReplyID(id);
+ return true;
+}
+
+
+// ---------------------------
+void GnuPacket::initFind(const char *str, XML *xml, int maxTTL)
+{
+
+ func = GNU_FUNC_QUERY;
+ ttl = maxTTL;
+ hops = 0;
+ id.generate();
+
+ MemoryStream mem(data,MAX_DATA);
+
+ mem.writeShort(0); // min speed
+
+ if (str)
+ {
+ int slen = strlen(str);
+ mem.write((void *)str,slen+1); // string
+ }else
+ mem.writeChar(0); // null string
+
+
+ if (xml)
+ xml->writeCompact(mem);
+
+ len = mem.pos;
+}
+
+// ---------------------------
+void GnuStream::ping(int ttl)
+{
+ GnuPacket ping;
+ ping.initPing(ttl);
+// servMgr->addReplyID(ping.id);
+ sendPacket(ping);
+ LOG_NETWORK("ping out %02x%02x%02x%02x",ping.id.id[0],ping.id.id[1],ping.id.id[2],ping.id.id[3]);
+}
+
+// ---------------------------
+void GnuStream::sendPacket(GnuPacket &p)
+{
+ try
+ {
+ lock.on();
+ packetsOut++;
+ stats.add(Stats::NUMPACKETSOUT);
+
+ switch(p.func)
+ {
+ case GNU_FUNC_PING: stats.add(Stats::NUMPINGOUT); break;
+ case GNU_FUNC_PONG: stats.add(Stats::NUMPONGOUT); break;
+ case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYOUT); break;
+ case GNU_FUNC_HIT: stats.add(Stats::NUMHITOUT); break;
+ case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHOUT); break;
+ default: stats.add(Stats::NUMOTHEROUT); break;
+ }
+
+
+ write(p.id.id,16);
+ writeChar(p.func); // ping func
+ writeChar(p.ttl); // ttl
+ writeChar(p.hops); // hops
+ writeLong(p.len); // len
+
+ if (p.len)
+ write(p.data,p.len);
+
+ stats.add(Stats::PACKETDATAOUT,23+p.len);
+
+ lock.off();
+ }catch(StreamException &e)
+ {
+ lock.off();
+ throw e;
+ }
+}
+// ---------------------------
+bool GnuStream::readPacket(GnuPacket &p)
+{
+ try
+ {
+ lock.on();
+ packetsIn++;
+ stats.add(Stats::NUMPACKETSIN);
+
+ read(p.id.id,16);
+ p.func = readChar();
+ p.ttl = readChar();
+ p.hops = readChar();
+ p.len = readLong();
+
+
+ if ((p.hops >= 1) && (p.hops <= 10))
+ stats.add((Stats::STAT)((int)Stats::NUMHOPS1+p.hops-1));
+
+ stats.add(Stats::PACKETDATAIN,23+p.len);
+
+ switch(p.func)
+ {
+ case GNU_FUNC_PING: stats.add(Stats::NUMPINGIN); break;
+ case GNU_FUNC_PONG: stats.add(Stats::NUMPONGIN); break;
+ case GNU_FUNC_QUERY: stats.add(Stats::NUMQUERYIN); break;
+ case GNU_FUNC_HIT: stats.add(Stats::NUMHITIN); break;
+ case GNU_FUNC_PUSH: stats.add(Stats::NUMPUSHIN); break;
+ default: stats.add(Stats::NUMOTHERIN); break;
+ }
+
+
+ if (p.len)
+ {
+ if (p.len > GnuPacket::MAX_DATA)
+ {
+ while (p.len--)
+ readChar();
+ lock.off();
+ return false;
+ }
+ read(p.data,p.len);
+ }
+
+ lock.off();
+ return true;
+ }catch(StreamException &e)
+ {
+ lock.off();
+ throw e;
+ }
+}
+
+// ---------------------------
+GnuStream::R_TYPE GnuStream::processPacket(GnuPacket &in, Servent *serv, GnuID &routeID)
+{
+
+ R_TYPE ret = R_DISCARD;
+
+ MemoryStream data(in.data,in.len);
+
+ Host remoteHost = serv->getHost();
+
+ in.ttl--;
+ in.hops++;
+
+ routeID = in.id;
+
+
+
+ switch(in.func)
+ {
+ case GNU_FUNC_PING: // ping
+ {
+ LOG_NETWORK("ping: from %d.%d.%d.%d : %02x%02x%02x%02x",
+ remoteHost.ip>>24&0xff,remoteHost.ip>>16&0xff,remoteHost.ip>>8&0xff,remoteHost.ip&0xff,
+ in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]
+ );
+ Host sh = servMgr->serverHost;
+ if (sh.isValid())
+ {
+ if ((servMgr->getFirewall() != ServMgr::FW_ON) && (!servMgr->pubInFull()))
+ {
+ GnuPacket pong;
+ pong.initPong(sh,true,in);
+ if (serv->outputPacket(pong,true))
+ LOG_NETWORK("pong out");
+ }
+ ret = R_BROADCAST;
+ }
+ }
+ break;
+ case GNU_FUNC_PONG: // pong
+ {
+ {
+ int ip,port,cnt,total;
+ port = data.readShort();
+ ip = data.readLong();
+ cnt = data.readLong();
+ total = data.readLong();
+
+ ip = SWAP4(ip);
+
+
+ Host h;
+ h.ip = ip;
+ h.port = port;
+
+ char sIP[64],rIP[64];
+ h.toStr(sIP);
+ remoteHost.toStr(rIP);
+
+ LOG_NETWORK("pong: %s via %s : %02x%02x%02x%02x",sIP,ip,rIP,in.id.id[0],in.id.id[1],in.id.id[2],in.id.id[3]);
+
+
+ ret = R_DISCARD;
+
+ if (h.isValid())
+ {
+
+ #if 0
+ // accept if this pong is a reply from one of our own pings, otherwise route back
+ if (servMgr->isReplyID(in.id))
+ {
+ servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+ ret = R_ACCEPTED;
+ }else
+ ret = R_ROUTE;
+ #endif
+ }
+
+ }
+ }
+ break;
+ case GNU_FUNC_QUERY: // query
+ ret = R_BROADCAST;
+
+ {
+ Host sh = servMgr->serverHost;
+ if (!sh.isValid())
+ sh.ip = 127<<24|1;
+
+ char words[256];
+ short spd = data.readShort();
+ data.readString(words,sizeof(words));
+ words[sizeof(words)-1] = 0;
+
+ MemoryStream xm(&data.buf[data.pos],data.len-data.pos);
+ xm.buf[xm.len] = 0;
+
+ Channel *hits[16];
+ int numHits=0;
+
+ if (strncmp(xm.buf,"<?xml",5)==0)
+ {
+ XML xml;
+ xml.read(xm);
+ XML::Node *cn = xml.findNode("channel");
+ if (cn)
+ {
+ ChanInfo info;
+ info.init(cn);
+ info.status = ChanInfo::S_PLAY;
+ numHits = chanMgr->findChannels(info,hits,16);
+ }
+ LOG_NETWORK("query XML: %s : found %d",xm.buf,numHits);
+ }else{
+ ChanInfo info;
+ info.name.set(words);
+ info.genre.set(words);
+ info.id.fromStr(words);
+ info.status = ChanInfo::S_PLAY;
+ numHits = chanMgr->findChannels(info,hits,16);
+ LOG_NETWORK("query STR: %s : found %d",words,numHits);
+ }
+
+
+
+ for(int i=0; i<numHits; i++)
+ {
+ bool push = (servMgr->getFirewall()!=ServMgr::FW_OFF);
+ bool busy = (servMgr->pubInFull() && servMgr->outFull()) || servMgr->relaysFull();
+ bool stable = servMgr->totalStreams>0;
+ bool tracker = hits[i]->isBroadcasting();
+
+ GnuPacket hit;
+ if (hit.initHit(sh,hits[i],&in,push,busy,stable,tracker,in.hops))
+ serv->outputPacket(hit,true);
+ }
+ }
+ break;
+ case GNU_FUNC_PUSH: // push
+ {
+
+ GnuID pid;
+ data.read(pid.id,16);
+
+ //LOG("push serv= %02x%02x%02x%02x",servMgr->id[0],servMgr->id[1],servMgr->id[2],servMgr->id[3]);
+ //LOG("pack = %02x%02x%02x%02x",id[0],id[1],id[2],id[3]);
+
+
+ int index = data.readLong();
+ int ip = data.readLong();
+ int port = data.readShort();
+
+
+ ip = SWAP4(ip);
+
+ Host h(ip,port);
+ char hostName[64];
+ h.toStr(hostName);
+
+#if 0
+ if (servMgr->isReplyID(pid))
+ {
+#if 0
+ Channel *c = chanMgr->findChannelByIndex(index);
+
+ if (!c)
+ {
+ LOG_NETWORK("push 0x%x to %s: Not found",index,hostName);
+ }else
+ {
+ if (!c->isFull() && !servMgr->streamFull())
+ {
+ LOG_NETWORK("push: 0x%x to %s: OK",index,hostName);
+
+ Servent *s = servMgr->allocServent();
+ if (s)
+ s->initGIV(h,c->info.id);
+ }else
+ LOG_NETWORK("push: 0x%x to %s: FULL",index,hostName);
+ }
+#endif
+ ret = R_ACCEPTED;
+ }else{
+ LOG_NETWORK("push: 0x%x to %s: ROUTE",index,hostName);
+ routeID = pid;
+ ret = R_ROUTE;
+ }
+#endif
+ }
+ break;
+ case GNU_FUNC_HIT: // hit
+ {
+ ret = R_DISCARD;
+
+ ChanHit hit;
+ if (readHit(data,hit,in.hops,in.id))
+ {
+
+ char flstr[64];
+ flstr[0]=0;
+ if (hit.firewalled) strcat(flstr,"Push,");
+ if (hit.tracker) strcat(flstr,"Tracker,");
+
+#if 0
+ if ((spd == 0) && (!isBroadcastHit))
+ {
+ if (servMgr->isReplyID(queryID))
+ {
+ ret = R_ACCEPTED;
+ LOG_NETWORK("self-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }else
+ {
+ routeID = queryID;
+ ret = R_ROUTE;
+ LOG_NETWORK("route-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }
+ }else
+ {
+ ret = R_BROADCAST;
+ LOG_NETWORK("broadcast-hit: %s 0x%02x %s %d chan",hostName,f2,flstr,num);
+ }
+#else
+ ret = R_BROADCAST;
+ LOG_NETWORK("broadcast-hit: %s",flstr);
+#endif
+ }
+ }
+ break;
+ default:
+ LOG_NETWORK("packet: %d",in.func);
+ break;
+ }
+
+
+ if ((in.ttl > 10) || (in.hops > 10) || (in.ttl==0))
+ if ((ret == R_BROADCAST) || (ret == R_ROUTE))
+ ret = R_DEAD;
+
+ return ret;
+}
+
+// ---------------------------
+bool GnuStream::readHit(Stream &data, ChanHit &ch,int hops,GnuID &id)
+{
+ int i;
+ int num = data.readChar(); // hits
+ int port = data.readShort(); // port
+ int ip = data.readLong(); // ip
+ ip = SWAP4(ip);
+ int spd = data.readLong(); // speed/broadcast
+
+ Host h(ip,port);
+ char hostName[64];
+
+ h.IPtoStr(hostName);
+
+ bool dataValid=true;
+
+ ChanHit *hits[100];
+ int numHits=0;
+
+ for(i=0; i<num; i++)
+ {
+ int index,bitrate,listeners;
+
+
+ index = data.readLong(); // index
+ bitrate = data.readShort(); // bitrate
+ listeners = data.readShort(); // listeners
+
+ // read name .. not used.
+ char fname[256];
+ data.readString(fname,sizeof(fname));
+ fname[sizeof(fname)-1] = 0;
+
+ ch.init();
+ ch.firewalled = false; // default to NO as we dont get the info until the next section.
+ ch.host = h;
+ ch.numListeners = listeners;
+ ch.numHops = hops;
+ ch.rhost[0] = ch.host;
+
+ ChanInfo info;
+
+
+ {
+ char xmlData[4000];
+ int xlen = data.readString(xmlData,sizeof(xmlData));
+
+ if ((strncmp(xmlData,"<?xml",5)==0) && (xlen < GnuPacket::MAX_DATA))
+ {
+ //LOG_NETWORK("Hit XML: %s",xmlData);
+
+ MemoryStream xm(xmlData,xlen);
+ XML xml;
+ xml.read(xm);
+ XML::Node *n = xml.findNode("channel");
+ if (n)
+ {
+ info.init(n);
+ char idStr[64];
+ info.id.toStr(idStr);
+ LOG_NETWORK("got hit %s %s",idStr,info.name.cstr());
+
+ ch.upTime = n->findAttrInt("uptime");
+
+ }else
+ LOG_NETWORK("Missing Channel node");
+ }else
+ {
+ LOG_NETWORK("Missing XML data");
+ //LOG_NETWORK("%s",xmlData);
+ dataValid = false;
+ }
+ }
+
+ if (info.id.isSet())
+ {
+ if (!chanMgr->findHitList(info))
+ chanMgr->addHitList(info);
+
+ ch.recv = true;
+ ch.chanID = info.id;
+ ChanHit *chp = chanMgr->addHit(ch);
+
+ if ((chp) && (numHits<100))
+ hits[numHits++] = chp;
+ }
+
+ }
+
+
+ int vendor = data.readLong(); // vendor ID
+
+ int pubLen = data.readChar(); // public sec length - should be 2
+
+ int f1 = data.readChar() & 0xff; // flags 1
+ int f2 = data.readChar() & 0xff; // flags 2
+
+ pubLen -= 2;
+ while (pubLen-->0)
+ data.readChar();
+
+
+ char agentStr[16];
+ agentStr[0]=0;
+ int maxPreviewTime=0;
+
+ // read private sector with peercast servant specific info
+ int privLen = data.readChar();
+
+ if (privLen)
+ {
+ char privData[256];
+ data.read(privData,privLen);
+ if (strncmp(privData,"<?xml",5)==0)
+ {
+ MemoryStream xm(privData,privLen);
+ XML xml;
+ xml.read(xm);
+ XML::Node *sn = xml.findNode("servent");
+ if (sn)
+ {
+ char *ag = sn->findAttr("agent");
+ if (ag)
+ {
+ strncpy(agentStr,ag,16);
+ agentStr[15]=0;
+ }
+ maxPreviewTime = sn->findAttrInt("preview");
+ }
+
+ }
+ }
+
+
+ // not used anymore
+ GnuID queryID;
+ data.read(queryID.id,16);
+
+ bool isBroadcastHit=false;
+ if (f1 & 32)
+ isBroadcastHit = (f2 & 32)!=0;
+
+ for(i=0; i<numHits; i++)
+ {
+ if (f1 & 1)
+ hits[i]->firewalled = (f2 & 1)!=0;
+
+ if (f1 & 64)
+ hits[i]->tracker = (f2 & 64)!=0;
+
+ }
+
+ return dataValid;
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : gnutella.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GNUTELLA_H
+#define _GNUTELLA_H
+
+// --------------------------------
+#include "stream.h"
+#include "sys.h"
+
+
+
+#define GNUTELLA_SETUP 0
+
+
+// --------------------------------
+static const int GNU_FUNC_PING = 0;
+static const int GNU_FUNC_PONG = 1;
+static const int GNU_FUNC_QUERY = 128;
+static const int GNU_FUNC_HIT = 129;
+static const int GNU_FUNC_PUSH = 64;
+
+extern const char *GNU_FUNC_STR(int);
+
+// --------------------------------
+static const char *GNU_PEERCONN = "PEERCAST CONNECT/0.1";
+static const char *GNU_CONNECT = "GNUTELLA CONNECT/0.6";
+static const char *GNU_OK = "GNUTELLA/0.6 200 OK";
+static const char *PCX_PCP_CONNECT = "pcp";
+
+static const char *PCX_HS_OS = "x-peercast-os:";
+static const char *PCX_HS_DL = "x-peercast-download:";
+static const char *PCX_HS_ID = "x-peercast-id:";
+static const char *PCX_HS_CHANNELID = "x-peercast-channelid:";
+static const char *PCX_HS_NETWORKID = "x-peercast-networkid:";
+static const char *PCX_HS_MSG = "x-peercast-msg:";
+static const char *PCX_HS_SUBNET = "x-peercast-subnet:";
+static const char *PCX_HS_FULLHIT = "x-peercast-fullhit:";
+static const char *PCX_HS_MINBCTTL = "x-peercast-minbcttl:";
+static const char *PCX_HS_MAXBCTTL = "x-peercast-maxbcttl:";
+static const char *PCX_HS_RELAYBC = "x-peercast-relaybc:";
+static const char *PCX_HS_PRIORITY = "x-peercast-priority:";
+static const char *PCX_HS_FLOWCTL = "x-peercast-flowctl:";
+static const char *PCX_HS_PCP = "x-peercast-pcp:";
+static const char *PCX_HS_PINGME = "x-peercast-pingme:";
+static const char *PCX_HS_PORT = "x-peercast-port:";
+static const char *PCX_HS_REMOTEIP = "x-peercast-remoteip:";
+static const char *PCX_HS_POS = "x-peercast-pos:";
+static const char *PCX_HS_SESSIONID = "x-peercast-sessionid:";
+
+// official version number sent to relay to check for updates
+static const char *PCX_OS_WIN32 = "Win32";
+static const char *PCX_OS_LINUX = "Linux";
+static const char *PCX_OS_MACOSX = "Apple-OSX";
+static const char *PCX_OS_WINAMP2 = "Win32-WinAmp2";
+static const char *PCX_OS_ACTIVEX = "Win32-ActiveX";
+
+static const char *PCX_DL_URL = "http://www.peercast.org/download.php";
+
+// version number sent to other clients
+static const char *PCX_OLDAGENT = "PeerCast/0.119E";
+
+
+
+
+
+// version number used inside packets GUIDs
+static const int PEERCAST_PACKETID = 0x0000119E;
+
+static const char *MIN_ROOTVER = "0.119E";
+
+static const char *MIN_CONNECTVER = "0.119D";
+static const int MIN_PACKETVER = 0x0000119D;
+
+static const char *ICY_OK = "ICY 200 OK";
+
+// --------------------------------
+
+static const int DEFAULT_PORT = 7144;
+
+// --------------------------------
+
+class Servent;
+class Channel;
+class ChanHit;
+
+
+// --------------------------------
+class GnuPacket
+{
+public:
+
+
+ // --------------------------------
+ class Hash
+ {
+ public:
+
+ bool isSame(Hash &h)
+ {
+ return (idChecksum == h.idChecksum) && (dataChecksum == h.dataChecksum);
+ }
+
+ bool isSameID(Hash &h)
+ {
+ return (idChecksum == h.idChecksum);
+ }
+
+ unsigned int idChecksum;
+ unsigned int dataChecksum;
+
+ };
+ // --------------------------------
+
+ enum {
+ MAX_DATA = 2000
+ };
+
+ void initPing(int);
+ void initPong(Host &, bool, GnuPacket &);
+ void initFind(const char *, class XML *,int);
+ bool initHit(Host &, Channel *, GnuPacket *,bool,bool,bool,bool,int);
+ void initPush(ChanHit &, Host &);
+
+
+ void makeChecksumID();
+
+ unsigned char func;
+ unsigned char ttl;
+ unsigned char hops;
+ unsigned int len;
+ Hash hash;
+ GnuID id;
+
+ char data[MAX_DATA];
+};
+// --------------------------------
+class GnuPacketBuffer
+{
+public:
+ GnuPacketBuffer(int s)
+ :size(s)
+ ,packets(new GnuPacket[size])
+ {
+ reset();
+ }
+ ~GnuPacketBuffer()
+ {
+ delete [] packets;
+ }
+
+ void reset()
+ {
+ readPtr = writePtr = 0;
+ }
+
+ GnuPacket *curr()
+ {
+ if (numPending())
+ return &packets[readPtr%size];
+ else
+ return NULL;
+
+ }
+ void next()
+ {
+ readPtr++;
+ }
+
+ int findMinHop()
+ {
+ int min=100;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ {
+ int idx = (readPtr+i)%size;
+ if (packets[idx].hops < min)
+ min = packets[idx].hops;
+ }
+ return min;
+ }
+ int findMaxHop()
+ {
+ int max=0;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ {
+ int idx = (readPtr+i)%size;
+ if (packets[idx].hops > max)
+ max = packets[idx].hops;
+ }
+ return max;
+ }
+
+ int percentFull()
+ {
+ return (numPending()*100) / size;
+ }
+
+
+ int sizeOfPending()
+ {
+ int tot=0;
+ int n = numPending();
+ for(int i=0; i<n; i++)
+ tot+=packets[(readPtr+i)%size].len;
+ return tot;
+ }
+
+ int numPending()
+ {
+ return writePtr-readPtr;
+ }
+
+ bool write(GnuPacket &p)
+ {
+ if ((writePtr-readPtr) >= size)
+ return false;
+ else
+ {
+ packets[writePtr%size] = p;
+ writePtr++;
+ return true;
+ }
+ }
+
+ int size;
+ GnuPacket *packets;
+ int readPtr,writePtr;
+};
+
+
+
+// --------------------------------
+class GnuStream : public IndirectStream
+{
+public:
+
+ enum R_TYPE
+ {
+ R_PROCESS,
+ R_DEAD,
+ R_DISCARD,
+ R_ACCEPTED,
+ R_BROADCAST,
+ R_ROUTE,
+ R_DUPLICATE,
+ R_BADVERSION,
+ R_DROP
+ };
+
+ GnuStream()
+ {
+ init(NULL);
+ }
+
+ void init(Stream *s)
+ {
+ IndirectStream::init(s);
+ packetsIn = packetsOut = 0;
+ }
+
+ bool readPacket(GnuPacket &);
+ void sendPacket(GnuPacket &);
+ R_TYPE processPacket(GnuPacket &, Servent *, GnuID &);
+
+ static const char *getRouteStr(R_TYPE);
+ bool readHit(Stream &data, ChanHit &ch,int,GnuID &);
+
+
+
+ void ping(int);
+
+ int packetsIn,packetsOut;
+ WLock lock;
+};
+
+
+#endif
--- /dev/null
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+
+// ---------------------------------------
+class HTML : public XML
+{
+public:
+ HTML(const char *);
+
+
+ void startNode(XML::Node *, const char * = NULL);
+ void addLink(const char *, const char *);
+ void addArgLink(const char *, const char *);
+ XML::Node *startTag(const char *, const char * = NULL,...);
+ XML::Node *startTagEnd(const char *, const char * = NULL,...);
+ void startSingleTagEnd(const char *,...);
+ void startTableRow(int);
+ void end();
+ void addRefresh(int);
+
+ char defArgs[128];
+ XML::Node *currNode,*headNode,*htmlNode;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : html.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// HTML protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include "html.h"
+#include "http.h"
+#include "stream.h"
+#include "gnutella.h"
+#include "servmgr.h"
+#include "channel.h"
+#include "stats.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------
+HTML::HTML(const char *t, Stream &o)
+{
+ o.writeCRLF = false;
+ out = new WriteBufferStream(8192, &o);
+ out->writeCRLF = false;
+
+ title.set(t);
+ tagLevel = 0;
+ refresh = 0;
+}
+
+HTML::~HTML()
+{
+ try {
+ out->flush();
+ } catch (StreamException &) {}
+ delete out;
+}
+
+// --------------------------------------
+void HTML::writeOK(const char *content)
+{
+ out->writeLine(HTTP_SC_OK);
+ out->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ //out->writeLine("%s %s",HTTP_HS_CACHE,"no-cache");
+ out->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ out->writeLineF("%s %s",HTTP_HS_CONTENT,content);
+ out->writeLine("");
+}
+// --------------------------------------
+void HTML::writeVariable(Stream &s,const String &varName, int loop)
+{
+ bool r=false;
+ if (varName.startsWith("servMgr."))
+ r=servMgr->writeVariable(s,varName+8);
+ else if (varName.startsWith("chanMgr."))
+ r=chanMgr->writeVariable(s,varName+8,loop);
+ else if (varName.startsWith("stats."))
+ r=stats.writeVariable(s,varName+6);
+ else if (varName.startsWith("sys."))
+ {
+ if (varName == "sys.log.dumpHTML")
+ {
+ sys->logBuf->dumpHTML(s);
+ r=true;
+ }
+ }
+ else if (varName.startsWith("loop."))
+ {
+ if (varName.startsWith("loop.channel."))
+ {
+ Channel *ch = chanMgr->findChannelByIndex(loop);
+ if (ch)
+ r = ch->writeVariable(s,varName+13,loop);
+ }else if (varName.startsWith("loop.servent."))
+ {
+ Servent *sv = servMgr->findServentByIndex(loop);
+ if (sv)
+ r = sv->writeVariable(s,varName+13);
+ }else if (varName.startsWith("loop.filter."))
+ {
+ ServFilter *sf = &servMgr->filters[loop];
+ r = sf->writeVariable(s,varName+12);
+
+ }else if (varName.startsWith("loop.bcid."))
+ {
+ BCID *bcid = servMgr->findValidBCID(loop);
+ if (bcid)
+ r = bcid->writeVariable(s,varName+10);
+
+ }else if (varName == "loop.indexEven")
+ {
+ s.writeStringF("%d",(loop&1)==0);
+ r = true;
+ }else if (varName == "loop.index")
+ {
+ s.writeStringF("%d",loop);
+ r = true;
+ }else if (varName.startsWith("loop.hit."))
+ {
+ char *idstr = getCGIarg(tmplArgs,"id=");
+ if (idstr)
+ {
+ GnuID id;
+ id.fromStr(idstr);
+ ChanHitList *chl = chanMgr->findHitListByID(id);
+ if (chl)
+ {
+ int cnt=0;
+ ChanHit *ch = chl->hit;
+ while (ch)
+ {
+ if (ch->host.ip && !ch->dead)
+ {
+ if (cnt == loop)
+ {
+ r = ch->writeVariable(s,varName+9);
+ break;
+ }
+ cnt++;
+ }
+ ch=ch->next;
+ }
+
+ }
+ }
+ }
+
+ }
+ else if (varName.startsWith("page."))
+ {
+ if (varName.startsWith("page.channel."))
+ {
+ char *idstr = getCGIarg(tmplArgs,"id=");
+ if (idstr)
+ {
+ GnuID id;
+ id.fromStr(idstr);
+ Channel *ch = chanMgr->findChannelByID(id);
+ if (ch)
+ r = ch->writeVariable(s,varName+13,loop);
+ }
+ }else
+ {
+
+ String v = varName+5;
+ v.append('=');
+ char *a = getCGIarg(tmplArgs,v);
+ if (a)
+ {
+ s.writeString(a);
+ r=true;
+ }
+ }
+ }
+
+
+ if (!r)
+ s.writeString(varName);
+}
+// --------------------------------------
+int HTML::getIntVariable(const String &varName,int loop)
+{
+ String val;
+ MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+ writeVariable(mem,varName,loop);
+
+ return atoi(val.cstr());
+}
+// --------------------------------------
+bool HTML::getBoolVariable(const String &varName,int loop)
+{
+ String val;
+ MemoryStream mem(val.cstr(),String::MAX_LEN);
+
+ writeVariable(mem,varName,loop);
+
+ // integer
+ if ((val[0] >= '0') && (val[0] <= '9'))
+ return atoi(val.cstr()) != 0;
+
+ // string
+ if (val[0]!=0)
+ return true;
+
+ return false;
+}
+
+// --------------------------------------
+void HTML::readIf(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ bool varCond=true;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '}')
+ {
+ if (getBoolVariable(var,loop)==varCond)
+ {
+ if (readTemplate(in,outp,loop))
+ readTemplate(in,NULL,loop);
+ }else{
+ if (readTemplate(in,NULL,loop))
+ readTemplate(in,outp,loop);
+ }
+ return;
+ }else if (c == '!')
+ {
+ varCond = !varCond;
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+
+// --------------------------------------
+void HTML::readLoop(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '}')
+ {
+ int cnt = getIntVariable(var,loop);
+
+ if (cnt)
+ {
+ int spos = in.getPosition();
+ for(int i=0; i<cnt; i++)
+ {
+ in.seekTo(spos);
+ readTemplate(in,outp,i);
+ }
+ }else
+ {
+ readTemplate(in,NULL,0);
+ }
+ return;
+
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+
+// --------------------------------------
+int HTML::readCmd(Stream &in,Stream *outp,int loop)
+{
+ String cmd;
+
+ int tmpl = TMPL_UNKNOWN;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (String::isWhitespace(c) || (c=='}'))
+ {
+ if (cmd == "loop")
+ {
+ readLoop(in,outp,loop);
+ tmpl = TMPL_LOOP;
+ }else if (cmd == "if")
+ {
+ readIf(in,outp,loop);
+ tmpl = TMPL_IF;
+ }else if (cmd == "end")
+ {
+ tmpl = TMPL_END;
+ }
+ else if (cmd == "else")
+ {
+ tmpl = TMPL_ELSE;
+ }
+ break;
+ }else
+ {
+ cmd.append(c);
+ }
+ }
+ return tmpl;
+}
+
+// --------------------------------------
+void HTML::readVariable(Stream &in,Stream *outp,int loop)
+{
+ String var;
+ while (!in.eof())
+ {
+ char c = in.readChar();
+ if (c == '}')
+ {
+ if (outp)
+ writeVariable(*outp,var,loop);
+ return;
+ }else
+ {
+ var.append(c);
+ }
+ }
+
+}
+// --------------------------------------
+bool HTML::readTemplate(Stream &in,Stream *outp,int loop)
+{
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '{')
+ {
+ c = in.readChar();
+ if (c == '$')
+ {
+ readVariable(in,outp,loop);
+ }
+ else if (c == '@')
+ {
+ int t = readCmd(in,outp,loop);
+ if (t == TMPL_END)
+ return false;
+ else if (t == TMPL_ELSE)
+ return true;
+ }
+ else if (c == '{')
+ {
+ if (outp)
+ outp->writeChar(c);
+ }
+ else
+ throw StreamException("Unknown template escape");
+ }else
+ {
+ if (outp)
+ outp->writeChar(c);
+ }
+ }
+ return false;
+}
+
+// --------------------------------------
+void HTML::writeTemplate(const char *fileName, const char *args)
+{
+ FileStream file;
+ MemoryStream mm;
+ try
+ {
+ file.openReadOnly(fileName);
+ mm.readFromFile(file);
+
+ tmplArgs = args;
+ readTemplate(mm,out,0);
+
+ }catch(StreamException &e)
+ {
+ out->writeString(e.msg);
+ out->writeString(" : ");
+ out->writeString(fileName);
+ }
+
+ mm.free2();
+ file.close();
+}
+// --------------------------------------
+void HTML::writeRawFile(const char *fileName)
+{
+ FileStream file;
+ try
+ {
+ file.openReadOnly(fileName);
+
+ file.writeTo(*out,file.length());
+
+ }catch(StreamException &)
+ {
+ }
+
+ file.close();
+}
+
+// --------------------------------------
+void HTML::locateTo(const char *url)
+{
+ out->writeLine(HTTP_SC_FOUND);
+ out->writeLineF("Location: %s",url);
+ out->writeLine("");
+}
+// --------------------------------------
+void HTML::startHTML()
+{
+ startNode("html");
+}
+// --------------------------------------
+void HTML::startBody()
+{
+ startNode("body");
+}
+// --------------------------------------
+void HTML::addHead()
+{
+ char buf[512];
+ startNode("head");
+ startTagEnd("title",title.cstr());
+ startTagEnd("meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"");
+
+ if (!refreshURL.isEmpty())
+ {
+ sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d;URL=%s\"",refresh,refreshURL.cstr());
+ startTagEnd(buf);
+ }else if (refresh)
+ {
+ sprintf(buf,"meta http-equiv=\"refresh\" content=\"%d\"",refresh);
+ startTagEnd(buf);
+ }
+
+
+ end();
+}
+// --------------------------------------
+void HTML::addContent(const char *s)
+{
+ out->writeString(s);
+}
+// --------------------------------------
+void HTML::startNode(const char *tag, const char *data)
+{
+ const char *p = tag;
+ char *o = &currTag[tagLevel][0];
+
+ int i;
+ for(i=0; i<MAX_TAGLEN-1; i++)
+ {
+ char c = *p++;
+ if ((c==0) || (c==' '))
+ break;
+ else
+ *o++ = c;
+ }
+ *o = 0;
+
+ out->writeString("<");
+ out->writeString(tag);
+ out->writeString(">");
+ if (data)
+ out->writeString(data);
+
+ tagLevel++;
+ if (tagLevel >= MAX_TAGLEVEL)
+ throw StreamException("HTML too deep!");
+}
+// --------------------------------------
+void HTML::end()
+{
+ tagLevel--;
+ if (tagLevel < 0)
+ throw StreamException("HTML premature end!");
+
+ out->writeString("</");
+ out->writeString(&currTag[tagLevel][0]);
+ out->writeString(">");
+}
+// --------------------------------------
+void HTML::addLink(const char *url, const char *text, bool toblank)
+{
+ char buf[1024];
+
+ sprintf(buf,"a href=\"%s\" %s",url,toblank?"target=\"_blank\"":"");
+ startNode(buf,text);
+ end();
+}
+// --------------------------------------
+void HTML::startTag(const char *tag, const char *fmt,...)
+{
+ if (fmt)
+ {
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tag,tmp);
+
+ va_end(ap);
+ }else{
+ startNode(tag,NULL);
+ }
+}
+// --------------------------------------
+void HTML::startTagEnd(const char *tag, const char *fmt,...)
+{
+ if (fmt)
+ {
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tag,tmp);
+
+ va_end(ap);
+ }else{
+ startNode(tag,NULL);
+ }
+ end();
+}
+// --------------------------------------
+void HTML::startSingleTagEnd(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[512];
+ vsprintf(tmp,fmt,ap);
+ startNode(tmp);
+
+ va_end(ap);
+ end();
+}
+
+// --------------------------------------
+void HTML::startTableRow(int i)
+{
+ if (i & 1)
+ startTag("tr bgcolor=\"#dddddd\" align=\"left\"");
+ else
+ startTag("tr bgcolor=\"#eeeeee\" align=\"left\"");
+}
--- /dev/null
+// ------------------------------------------------
+// File : html.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTML_H
+#define _HTML_H
+
+// ---------------------------------------
+#include "xml.h"
+#include "sys.h"
+
+class FileStream;
+class WriteBufferStream;
+
+// ---------------------------------------
+class HTML
+{
+public:
+ enum
+ {
+ MAX_TAGLEVEL = 64,
+ MAX_TAGLEN = 64
+ };
+
+ enum
+ {
+ TMPL_UNKNOWN,
+ TMPL_LOOP,
+ TMPL_IF,
+ TMPL_ELSE,
+ TMPL_END
+ };
+
+ HTML(const char *,Stream &);
+ ~HTML();
+
+ void startNode(const char *, const char * = NULL);
+ void addLink(const char *, const char *, bool = false);
+ void startTag(const char *, const char * = NULL,...);
+ void startTagEnd(const char *, const char * = NULL,...);
+ void startSingleTagEnd(const char *,...);
+ void startTableRow(int);
+ void end();
+ void setRefresh(int sec) {refresh = sec;}
+ void setRefreshURL(const char *u){refreshURL.set(u);}
+ void addHead();
+ void startHTML();
+ void startBody();
+
+ void locateTo(const char *);
+ void addContent(const char *);
+
+ void writeOK(const char *);
+ void writeTemplate(const char *, const char *);
+ void writeRawFile(const char *);
+ void writeVariable(Stream &,const String &,int);
+ int getIntVariable(const String &,int);
+ bool getBoolVariable(const String &,int);
+
+
+ void readIf(Stream &,Stream *,int);
+ void readLoop(Stream &,Stream *,int);
+ void readVariable(Stream &,Stream *,int);
+ bool readTemplate(Stream &,Stream *,int);
+ int readCmd(Stream &,Stream *,int);
+
+
+ const char *tmplArgs;
+ String title,refreshURL;
+ char currTag[MAX_TAGLEVEL][MAX_TAGLEN];
+ int tagLevel;
+ int refresh;
+ WriteBufferStream *out;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : http.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// HTTP protocol handling
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "http.h"
+#include "sys.h"
+#include "common.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+//-----------------------------------------
+bool HTTP::checkResponse(int r)
+{
+ if (readResponse()!=r)
+ {
+ LOG_ERROR("Unexpected HTTP: %s",cmdLine);
+ throw StreamException("Unexpected HTTP response");
+ return false;
+ }
+
+ return true;
+}
+//-----------------------------------------
+void HTTP::readRequest()
+{
+ readLine(cmdLine,sizeof(cmdLine));
+}
+//-----------------------------------------
+int HTTP::readResponse()
+{
+ readLine(cmdLine,sizeof(cmdLine));
+
+ char *cp = cmdLine;
+
+ while (*cp) if (*++cp == ' ') break;
+ while (*cp) if (*++cp != ' ') break;
+
+ char *scp = cp;
+
+ while (*cp) if (*++cp == ' ') break;
+ *cp = 0;
+
+ return atoi(scp);
+}
+
+//-----------------------------------------
+bool HTTP::nextHeader()
+{
+ if (readLine(cmdLine,sizeof(cmdLine)))
+ {
+ char *ap = strstr(cmdLine,":");
+ if (ap)
+ while (*++ap)
+ if (*ap!=' ')
+ break;
+ arg = ap;
+ return true;
+ }else
+ {
+ arg = NULL;
+ return false;
+ }
+
+}
+//-----------------------------------------
+bool HTTP::isHeader(const char *hs)
+{
+ return stristr(cmdLine,hs) != NULL;
+}
+//-----------------------------------------
+bool HTTP::isRequest(const char *rq)
+{
+ return strncmp(cmdLine,rq,strlen(rq)) == 0;
+}
+//-----------------------------------------
+char *HTTP::getArgStr()
+{
+ return arg;
+}
+//-----------------------------------------
+int HTTP::getArgInt()
+{
+ if (arg)
+ return atoi(arg);
+ else
+ return 0;
+}
+//-----------------------------------------
+void HTTP::getAuthUserPass(char *user, char *pass)
+{
+ if (arg)
+ {
+ char *s = stristr(arg,"Basic");
+ if (s)
+ {
+ while (*s)
+ if (*s++ == ' ')
+ break;
+ String str;
+ str.set(s,String::T_BASE64);
+ str.convertTo(String::T_ASCII);
+ s = strstr(str.cstr(),":");
+ if (s)
+ {
+ *s = 0;
+ if (user)
+ strcpy(user,str.cstr());
+ if (pass)
+ strcpy(pass,s+1);
+ }
+ }
+ }
+}
+// -----------------------------------
+void CookieList::init()
+{
+ for(int i=0; i<MAX_COOKIES; i++)
+ list[i].clear();
+
+ neverExpire = false;
+}
+
+// -----------------------------------
+bool CookieList::contains(Cookie &c)
+{
+ if ((c.id[0]) && (c.ip))
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].compare(c))
+ return true;
+
+ return false;
+}
+// -----------------------------------
+void Cookie::logDebug(const char *str, int ind)
+{
+ char ipstr[64];
+ Host h;
+ h.ip = ip;
+ h.IPtoStr(ipstr);
+
+ LOG_DEBUG("%s %d: %s - %s",str,ind,ipstr,id);
+}
+
+// -----------------------------------
+bool CookieList::add(Cookie &c)
+{
+ if (contains(c))
+ return false;
+
+ unsigned int oldestTime=(unsigned int)-1;
+ int oldestIndex=0;
+
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].time <= oldestTime)
+ {
+ oldestIndex = i;
+ oldestTime = list[i].time;
+ }
+
+ c.logDebug("Added cookie",oldestIndex);
+ c.time = sys->getTime();
+ list[oldestIndex]=c;
+ return true;
+}
+// -----------------------------------
+void CookieList::remove(Cookie &c)
+{
+ for(int i=0; i<MAX_COOKIES; i++)
+ if (list[i].compare(c))
+ list[i].clear();
+}
--- /dev/null
+// ------------------------------------------------
+// File : http.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+#include "stream.h"
+
+// -------------------------------------
+class HTTPException : public StreamException
+{
+public:
+ HTTPException(const char *m, int c) : StreamException(m) {code=c;}
+ int code;
+};
+
+// --------------------------------------------
+static const char *HTTP_SC_OK = "HTTP/1.0 200 OK";
+static const char *HTTP_SC_NOTFOUND = "HTTP/1.0 404 Not Found";
+static const char *HTTP_SC_UNAVAILABLE = "HTTP/1.0 503 Service Unavailable";
+static const char *HTTP_SC_UNAUTHORIZED = "HTTP/1.0 401 Unauthorized";
+static const char *HTTP_SC_FOUND = "HTTP/1.0 302 Found";
+static const char *HTTP_SC_BADREQUEST = "HTTP/1.0 400 Bad Request";
+static const char *HTTP_SC_FORBIDDEN = "HTTP/1.0 403 Forbidden";
+static const char *HTTP_SC_SWITCH = "HTTP/1.0 101 Switch protocols";
+
+static const char *RTSP_SC_OK = "RTSP/1.0 200 OK";
+
+
+static const char *HTTP_PROTO1 = "HTTP/1.";
+static const char *RTSP_PROTO1 = "RTSP/1.";
+
+static const char *HTTP_HS_SERVER = "Server:";
+static const char *HTTP_HS_AGENT = "User-Agent:";
+static const char *HTTP_HS_CONTENT = "Content-Type:";
+static const char *HTTP_HS_CACHE = "Cache-Control:";
+static const char *HTTP_HS_CONNECTION = "Connection:";
+static const char *HTTP_HS_SETCOOKIE = "Set-Cookie:";
+static const char *HTTP_HS_COOKIE = "Cookie:";
+static const char *HTTP_HS_HOST = "Host:";
+static const char *HTTP_HS_ACCEPT = "Accept:";
+static const char *HTTP_HS_LENGTH = "Content-Length:";
+
+static const char *MIME_MP3 = "audio/mpeg";
+static const char *MIME_XMP3 = "audio/x-mpeg";
+static const char *MIME_OGG = "application/ogg";
+static const char *MIME_XOGG = "application/x-ogg";
+static const char *MIME_MOV = "video/quicktime";
+static const char *MIME_MPG = "video/mpeg";
+static const char *MIME_NSV = "video/nsv";
+static const char *MIME_ASF = "video/x-ms-asf";
+static const char *MIME_ASX = "video/x-ms-asf"; // same as ASF
+static const char *MIME_MMS = "application/x-mms-framed";
+
+static const char *MIME_RAM = "audio/x-pn-realaudio";
+
+
+static const char *MIME_WMA = "audio/x-ms-wma";
+static const char *MIME_WMV = "video/x-ms-wmv";
+
+static const char *MIME_HTML = "text/html";
+static const char *MIME_XML = "text/xml";
+static const char *MIME_CSS = "text/css";
+static const char *MIME_TEXT = "text/plain";
+static const char *MIME_PLS = "audio/mpegurl";
+static const char *MIME_XPLS = "audio/x-mpegurl";
+static const char *MIME_XSCPLS = "audio/x-scpls";
+static const char *MIME_SDP = "application/sdp";
+static const char *MIME_M3U = "audio/m3u";
+static const char *MIME_MPEGURL = "audio/mpegurl";
+static const char *MIME_XM3U = "audio/x-mpegurl";
+static const char *MIME_XPEERCAST = "application/x-peercast";
+static const char *MIME_XPCP = "application/x-peercast-pcp";
+static const char *MIME_RAW = "application/binary";
+static const char *MIME_JPEG = "image/jpeg";
+static const char *MIME_GIF = "image/gif";
+static const char *MIME_PNG = "image/png";
+
+
+// --------------------------------------------
+class Cookie
+{
+public:
+ Cookie()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ time = 0;
+ ip = 0;
+ id[0]=0;
+ }
+
+ void set(const char *i, unsigned int nip)
+ {
+ strncpy(id,i,sizeof(id)-1);
+ id[sizeof(id)-1]=0;
+ ip = nip;
+ }
+ bool compare(Cookie &c)
+ {
+ if (c.ip == ip)
+ if (strcmp(c.id,id)==0)
+ return true;
+
+ return false;
+ }
+
+ void logDebug(const char *,int);
+
+ unsigned int ip;
+ char id[64];
+ unsigned int time;
+};
+
+// --------------------------------------------
+class CookieList
+{
+public:
+ enum {
+ MAX_COOKIES = 32
+ };
+
+
+
+ void init();
+ bool add(Cookie &);
+ void remove(Cookie &);
+ bool contains(Cookie &);
+
+
+ Cookie list[MAX_COOKIES];
+ bool neverExpire;
+
+};
+
+// --------------------------------------------
+class HTTP : public IndirectStream
+{
+public:
+ HTTP(Stream &s)
+ {
+ init(&s);
+ }
+
+ void initRequest(const char *r)
+ {
+ strcpy(cmdLine,r);
+ }
+ void readRequest();
+ bool isRequest(const char *);
+
+ int readResponse();
+ bool checkResponse(int);
+
+ bool nextHeader();
+ bool isHeader(const char *);
+ char *getArgStr();
+ int getArgInt();
+
+ void getAuthUserPass(char *, char *);
+
+ char cmdLine[8192],*arg;
+
+};
+
+#endif
--- /dev/null
+#include "icy.h"
+#include "socket.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void ICYSource::stream(Channel *ch)
+{
+ ChannelStream *source=NULL;
+ try
+ {
+
+ if (!ch->sock)
+ throw StreamException("ICY channel has no socket");
+
+ ch->resetPlayTime();
+
+ ch->setStatus(Channel::S_BROADCASTING);
+ source = ch->createSource();
+ ch->readStream(*ch->sock,source);
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Channel aborted: %s",e.msg);
+ }
+
+
+ ch->setStatus(Channel::S_CLOSING);
+
+ if (ch->sock)
+ {
+ ch->sock->close();
+ delete ch->sock;
+ ch->sock = NULL;
+ }
+
+ if (source)
+ delete source;
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : icy.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _ICY_H
+#define _ICY_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class ICYSource : public ChannelSource
+{
+public:
+ virtual void stream(Channel *);
+
+};
+
+
+
+
+#endif
--- /dev/null
+#ifndef _ID_H
+#define _ID_H
+
+#include <string.h>
+
+// ---------------------------------------------------
+class IDString
+{
+private:
+ enum
+ {
+ LENGTH = 31
+ };
+
+ char data[LENGTH+1];
+public:
+ IDString(const char *id,int cnt)
+ {
+ if (cnt >= LENGTH)
+ cnt=LENGTH;
+ int i;
+ for(i=0; i<cnt; i++)
+ data[i]=id[i];
+ data[i]=0;
+ }
+
+ operator const char *()
+ {
+ return str();
+ }
+
+ const char *str() {return data;}
+
+};
+
+
+
+
+// ---------------------------------------------------
+class ID4
+{
+private:
+ union
+ {
+ int iv;
+ char cv[4];
+ };
+
+public:
+
+ ID4()
+ : iv( 0 )
+ {
+ }
+
+ ID4(int i)
+ :iv(i)
+ {
+ }
+
+ ID4(const char *id)
+ :iv(0)
+ {
+ if (id)
+ for(int i=0; i<4; i++)
+ if ((cv[i]=id[i])==0)
+ break;
+ }
+
+ void clear()
+ {
+ iv = 0;
+ }
+
+ operator int() const
+ {
+ return iv;
+ }
+
+ int operator == (ID4 id) const
+ {
+ return iv==id.iv;
+ }
+ int operator != (ID4 id) const
+ {
+ return iv!=id.iv;
+ }
+
+ bool isSet() const {return iv!=0;}
+
+
+ int getValue() const {return iv;}
+ IDString getString() const {return IDString(cv,4);}
+ void *getData() {return cv;}
+
+};
+
+
+
+
+#endif
--- /dev/null
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95¶\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95¶\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24 Remove static variables
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14 First version
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "identify_encoding.h"
+
+enum encoding_id
+{
+ eid_KNOWN = 0,
+ eid_ASCII = 1,
+ eid_JIS = 2,
+ eid_SJIS = 3,
+ eid_EUCJP = 4,
+ eid_UTF8 = 5
+};
+
+const char *encoding_str[] =
+{
+ "KNOWN", "ASCII", "ISO-2022-JP", "SJIS", "EUC-JP", "UTF-8"
+};
+
+static int
+is_ascii(ie_state_t *st, const unsigned char *p)
+{
+ if (!(isprint(*p) || isspace(*p)) || *p >= 0x80)
+ st->flag = 0;
+ return st->flag;
+}
+
+static int
+is_jis(ie_state_t *st, const unsigned char *p)
+{
+ if (*p >= 0x80)
+ st->flag = 0;
+ return st->flag;
+}
+
+static int
+is_sjis(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0x81 && *p <= 0x9f) st->c_type = 1;
+ else if (*p >= 0xe0 && *p <= 0xef) st->c_type = 1;
+ else if (*p >= 0xa1 && *p <= 0xdf) st->state = 0;
+ else st->flag = 1;
+ }
+ break;
+ case 1:
+ if (*p >= 0x40 && *p <= 0x7e) st->state = 0;
+ else if (*p >= 0x80 && *p <= 0xfc) st->state = 0;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+static int
+is_eucjp(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0xa1 && *p <= 0xfe) st->c_type = 1;
+ else if (*p == 0x8e ) st->c_type = 2;
+ else if (*p == 0x8f ) st->c_type = 3;
+ else st->flag = 0;
+ }
+ break;
+ case 1:
+ switch (st->c_type)
+ {
+ case 1:
+ if (*p >= 0xa1 && *p <= 0xfe) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 2:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 3:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 2;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+ break;
+ case 2:
+ if (*p >= 0x81 && *p <= 0xff) st->state = 0;
+ else st->flag = 0;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+static int
+is_utf8(ie_state_t *st, const unsigned char *p)
+{
+ switch (st->state)
+ {
+ case 0:
+ st->c_type = 0;
+ if (*p >= 0x80)
+ {
+ st->state = 1;
+ if (*p >= 0xc2 && *p <= 0xdf) st->c_type = 1;
+ else if (*p == 0xe0 ) st->c_type = 2;
+ else if (*p >= 0xe1 && *p <= 0xef) st->c_type = 3;
+ else if (*p == 0xf0 ) st->c_type = 4;
+ else if (*p >= 0xf1 && *p <= 0xf3) st->c_type = 5;
+ else if (*p == 0xf4 ) st->c_type = 6;
+ else st->flag = 0;
+ }
+ break;
+ case 1:
+ switch (st->c_type)
+ {
+ case 1:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ break;
+ case 2:
+ if (*p >= 0xa0 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 3:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 4:
+ if (*p >= 0x90 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 5:
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 2;
+ else st->flag = 0;
+ break;
+ case 6:
+ if (*p >= 0x80 && *p <= 0x8f) st->state = 2;
+ else st->flag = 0;
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+ break;
+ case 2:
+ if (st->c_type >= 2 && st->c_type <= 3)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ }else if (st->c_type >= 4 && st->c_type <= 6)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 3;
+ else st->flag = 0;
+ }else{
+ st->flag = 0;
+ }
+ break;
+ case 3:
+ if (st->c_type >= 4 && st->c_type <= 6)
+ {
+ if (*p >= 0x80 && *p <= 0xbf) st->state = 0;
+ else st->flag = 0;
+ }else{
+ st->flag = 0;
+ }
+ break;
+ default:
+ st->flag = 0;
+ break;
+ }
+
+ return st->flag;
+}
+
+identify_encoding_t*
+identify_encoding_open(enum identify_encoding_order order)
+{
+ identify_encoding_t* cd;
+ cd = (identify_encoding_t*)malloc(sizeof(identify_encoding_t));
+
+ if (cd == NULL)
+ {
+ cd = (identify_encoding_t*)(-1);
+ }else{
+ cd->order = order;
+ identify_encoding_reset(cd);
+ }
+ return cd;
+}
+
+void
+identify_encoding_close(identify_encoding_t* cd)
+{
+ if (cd != (identify_encoding_t*)(-1) || cd != NULL)
+ {
+ free(cd);
+ }
+}
+
+static void
+identify_encoding_reset_state(ie_state_t* st)
+{
+ st->flag = 1;
+ st->state = 0;
+ st->c_type = 0;
+}
+
+void
+identify_encoding_reset(identify_encoding_t* cd)
+{
+ identify_encoding_reset_state(&(cd->st_ascii));
+ identify_encoding_reset_state(&(cd->st_jis));
+ identify_encoding_reset_state(&(cd->st_sjis));
+ identify_encoding_reset_state(&(cd->st_eucjp));
+ identify_encoding_reset_state(&(cd->st_utf8));
+}
+
+const char*
+identify_encoding(identify_encoding_t *cd, char* instr)
+{
+ int n;
+ unsigned char *p;
+ enum encoding_id eid = eid_KNOWN;
+
+ identify_encoding_reset(cd);
+
+ for (n = 0, p = (unsigned char *)instr; *p != '\0' && n < IDENTIFY_MAX_LENGTH; p++, n++)
+ {
+ if (cd->st_ascii.flag == 1) is_ascii(&(cd->st_ascii), p);
+ if (cd->st_jis.flag == 1) is_jis(&(cd->st_jis), p);
+ if (cd->st_sjis.flag == 1) is_sjis(&(cd->st_sjis), p);
+ if (cd->st_eucjp.flag == 1) is_eucjp(&(cd->st_eucjp), p);
+ if (cd->st_utf8.flag == 1) is_utf8(&(cd->st_utf8), p);
+ }
+
+ if (cd->st_ascii.flag == 1) eid = eid_ASCII;
+ else if (cd->st_jis.flag == 1) eid = eid_JIS;
+ else if (cd->st_utf8.flag == 1) eid = eid_UTF8;
+ else if (cd->order == ieo_EUCJP)
+ {
+ if (cd->st_eucjp.flag == 1) eid = eid_EUCJP;
+ else if (cd->st_sjis.flag == 1) eid = eid_SJIS;
+ }else{
+ if (cd->st_sjis.flag == 1) eid = eid_SJIS;
+ else if (cd->st_eucjp.flag == 1) eid = eid_EUCJP;
+ }
+
+ return encoding_str[ eid ];
+}
--- /dev/null
+/*
+ *
+ * \8a¿\8e\9a\83R\81[\83h\82Ì\94»\95Ê\82µ\81Aiconv \97p\82Ì\95¶\8e\9a\83G\83\93\83R\81[\83f\83B\83\93\83O\95¶\8e\9a\97ñ\82ð\95Ô\82·
+ *
+ * 2001/10/24 Remove static variables
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ * 2001/10/14 First version
+ * Kazuhiko Iwama <iwama@ymc.ne.jp>
+ *
+ */
+
+#ifndef IDENTIFY_ENCODING_H
+#define IDENTIFY_ENCODING_H
+
+#define IDENTIFY_MAX_LENGTH 256
+
+enum identify_encoding_order {
+ ieo_EUCJP = 0,
+ ieo_SJIS = 1
+};
+
+typedef struct {
+ int flag;
+ int state;
+ int c_type;
+} ie_state_t;
+
+typedef struct {
+ enum identify_encoding_order order;
+ ie_state_t st_ascii;
+ ie_state_t st_jis;
+ ie_state_t st_sjis;
+ ie_state_t st_eucjp;
+ ie_state_t st_utf8;
+} identify_encoding_t;
+
+identify_encoding_t* identify_encoding_open(enum identify_encoding_order order);
+void identify_encoding_close(identify_encoding_t* cd);
+void identify_encoding_reset(identify_encoding_t* cd);
+const char *identify_encoding(identify_encoding_t *cd, char* instr);
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : inifile.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// .INI file reading/writing class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "inifile.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+ void openReadOnly(const char *);
+ void openWriteReplace(const char *);
+// -----------------------------------------
+bool IniFile::openReadOnly(const char *fn)
+{
+ try
+ {
+ fStream.openReadOnly(fn);
+ }catch(StreamException &)
+ {
+ return false;
+ }
+ return true;
+}
+// -----------------------------------------
+bool IniFile::openWriteReplace(const char *fn)
+{
+ try
+ {
+ fStream.openWriteReplace(fn);
+#if defined(_LINUX) || defined(__APPLE__)
+ fStream.writeCRLF = false;
+#endif
+
+ }catch(StreamException &)
+ {
+ return false;
+ }
+ return true;
+}
+// -----------------------------------------
+void IniFile::close()
+{
+ fStream.close();
+}
+
+
+// -----------------------------------------
+bool IniFile::readNext()
+{
+ if (fStream.eof())
+ return false;
+
+ try
+ {
+ fStream.readLine(currLine,256);
+ }catch(StreamException &)
+ {
+ return false;
+ }
+
+
+ // find end of value name and null terminate
+ char *nend = strstr(currLine,"=");
+
+ if (nend)
+ {
+ *nend = 0;
+ valueStr = trimstr(nend+1);
+ }else
+ valueStr = NULL;
+
+ nameStr = trimstr(currLine);
+
+ return true;
+}
+// -----------------------------------------
+bool IniFile::isName(const char *str)
+{
+ return stricmp(getName(),str)==0;
+}
+
+// -----------------------------------------
+char * IniFile::getName()
+{
+ return nameStr;
+}
+// -----------------------------------------
+int IniFile::getIntValue()
+{
+ if (valueStr)
+ return atoi(valueStr);
+ else
+ return 0;
+}
+// -----------------------------------------
+char * IniFile::getStrValue()
+{
+ if (valueStr)
+ return valueStr;
+ else
+ return "";
+}
+// -----------------------------------------
+bool IniFile::getBoolValue()
+{
+ if (!valueStr)
+ return false;
+
+
+ if ( (stricmp(valueStr,"yes")==0) ||
+ (stricmp(valueStr,"y")==0) ||
+ (stricmp(valueStr,"1")==0) )
+ return true;
+
+ return false;
+}
+
+// -----------------------------------------
+void IniFile::writeIntValue(const char *name, int iv)
+{
+ sprintf(currLine,"%s = %d",name,iv);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeStrValue(const char *name, const char *sv)
+{
+ sprintf(currLine,"%s = %s",name,sv);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeSection(const char *name)
+{
+ fStream.writeLine("");
+ sprintf(currLine,"[%s]",name);
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeBoolValue(const char *name, int v)
+{
+ sprintf(currLine,"%s = %s",name,(v!=0)?"Yes":"No");
+ fStream.writeLine(currLine);
+}
+// -----------------------------------------
+void IniFile::writeLine(const char *str)
+{
+ fStream.writeLine(str);
+}
--- /dev/null
+// ------------------------------------------------
+// File : inifile.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _INIFILE
+#define _INIFILE
+
+#include "stream.h"
+
+// -----------------------------------------
+class IniFile
+{
+public:
+ bool openReadOnly(const char *);
+ bool openWriteReplace(const char *);
+ void close();
+
+ bool readNext();
+
+ bool isName(const char *);
+ char * getName();
+ int getIntValue();
+ char * getStrValue();
+ bool getBoolValue();
+
+ void writeSection(const char *);
+ void writeIntValue(const char *, int);
+ void writeStrValue(const char *, const char *);
+ void writeBoolValue(const char *, int);
+ void writeLine(const char *);
+
+
+ FileStream fStream;
+ char currLine[256];
+ char *nameStr,*valueStr;
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : jis.cpp
+// Date: 1-april-2004
+// Author: giles
+//
+// ShiftJIS/EUC to Unicode conversions
+// (modified version of program by Y. Kuno, see below)
+//
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+/* J2Uc.c --- written by Y. Kuno, July 1996. */
+/* Compile with -DSJIS if you want to convert from SJIS; otherwise */
+/* EUC-JP is assumed. */
+/* We are thankful to following people for permitting us free use */
+/* of the following materials. */
+/* * Itaru Ichikawa (Fujitsu) --- nkf 1.4 source code. */
+/* * Glenn Adams (Unicode Inc.) --- JISx0208 to Unicode mapping table. */
+/* This source code can freely be used, distributed, modified provided */
+/* that this credit is also included in the source code. */
+
+// -----------------------------------
+
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// -----------------------------------
+
+#define SJ0162 0x00e1 /* 01 - 62 ku offset */
+#define SJ6394 0x0161 /* 63 - 94 ku offset */
+
+
+// -----------------------------------
+static unsigned short uniTable[94][94] = {
+{12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,
+ 180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,
+ 12293,12294,12295,12540,8213,8208,65295,92,12316,8214,65372,8230,
+ 8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,
+ 65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,
+ 8722,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,
+ 9794,9792,176,8242,8243,8451,65509,65284,162,163,65285,65283,
+ 65286,65290,65312,167,9734,9733,9675,9679,9678,9671,},
+{9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,
+ 8595,12307,0,0,0,0,0,0,0,0,0,0,0,8712,8715,8838,8839,8834,8835,
+ 8746,8745,0,0,0,0,0,0,0,0,8743,8744,172,8658,8660,8704,8707,0,0,
+ 0,0,0,0,0,0,0,0,0,8736,8869,8978,8706,8711,8801,8786,8810,8811,
+ 8730,8765,8733,8757,8747,8748,0,0,0,0,0,0,0,8491,8240,9839,9837,
+ 9834,8224,8225,182,0,0,0,0,9711,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65296,65297,65298,65299,65300,65301,65302,
+ 65303,65304,65305,0,0,0,0,0,0,0,65313,65314,65315,65316,65317,65318,65319,
+ 65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,
+ 65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,65345,65346,65347,
+ 65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,
+ 65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,},
+{12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,
+ 12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,
+ 12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,
+ 12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,
+ 12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,
+ 12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,
+ 12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,
+ 12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,
+ 12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,
+ 12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,
+ 12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,
+ 12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,
+ 12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,
+ 12533,12534,0,0,0,0,0,0,0,0,},
+{913,914,915,916,917,918,919,920,921,922,923,924,
+ 925,926,927,928,929,931,932,933,934,935,936,937,0,
+ 0,0,0,0,0,0,0,945,946,947,948,949,950,951,952,953,954,
+ 955,956,957,958,959,960,961,963,964,965,966,967,
+ 968,969,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,},
+{1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,
+ 1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,
+ 1063,1064,1065,1066,1067,1068,1069,1070,1071,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,
+ 1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,
+ 1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,},
+{9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,
+ 9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,
+ 9512,9527,9535,9501,9520,9509,9528,9538,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,
+ 24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,
+ 22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,
+ 26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,
+ 22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,
+ 32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,
+ 32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,
+ 21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,},
+{38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,
+ 40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,
+ 21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,
+ 23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,
+ 33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,
+ 27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,
+ 28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,
+ 40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,},
+{25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,
+ 27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,
+ 28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,
+ 22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,
+ 29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,
+ 35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,
+ 33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,
+ 22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,},
+{39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,
+ 35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,
+ 34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,
+ 22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,
+ 35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,
+ 25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,
+ 28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,
+ 20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,},
+{31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,
+ 21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,
+ 25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,
+ 29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,
+ 35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,
+ 20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,
+ 38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,
+ 24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,},
+{27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,
+ 35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,
+ 23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,
+ 25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,
+ 21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,
+ 24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,
+ 32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,
+ 34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,},
+{20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,
+ 22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,
+ 29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,
+ 20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,
+ 22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,
+ 33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,
+ 29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,
+ 31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,},
+{25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,
+ 37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,
+ 20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,
+ 24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,
+ 32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,
+ 33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,
+ 28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,
+ 21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,},
+{26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,
+ 36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,
+ 24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,
+ 21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,
+ 29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,
+ 40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,
+ 27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,
+ 20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,},
+{21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,
+ 24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,
+ 26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,
+ 30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,
+ 33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,
+ 37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,
+ 25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,
+ 40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,},
+{27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,
+ 26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,
+ 24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,
+ 20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,
+ 28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,
+ 38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,
+ 21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,
+ 31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,},
+{23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,
+ 39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,
+ 29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,
+ 20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,
+ 23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,
+ 26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,
+ 33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,
+ 27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,},
+{27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,
+ 36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,
+ 22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,
+ 20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,
+ 29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,
+ 26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,
+ 23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,
+ 21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,},
+{23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,
+ 33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,
+ 37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,
+ 37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,
+ 34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,
+ 26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,
+ 21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,
+ 21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,},
+{21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,
+ 23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,
+ 25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,
+ 28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,
+ 31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,
+ 35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,
+ 20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,
+ 29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,},
+{25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,
+ 20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,
+ 26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,
+ 34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,
+ 22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,
+ 37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,
+ 32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,
+ 26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,},
+{28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,
+ 24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,
+ 30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,
+ 38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,
+ 31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,
+ 25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,
+ 21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,
+ 27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,},
+{32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,
+ 37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,
+ 22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,
+ 31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,
+ 21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,
+ 25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,
+ 30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,
+ 35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,},
+{33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,
+ 36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,
+ 23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,
+ 22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,
+ 32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,
+ 33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,
+ 37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,
+ 28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,},
+{21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,
+ 40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,
+ 28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,
+ 22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,
+ 24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,
+ 31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,
+ 24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,
+ 28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,},
+{24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,
+ 29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,
+ 38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,
+ 27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,
+ 20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,
+ 32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,
+ 22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,
+ 27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,},
+{37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,
+ 37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,
+ 24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,
+ 38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,
+ 33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,
+ 20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,
+ 24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,
+ 29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,},
+{33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,
+ 39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,
+ 33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,
+ 31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,
+ 33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,
+ 21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,
+ 37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,
+ 24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,},
+{22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,
+ 29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,
+ 22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,
+ 25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,
+ 24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,
+ 22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,
+ 31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,
+ 33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,},
+{20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,
+ 37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,
+ 22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,
+ 27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,
+ 29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,
+ 21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,
+ 30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,
+ 27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,},
+{40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,
+ 30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,
+ 27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,
+ 37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,
+ 38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,
+ 24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,
+ 36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,
+ 23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,},
+{31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,
+ 21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,
+ 32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,
+ 38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,
+ 22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,
+ 20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,
+ 24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,
+ 23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,},
+{27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,
+ 35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,
+ 24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,
+ 35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,
+ 26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,
+ 32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,
+ 21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,
+ 25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,},
+{28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,
+ 31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,
+ 40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,
+ 23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,
+ 22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,
+ 26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,
+ 20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,
+ 35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,},
+{35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,
+ 26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,
+ 37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,
+ 22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,
+ 29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,
+ 24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,
+ 33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,
+ 34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,},
+{30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,
+ 21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,
+ 26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,
+ 30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,
+ 20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,
+ 22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,
+ 31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,
+ 28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,},
+{34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,
+ 24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,
+ 34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,
+ 36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,
+ 28286,30871,33109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,
+ 20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,
+ 20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,
+ 20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,
+ 20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,
+ 20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,
+ 20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,
+ 20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,},
+{20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,
+ 20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,
+ 20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,
+ 22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,
+ 20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,
+ 34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,
+ 21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,
+ 21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,},
+{36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,
+ 21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,
+ 21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,
+ 20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,
+ 21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,
+ 21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,
+ 21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,
+ 21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,},
+{21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,
+ 21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,
+ 21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,
+ 21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,
+ 21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,
+ 22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,
+ 22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,
+ 22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,},
+{22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,
+ 22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,
+ 22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,
+ 22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,
+ 22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,
+ 22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,
+ 22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,
+ 22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,},
+{22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,
+ 23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,
+ 23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,
+ 23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,
+ 23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,
+ 25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,
+ 23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,
+ 23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,},
+{23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,
+ 23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,
+ 23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,
+ 23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,
+ 23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,
+ 24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,
+ 24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,
+ 24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,},
+{24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,
+ 24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,
+ 24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,
+ 24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,
+ 24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,
+ 24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,
+ 24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,
+ 24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,},
+{24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,
+ 24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,
+ 24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,
+ 24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,
+ 24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,
+ 25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,
+ 25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,
+ 25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,},
+{25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,
+ 25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,
+ 25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,
+ 25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,
+ 25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,
+ 25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,
+ 25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,
+ 25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,},
+{25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,
+ 25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,
+ 25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,
+ 25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,
+ 26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,
+ 26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,
+ 26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,
+ 26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,},
+{26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,
+ 26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,
+ 26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,
+ 26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,
+ 26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,
+ 26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,
+ 26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,
+ 26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,},
+{26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,
+ 26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,
+ 27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,
+ 27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,
+ 27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,
+ 27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,
+ 27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,
+ 27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,},
+{27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,
+ 27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,
+ 30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,
+ 27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,
+ 27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,
+ 27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,
+ 27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,
+ 27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,},
+{27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,
+ 27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,
+ 28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,
+ 28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,
+ 28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,
+ 28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,
+ 28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,
+ 28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,},
+{28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,
+ 28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,
+ 28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,
+ 28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,
+ 28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,
+ 28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,
+ 29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,
+ 29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,},
+{29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,
+ 29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,
+ 29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,
+ 29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,
+ 29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,
+ 29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,
+ 29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,
+ 29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,},
+{29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,
+ 29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,
+ 30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,
+ 30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,
+ 30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,
+ 30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,
+ 30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,
+ 30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,},
+{30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,
+ 30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,
+ 30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,
+ 30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,
+ 30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,
+ 30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,
+ 30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,
+ 30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,},
+{30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,
+ 31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,
+ 31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,
+ 31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,
+ 31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,
+ 31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,
+ 31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,
+ 31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,},
+{31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,
+ 31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,
+ 31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,
+ 31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,
+ 31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,
+ 31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,
+ 31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,
+ 31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,},
+{32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,
+ 32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,
+ 32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,
+ 32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,
+ 32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,
+ 32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,
+ 32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,
+ 32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,},
+{32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,
+ 32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,
+ 32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,
+ 32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,
+ 32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,
+ 32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,
+ 32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,
+ 32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,},
+{38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,
+ 33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,
+ 33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,
+ 33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,
+ 33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,
+ 33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,
+ 33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,
+ 33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,},
+{33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,
+ 33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,
+ 33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,
+ 33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,
+ 34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,
+ 33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,
+ 33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,
+ 34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,},
+{34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,
+ 34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,
+ 34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,
+ 34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,
+ 34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,
+ 34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,
+ 34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,
+ 34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,},
+{34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,
+ 38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,
+ 34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,
+ 34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,
+ 34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,
+ 34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,
+ 35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,
+ 35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,},
+{35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,
+ 35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,
+ 35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,
+ 35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,
+ 35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,
+ 35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,
+ 35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,
+ 35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,},
+{35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,
+ 35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,
+ 35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,
+ 36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,
+ 36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,
+ 36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,
+ 36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,
+ 36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,},
+{36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,
+ 36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,
+ 36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,
+ 36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,
+ 36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,
+ 36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,
+ 36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,
+ 36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,},
+{36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,
+ 36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,
+ 37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,
+ 37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,
+ 37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,
+ 37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,
+ 37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,
+ 37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,},
+{37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,
+ 37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,
+ 37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,
+ 37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,
+ 38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,
+ 38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,
+ 28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,
+ 38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,},
+{38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,
+ 38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,
+ 38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,
+ 38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,
+ 38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,
+ 38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,
+ 38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,
+ 38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,},
+{39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,
+ 39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,
+ 39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,
+ 39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,
+ 39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,
+ 39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,
+ 39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,
+ 39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,},
+{39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,
+ 39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,
+ 39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,
+ 39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,
+ 39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,
+ 39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,
+ 40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,
+ 40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,},
+{40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,
+ 40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,
+ 40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,
+ 40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,
+ 40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,
+ 40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,
+ 30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,
+ 40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,},
+{22575,27079,36953,29796,20956,29081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+};
+
+
+// ------------------------------------------------------------
+unsigned short JISConverter::sjisToUnicode(unsigned short sjis)
+{
+ unsigned short u;
+ unsigned int c = sjis>>8;
+ unsigned int c1 = sjis&0xff;
+
+ c = c + c - ((c <= 0x9f) ? SJ0162 : SJ6394);
+ if(c1 < 0x9f)
+ {
+ c1 = c1 - ((c1 > 0x7f) ? 0x20 : 0x1f);
+ }
+ else
+ {
+ c1 = c1 - 0x7e; c++;
+ }
+ c -= 33;
+ c1 -= 33;
+ if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+ u = 0x3013;
+ else
+ {
+ u = uniTable[c][c1];
+ if(!u)
+ u = 0x3013;
+ }
+
+ return u;
+}
+// ------------------------------------------------------------
+unsigned short JISConverter::eucToUnicode(unsigned short euc)
+{
+ unsigned short u;
+ unsigned int c = euc>>8;
+ unsigned int c1 = euc&0xff;
+
+ c &= 0x7f;
+ c -= 33;
+ c1 &= 0x7f;
+ c1 -= 33;
+ if(c < 0 || c1 < 0 || c > 93 || c1 > 93)
+ u = 0x3013;
+ else
+ {
+ u = uniTable[c][c1];
+ if(!u)
+ u = 0x3013;
+ }
+ return u;
+}
--- /dev/null
+// ------------------------------------------------
+// File : jis.h
+// Date: 1-april-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _JIS_H
+#define _JIS_H
+
+// ----------------------------------
+class JISConverter
+{
+public:
+
+ static unsigned short sjisToUnicode(unsigned short);
+ static unsigned short eucToUnicode(unsigned short);
+};
+
+
+
+#endif
+
+
--- /dev/null
+// ------------------------------------------------
+// File : mms.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mms.h"
+#include "asf.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+ASFInfo parseASFHeader(Stream &in);
+
+
+// ------------------------------------------
+void MMSStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MMSStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MMSStream::readPacket(Stream &in,Channel *ch)
+{
+ {
+ ASFChunk chunk;
+
+ chunk.read(in);
+
+ switch (chunk.type)
+ {
+ case 0x4824: // asf header
+ {
+ MemoryStream mem(ch->headPack.data,sizeof(ch->headPack.data));
+
+ chunk.write(mem);
+
+
+
+
+ MemoryStream asfm(chunk.data,chunk.dataLen);
+ ASFObject asfHead;
+ asfHead.readHead(asfm);
+
+ ASFInfo asf = parseASFHeader(asfm);
+ LOG_DEBUG("ASF Info: pnum=%d, psize=%d, br=%d",asf.numPackets,asf.packetSize,asf.bitrate);
+ for(int i=0; i<ASFInfo::MAX_STREAMS; i++)
+ {
+ ASFStream *s = &asf.streams[i];
+ if (s->id)
+ LOG_DEBUG("ASF Stream %d : %s, br=%d",s->id,s->getTypeName(),s->bitrate);
+ }
+
+ ch->info.bitrate = asf.bitrate/1000;
+
+ ch->headPack.type = ChanPacket::T_HEAD;
+ ch->headPack.len = mem.pos;
+ ch->headPack.pos = ch->streamPos;
+ ch->newPacket(ch->headPack);
+
+ ch->streamPos += ch->headPack.len;
+
+ break;
+ }
+ case 0x4424: // asf data
+ {
+
+ ChanPacket pack;
+
+ MemoryStream mem(pack.data,sizeof(pack.data));
+
+ chunk.write(mem);
+
+ pack.type = ChanPacket::T_DATA;
+ pack.len = mem.pos;
+ pack.pos = ch->streamPos;
+
+ ch->newPacket(pack);
+ ch->streamPos += pack.len;
+
+ break;
+ }
+ default:
+ throw StreamException("Unknown ASF chunk");
+
+ }
+
+ }
+ return 0;
+}
+
+
+// -----------------------------------
+ASFInfo parseASFHeader(Stream &in)
+{
+ ASFInfo asf;
+
+ try
+ {
+ int numHeaders = in.readLong();
+
+ in.readChar();
+ in.readChar();
+
+ LOG_CHANNEL("ASF Headers: %d",numHeaders);
+ for(int i=0; i<numHeaders; i++)
+ {
+
+ ASFObject obj;
+
+ unsigned int l = obj.readHead(in);
+ obj.readData(in,l);
+
+
+ MemoryStream data(obj.data,obj.lenLo);
+
+
+ switch (obj.type)
+ {
+ case ASFObject::T_FILE_PROP:
+ {
+ data.skip(32);
+
+ unsigned int dpLo = data.readLong();
+ unsigned int dpHi = data.readLong();
+
+ data.skip(24);
+
+ data.readLong();
+ //data.writeLong(1); // flags = broadcast, not seekable
+
+ int min = data.readLong();
+ int max = data.readLong();
+ int br = data.readLong();
+
+ if (min != max)
+ throw StreamException("ASF packetsizes (min/max) must match");
+
+ asf.packetSize = max;
+ asf.bitrate = br;
+ asf.numPackets = dpLo;
+ break;
+ }
+ case ASFObject::T_STREAM_BITRATE:
+ {
+ int cnt = data.readShort();
+ for(int i=0; i<cnt; i++)
+ {
+ unsigned int id = data.readShort();
+ int bitrate = data.readLong();
+ if (id < ASFInfo::MAX_STREAMS)
+ asf.streams[id].bitrate = bitrate;
+ }
+ break;
+ }
+ case ASFObject::T_STREAM_PROP:
+ {
+ ASFStream s;
+ s.read(data);
+ asf.streams[s.id].id = s.id;
+ asf.streams[s.id].type = s.type;
+ break;
+ }
+ }
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("ASF: %s",e.msg);
+ }
+
+ return asf;
+}
+
+
--- /dev/null
+// ------------------------------------------------
+// File : mms.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MMS_H
+#define _MMS_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MMSStream : public ChannelStream
+{
+public:
+
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "mp3.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// ------------------------------------------
+void MP3Stream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void MP3Stream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int MP3Stream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ if (ch->icyMetaInterval)
+ {
+
+ int rlen = ch->icyMetaInterval;
+
+ while (rlen)
+ {
+ int rl = rlen;
+ if (rl > ChanMgr::MAX_METAINT)
+ rl = ChanMgr::MAX_METAINT;
+
+ pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+ ch->streamPos+=pack.len;
+
+ rlen-=rl;
+ }
+
+ unsigned char len;
+ in.read(&len,1);
+ if (len)
+ {
+ if (len*16 > 1024) len = 1024/16;
+ char buf[1024];
+ in.read(buf,len*16);
+ ch->processMp3Metadata(buf);
+ }
+
+ }else{
+
+ pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos += pack.len;
+ }
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : mp3.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _MP3_H
+#define _MP3_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class MP3Stream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : nsv.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "nsv.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void NSVStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+void NSVStream::readHeader(Stream &,Channel *)
+{
+}
+// ------------------------------------------
+int NSVStream::readPacket(Stream &in,Channel *ch)
+{
+ ChanPacket pack;
+
+ if (ch->icyMetaInterval)
+ {
+
+ int rlen = ch->icyMetaInterval;
+
+ while (rlen)
+ {
+ int rl = rlen;
+ if (rl > ChanMgr::MAX_METAINT)
+ rl = ChanMgr::MAX_METAINT;
+
+ pack.init(ChanPacket::T_DATA,pack.data,rl,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+ ch->streamPos+=pack.len;
+
+ rlen-=rl;
+ }
+
+ unsigned char len;
+ in.read(&len,1);
+ if (len)
+ {
+ if (len*16 > 1024) len = 1024/16;
+ char buf[1024];
+ in.read(buf,len*16);
+ ch->processMp3Metadata(buf);
+ }
+
+ }else{
+
+ pack.init(ChanPacket::T_DATA,pack.data,ChanMgr::MAX_METAINT,ch->streamPos);
+ in.read(pack.data,pack.len);
+ ch->newPacket(pack);
+ ch->checkReadDelay(pack.len);
+
+ ch->streamPos += pack.len;
+ }
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : nsv.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _NSV_H
+#define _NSV_H
+
+
+#include "channel.h"
+
+// ----------------------------------------------
+class NSVStream : public ChannelStream
+{
+public:
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : mp3.cpp
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "channel.h"
+#include "ogg.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+static int test=0;
+// ------------------------------------------
+void OGGStream::readHeader(Stream &,Channel *)
+{
+ test = 0;
+}
+
+// ------------------------------------------
+void OGGStream::readEnd(Stream &,Channel *)
+{
+}
+
+// ------------------------------------------
+int OGGStream::readPacket(Stream &in,Channel *ch)
+{
+ OggPage ogg;
+ ChanPacket pack;
+
+ ogg.read(in);
+
+ if (ogg.isBOS())
+ {
+ if (!vorbis.needHeader() && !theora.needHeader())
+ {
+ ch->headPack.len = 0;
+ }
+
+ if (ogg.detectVorbis())
+ vorbis.bos(ogg.getSerialNo());
+ if (ogg.detectTheora())
+ theora.bos(ogg.getSerialNo());
+ }
+
+ if (ogg.isEOS())
+ {
+
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ {
+ LOG_CHANNEL("Vorbis stream: EOS");
+ vorbis.eos();
+ }
+ if (ogg.getSerialNo() == theora.serialNo)
+ {
+ LOG_CHANNEL("Theora stream: EOS");
+ theora.eos();
+ }
+ }
+
+ if (vorbis.needHeader() || theora.needHeader())
+ {
+
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ vorbis.readHeader(ch,ogg);
+ else if (ogg.getSerialNo() == theora.serialNo)
+ theora.readHeader(ch,ogg);
+ else
+ throw StreamException("Bad OGG serial no.");
+
+
+ if (!vorbis.needHeader() && !theora.needHeader())
+ {
+
+ ch->info.bitrate = 0;
+
+ if (vorbis.isActive())
+ ch->info.bitrate += vorbis.bitrate;
+
+ if (theora.isActive())
+ {
+ ch->info.bitrate += theora.bitrate;
+ ch->info.contentType = ChanInfo::T_OGM;
+ }
+
+
+ ch->headPack.type = ChanPacket::T_HEAD;
+ ch->headPack.pos = ch->streamPos;
+
+ ch->startTime = sys->getDTime();
+
+ ch->streamPos += ch->headPack.len;
+
+ ch->newPacket(ch->headPack);
+ LOG_CHANNEL("Got %d bytes of headers",ch->headPack.len);
+ }
+
+ }else
+ {
+
+
+ pack.init(ChanPacket::T_DATA,ogg.data,ogg.headLen+ogg.bodyLen,ch->streamPos);
+ ch->newPacket(pack);
+
+ ch->streamPos+=pack.len;
+
+ if (theora.isActive())
+ {
+ if (ogg.getSerialNo() == theora.serialNo)
+ {
+ ch->sleepUntil(theora.getTime(ogg));
+ }
+ }else if (vorbis.isActive())
+ {
+ if (ogg.getSerialNo() == vorbis.serialNo)
+ {
+ ch->sleepUntil(vorbis.getTime(ogg));
+ }
+ }
+
+ }
+ return 0;
+}
+
+// -----------------------------------
+void OggSubStream::readHeader(Channel *ch,OggPage &ogg)
+{
+ if ((pack.bodyLen + ogg.bodyLen) >= OggPacket::MAX_BODYLEN)
+ throw StreamException("OGG packet too big");
+
+ if (ch->headPack.len+(ogg.bodyLen+ogg.headLen) >= ChanMeta::MAX_DATALEN)
+ throw StreamException("OGG packet too big for headMeta");
+
+// copy complete packet into head packet
+ memcpy(&ch->headPack.data[ch->headPack.len],ogg.data,ogg.headLen+ogg.bodyLen);
+ ch->headPack.len += ogg.headLen+ogg.bodyLen;
+
+ // add body to packet
+ memcpy(&pack.body[pack.bodyLen],&ogg.data[ogg.headLen],ogg.bodyLen);
+ pack.bodyLen += ogg.bodyLen;
+
+ pack.addLacing(ogg);
+
+ if (pack.numPackets >= maxHeaders)
+ procHeaders(ch);
+
+}
+// -----------------------------------
+void OggVorbisSubStream::procHeaders(Channel *ch)
+{
+ unsigned int packPtr=0;
+
+ for(int i=0; i<pack.numPackets; i++)
+ {
+ MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+ packPtr += pack.packetSizes[i];
+
+ char id[8];
+
+ vin.read(id,7);
+ id[7]=0;
+
+ switch (id[0])
+ {
+ case 1: // ident
+ LOG_CHANNEL("OGG Vorbis Header: Ident (%d bytes)",vin.len);
+ readIdent(vin,ch->info);
+ break;
+ case 3: // comment
+ {
+ LOG_CHANNEL("OGG Vorbis Header: Comment (%d bytes)",vin.len);
+ ChanInfo newInfo = ch->info;
+ readComment(vin,newInfo);
+ ch->updateInfo(newInfo);
+ }
+ break;
+ case 5: // setup
+ LOG_CHANNEL("OGG Vorbis Header: Setup (%d bytes)",vin.len);
+ //readSetup(vin);
+ break;
+ default:
+ throw StreamException("Unknown Vorbis packet header type");
+ break;
+ }
+ }
+
+}
+// -----------------------------------
+double OggTheoraSubStream::getTime(OggPage &ogg)
+{
+ int64_t iframe=ogg.granPos>>granposShift;
+ int64_t pframe=ogg.granPos-(iframe<<granposShift);
+
+ return (iframe+pframe)*frameTime;
+}
+// -----------------------------------
+void OggTheoraSubStream::readInfo(Stream &in, ChanInfo &info)
+{
+ int verMaj = in.readBits(8);
+ int verMin = in.readBits(8);
+ int verSub = in.readBits(8);
+
+ int encWidth = in.readBits(16) << 4;
+ int encHeight = in.readBits(16) << 4;
+
+ in.readBits(24+24+8+8);
+
+ int fpsNum = in.readBits(32);
+ int fpsDen = in.readBits(32);
+
+ float fps = (float)fpsNum/(float)fpsDen;
+ frameTime = (double)fpsDen/(double)fpsNum;
+
+ in.readBits(24+24+8);
+
+ bitrate = in.readBits(24) / 1000;
+ int quality = in.readBits(6);
+
+ granposShift = in.readBits(5);
+
+ LOG_CHANNEL("OGG Theora Info: %dx%dx%.1ffps %dkbps %dQ %dG",encWidth,encHeight,fps,bitrate,quality,granposShift);
+
+
+}
+// -----------------------------------
+void OggTheoraSubStream::procHeaders(Channel *ch)
+{
+ unsigned int packPtr=0;
+
+ for(int i=0; i<pack.numPackets; i++)
+ {
+ MemoryStream vin(&pack.body[packPtr],pack.packetSizes[i]);
+
+ packPtr += pack.packetSizes[i];
+
+ unsigned char id[8];
+
+ vin.read(id,7);
+ id[7]=0;
+
+ switch (id[0] & 0xff)
+ {
+ case 128: // info
+ LOG_CHANNEL("OGG Theora Header: Info (%d bytes)",vin.len);
+ readInfo(vin,ch->info);
+ break;
+ default:
+ LOG_CHANNEL("OGG Theora Header: Unknown %d (%d bytes)",id[0] & 0xff,vin.len);
+ break;
+ }
+
+
+
+ }
+
+}
+
+// -----------------------------------
+double OggVorbisSubStream::getTime(OggPage &ogg)
+{
+ return (double)ogg.granPos / (double)samplerate;
+
+}
+
+// -----------------------------------
+void OggVorbisSubStream::readIdent(Stream &in, ChanInfo &info)
+{
+ int ver = in.readLong();
+ int chans = in.readChar();
+ samplerate = in.readLong();
+ int brMax = in.readLong();
+ int brNom = in.readLong();
+ int brLow = in.readLong();
+
+
+ in.readChar(); // skip blocksize 0+1
+
+ LOG_CHANNEL("OGG Vorbis Ident: ver=%d, chans=%d, rate=%d, brMax=%d, brNom=%d, brLow=%d",
+ ver,chans,samplerate,brMax,brNom,brLow);
+
+
+ bitrate = brNom/1000;
+
+ char frame = in.readChar(); // framing bit
+ if (!frame)
+ throw StreamException("Bad Indent frame");
+
+}
+
+
+// -----------------------------------
+void OggVorbisSubStream::readSetup(Stream &in)
+{
+ // skip everything in packet
+ int cnt=0;
+ while (!in.eof())
+ {
+ cnt++;
+ in.readChar();
+ }
+
+ LOG_CHANNEL("Read %d bytes of Vorbis Setup",cnt);
+}
+// -----------------------------------
+void OggVorbisSubStream::readComment(Stream &in, ChanInfo &info)
+{
+ int vLen = in.readLong(); // vendor len
+
+ in.skip(vLen);
+
+ char argBuf[8192];
+
+ info.track.clear();
+
+ int cLen = in.readLong(); // comment len
+ for(int i=0; i<cLen; i++)
+ {
+ int l = in.readLong();
+ if (l > sizeof(argBuf))
+ throw StreamException("Comment string too long");
+ in.read(argBuf,l);
+ argBuf[l] = 0;
+ LOG_CHANNEL("OGG Comment: %s",argBuf);
+
+ char *arg;
+ if ((arg=stristr(argBuf,"ARTIST=")))
+ {
+ info.track.artist.set(arg+7,String::T_ASCII);
+ info.track.artist.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"TITLE=")))
+ {
+ info.track.title.set(arg+6,String::T_ASCII);
+ info.track.title.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"GENRE=")))
+ {
+ info.track.genre.set(arg+6,String::T_ASCII);
+ info.track.genre.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"CONTACT=")))
+ {
+ info.track.contact.set(arg+8,String::T_ASCII);
+ info.track.contact.convertTo(String::T_UNICODE);
+
+ }else if ((arg=stristr(argBuf,"ALBUM=")))
+ {
+ info.track.album.set(arg+6,String::T_ASCII);
+ info.track.album.convertTo(String::T_UNICODE);
+ }
+ }
+
+ char frame = in.readChar(); // framing bit
+ if (!frame)
+ throw StreamException("Bad Comment frame");
+
+// updateMeta();
+
+}
+
+// -----------------------------------
+bool OggPage::isBOS()
+{
+ return (data[5] & 0x02) != 0;
+}
+// -----------------------------------
+bool OggPage::isEOS()
+{
+ return (data[5] & 0x04) != 0;
+}
+// -----------------------------------
+bool OggPage::isNewPacket()
+{
+ return (data[5] & 0x01) == 0;
+}
+// -----------------------------------
+bool OggPage::isHeader()
+{
+ return ((*(unsigned int *)&data[6]) || (*(unsigned int *)&data[10])) == 0;
+}
+// -----------------------------------
+unsigned int OggPage::getSerialNo()
+{
+ return *(unsigned int *)&data[14];
+}
+
+// -----------------------------------
+void OggPage::read(Stream &in)
+{
+ // skip until we get OGG capture pattern
+ bool gotOgg=false;
+ while (!gotOgg)
+ {
+ if (in.readChar() == 'O')
+ if (in.readChar() == 'g')
+ if (in.readChar() == 'g')
+ if (in.readChar() == 'S')
+ gotOgg = true;
+ if (!gotOgg)
+ LOG_CHANNEL("Skipping OGG packet");
+ }
+
+
+
+ memcpy(&data[0],"OggS",4);
+
+ in.read(&data[4],27-4);
+
+ int numSegs = data[26];
+ bodyLen = 0;
+
+ // read segment table
+ in.read(&data[27],numSegs);
+ for(int i=0; i<numSegs; i++)
+ bodyLen += data[27+i];
+
+ if (bodyLen >= MAX_BODYLEN)
+ throw StreamException("OGG body too big");
+
+ headLen = 27+numSegs;
+
+ if (headLen > MAX_HEADERLEN)
+ throw StreamException("OGG header too big");
+
+ in.read(&data[headLen],bodyLen);
+
+ granPos = *(unsigned int *)&data[10];
+ granPos <<= 32;
+ granPos |= *(unsigned int *)&data[6];
+
+
+ #if 0
+ LOG_DEBUG("OGG Packet - page %d, id = %x - %s %s %s - %d:%d - %d segs, %d bytes",
+ *(unsigned int *)&data[18],
+ *(unsigned int *)&data[14],
+ data[5]&0x1?"cont":"new",
+ data[5]&0x2?"bos":"",
+ data[5]&0x4?"eos":"",
+ (unsigned int)(granPos>>32),
+ (unsigned int)(granPos&0xffffffff),
+ numSegs,
+ headLen+bodyLen);
+
+ #endif
+
+}
+// -----------------------------------
+bool OggPage::detectVorbis()
+{
+ return memcmp(&data[headLen+1],"vorbis",6) == 0;
+}
+// -----------------------------------
+bool OggPage::detectTheora()
+{
+ return memcmp(&data[headLen+1],"theora",6) == 0;
+}
+
+// -----------------------------------
+void OggPacket::addLacing(OggPage &ogg)
+{
+
+ int numSegs = ogg.data[26];
+ for(int i=0; i<numSegs; i++)
+ {
+ int seg = ogg.data[27+i];
+
+ packetSizes[numPackets]+=seg;
+
+ if (seg < 255)
+ {
+ numPackets++;
+ if (numPackets >= MAX_PACKETS)
+ throw StreamException("Too many OGG packets");
+ packetSizes[numPackets]=0;
+ }
+ }
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : ogg.h
+// Date: 28-may-2003
+// Author: giles
+//
+// (c) 2002-3 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _OGG_H
+#define _OGG_H
+
+
+#include "channel.h"
+// ----------------------------------------------
+class OggPage;
+
+// ----------------------------------
+class OggPacket
+{
+public:
+ enum
+ {
+ MAX_BODYLEN = 65536, // probably too small
+ MAX_PACKETS = 256 // prolly too small too, but realloc?!?!?!
+ };
+
+ void addLacing(OggPage &);
+
+ int bodyLen;
+ unsigned char body[MAX_BODYLEN];
+
+
+ int numPackets;
+ unsigned int packetSizes[MAX_PACKETS];
+};
+
+// ----------------------------------------------
+class OggSubStream
+{
+public:
+ OggSubStream()
+ :maxHeaders(0),serialNo(0),bitrate(0)
+ {}
+
+ bool needHeader()
+ {
+ return maxHeaders && (pack.numPackets < maxHeaders);
+ }
+
+ void eos()
+ {
+ maxHeaders=0;
+ serialNo=0;
+ }
+
+ void bos(unsigned int ser)
+ {
+ maxHeaders = 3;
+ pack.numPackets=0;
+ pack.packetSizes[0]=0;
+ pack.bodyLen = 0;
+ serialNo = ser;
+ bitrate = 0;
+ }
+
+ bool isActive() {return serialNo!=0;}
+
+ void readHeader(Channel *,OggPage &);
+
+ virtual void procHeaders(Channel *) = 0;
+
+ int bitrate;
+
+ OggPacket pack;
+ int maxHeaders;
+ unsigned int serialNo;
+};
+// ----------------------------------------------
+class OggVorbisSubStream : public OggSubStream
+{
+public:
+ OggVorbisSubStream()
+ :samplerate(0)
+ {}
+
+ virtual void procHeaders(Channel *);
+
+ void readIdent(Stream &, ChanInfo &);
+ void readSetup(Stream &);
+ void readComment(Stream &, ChanInfo &);
+
+ double getTime(OggPage &);
+
+ int samplerate;
+
+};
+// ----------------------------------------------
+class OggTheoraSubStream : public OggSubStream
+{
+public:
+ OggTheoraSubStream() : granposShift(0), frameTime(0) {}
+
+ virtual void procHeaders(Channel *);
+
+ void readInfo(Stream &, ChanInfo &);
+
+ double getTime(OggPage &);
+
+ int granposShift;
+ double frameTime;
+};
+
+// ----------------------------------------------
+class OGGStream : public ChannelStream
+{
+public:
+ OGGStream()
+ {}
+
+
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+
+ void readHeaders(Stream &,Channel *, OggPage &);
+
+ OggVorbisSubStream vorbis;
+ OggTheoraSubStream theora;
+};
+
+// ----------------------------------
+class OggPage
+{
+public:
+ enum
+ {
+ MAX_BODYLEN = 65536,
+ MAX_HEADERLEN = 27+256
+ };
+
+ void read(Stream &);
+ bool isBOS();
+ bool isEOS();
+ bool isNewPacket();
+ bool isHeader();
+ unsigned int getSerialNo();
+
+ bool detectVorbis();
+ bool detectTheora();
+
+
+ int64_t granPos;
+ int headLen,bodyLen;
+ unsigned char data[MAX_HEADERLEN+MAX_BODYLEN];
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : pcp.cpp
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "atom.h"
+#include "pcp.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------
+void PCPStream::init(GnuID &rid)
+{
+ remoteID = rid;
+ routeList.clear();
+
+ lastPacketTime = 0;
+ nextRootPacket = 0; // 0 seconds (never)
+
+ inData.init();
+ inData.accept = ChanPacket::T_PCP;
+
+ outData.init();
+ outData.accept = ChanPacket::T_PCP;
+}
+// ------------------------------------------
+void PCPStream::readVersion(Stream &in)
+{
+ int len = in.readInt();
+
+ if (len != 4)
+ throw StreamException("Invalid PCP");
+
+ int ver = in.readInt();
+
+ LOG_DEBUG("PCP ver: %d",ver);
+}
+// ------------------------------------------
+void PCPStream::readHeader(Stream &in,Channel *)
+{
+// AtomStream atom(in);
+
+// if (in.readInt() != PCP_CONNECT)
+// throw StreamException("Not PCP");
+
+// readVersion(in);
+}
+// ------------------------------------------
+bool PCPStream::sendPacket(ChanPacket &pack,GnuID &destID)
+{
+ if (destID.isSet())
+ if (!destID.isSame(remoteID))
+ if (!routeList.contains(destID))
+ return false;
+
+ return outData.writePacket(pack);
+}
+// ------------------------------------------
+void PCPStream::flush(Stream &in)
+{
+ ChanPacket pack;
+ // send outward packets
+ while (outData.numPending())
+ {
+ outData.readPacket(pack);
+ pack.writeRaw(in);
+ }
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,Channel *)
+{
+ BroadcastState bcs;
+ return readPacket(in,bcs);
+}
+// ------------------------------------------
+int PCPStream::readPacket(Stream &in,BroadcastState &bcs)
+{
+ int error = PCP_ERROR_GENERAL;
+ try
+ {
+ AtomStream atom(in);
+
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream patom(mem);
+
+
+ // send outward packets
+ error = PCP_ERROR_WRITE;
+ if (outData.numPending())
+ {
+ outData.readPacket(pack);
+ pack.writeRaw(in);
+ }
+ error = PCP_ERROR_GENERAL;
+
+ if (outData.willSkip())
+ {
+ error = PCP_ERROR_WRITE+PCP_ERROR_SKIP;
+ throw StreamException("Send too slow");
+ }
+
+
+ error = PCP_ERROR_READ;
+ // poll for new downward packet
+ if (in.readReady())
+ {
+ int numc,numd;
+ ID4 id;
+
+ id = atom.read(numc,numd);
+
+ mem.rewind();
+ pack.len = patom.writeAtoms(id, in, numc, numd);
+ pack.type = ChanPacket::T_PCP;
+
+ //inData.writePacket(pack);
+ //}
+ error = PCP_ERROR_GENERAL;
+
+ // process downward packets
+ //if (inData.numPending())
+ //{
+ //inData.readPacket(pack);
+
+ mem.rewind();
+
+ //int numc,numd;
+ id = patom.read(numc,numd);
+
+ error = PCPStream::procAtom(patom,id,numc,numd,bcs);
+
+ if (error)
+ throw StreamException("PCP exception");
+ }
+
+ error = 0;
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("PCP readPacket: %s (%d)",e.msg,error);
+ }
+
+ return error;
+}
+
+// ------------------------------------------
+void PCPStream::readEnd(Stream &,Channel *)
+{
+}
+
+
+// ------------------------------------------
+void PCPStream::readPushAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+ Host host;
+ GnuID chanID;
+
+ chanID.clear();
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_PUSH_IP)
+ host.ip = atom.readInt();
+ else if (id == PCP_PUSH_PORT)
+ host.port = atom.readShort();
+ else if (id == PCP_PUSH_CHANID)
+ atom.readBytes(chanID.id,16);
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+
+ if (bcs.forMe)
+ {
+ char ipstr[64];
+ host.toStr(ipstr);
+
+ Servent *s = NULL;
+
+ if (chanID.isSet())
+ {
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (ch)
+ if (ch->isBroadcasting() || !ch->isFull() && !servMgr->relaysFull() && ch->info.id.isSame(chanID))
+ s = servMgr->allocServent();
+ }else{
+ s = servMgr->allocServent();
+ }
+
+ if (s)
+ {
+ LOG_DEBUG("GIVing to %s",ipstr);
+ s->initGIV(host,chanID);
+ }
+ }
+
+}
+// ------------------------------------------
+void PCPStream::readRootAtoms(AtomStream &atom, int numc,BroadcastState &bcs)
+{
+ String url;
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_ROOT_UPDINT)
+ {
+ int si = atom.readInt();
+
+ chanMgr->setUpdateInterval(si);
+ LOG_DEBUG("PCP got new host update interval: %ds",si);
+ }else if (id == PCP_ROOT_URL)
+ {
+ url = "http://www.peercast.org/";
+ String loc;
+ atom.readString(loc.data,sizeof(loc.data),d);
+ url.append(loc);
+
+ }else if (id == PCP_ROOT_CHECKVER)
+ {
+ unsigned int newVer = atom.readInt();
+ if (newVer > PCP_CLIENT_VERSION)
+ {
+ strcpy(servMgr->downloadURL,url.cstr());
+ peercastApp->notifyMessage(ServMgr::NT_UPGRADE,"There is a new version available, please click here to upgrade your client.");
+ }
+ LOG_DEBUG("PCP got version check: %d / %d",newVer,PCP_CLIENT_VERSION);
+
+ }else if (id == PCP_ROOT_NEXT)
+ {
+ unsigned int time = atom.readInt();
+
+ if (time)
+ {
+ unsigned int ctime = sys->getTime();
+ nextRootPacket = ctime+time;
+ LOG_DEBUG("PCP expecting next root packet in %ds",time);
+ }else
+ {
+ nextRootPacket = 0;
+ }
+
+ }else if (id == PCP_ROOT_UPDATE)
+ {
+ atom.skip(c,d);
+
+ chanMgr->broadcastTrackerUpdate(remoteID,true);
+
+ }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
+ {
+ String newMsg;
+
+ atom.readString(newMsg.data,sizeof(newMsg.data),d);
+ if (!newMsg.isSame(servMgr->rootMsg.cstr()))
+ {
+ servMgr->rootMsg = newMsg;
+ LOG_DEBUG("PCP got new root mesg: %s",servMgr->rootMsg.cstr());
+ peercastApp->notifyMessage(ServMgr::NT_PEERCAST,servMgr->rootMsg.cstr());
+ }
+ }else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+}
+
+// ------------------------------------------
+void PCPStream::readPktAtoms(Channel *ch,AtomStream &atom,int numc,BroadcastState &bcs)
+{
+ ChanPacket pack;
+ ID4 type;
+
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_CHAN_PKT_TYPE)
+ {
+ type = atom.readID4();
+
+ if (type == PCP_CHAN_PKT_HEAD)
+ pack.type = ChanPacket::T_HEAD;
+ else if (type == PCP_CHAN_PKT_DATA)
+ pack.type = ChanPacket::T_DATA;
+ else
+ pack.type = ChanPacket::T_UNKNOWN;
+
+ }else if (id == PCP_CHAN_PKT_POS)
+ {
+ pack.pos = atom.readInt();
+
+
+ }else if (id == PCP_CHAN_PKT_DATA)
+ {
+ pack.len = d;
+ atom.readBytes(pack.data,pack.len);
+ }
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ if (ch)
+ {
+
+ int diff = pack.pos - ch->streamPos;
+ if (diff)
+ {
+ LOG_DEBUG("PCP skipping %s%8d (%10d -> %10d) count=%2d",(diff>0)?"+":"",diff,ch->streamPos,pack.pos, ch->skipCount);
+ if (ch->lastSkipTime + 120 < sys->getTime()){
+ ch->skipCount = 0;
+ }
+ ch->lastSkipTime = sys->getTime();
+ ch->skipCount++; //JP-EX
+ pack.skip = true;
+ }
+
+ if (servMgr->autoBumpSkipCount) //JP-EX
+ {
+ if (ch->skipCount > servMgr->autoBumpSkipCount)
+ {
+ LOG_DEBUG("Auto bump");
+ ch->bump = true;
+ }
+ }
+
+ if (pack.type == ChanPacket::T_HEAD)
+ {
+ LOG_DEBUG("New head packet at %d",pack.pos);
+ bool renewhead;
+ if (servMgr->keepDownstreams)
+ renewhead = (memcmp(ch->headPack.data, pack.data, pack.len) != 0);
+ else
+ renewhead = true;
+
+ /*
+ // check for stream restart
+ if (pack.pos == 0)
+ {
+ LOG_CHANNEL("PCP resetting stream");
+ ch->streamIndex++;
+ ch->rawData.init();
+ }
+ */
+ if (renewhead || ch->lastStopTime + 30 < sys->getTime()) {
+ // check for stream restart
+ if (pack.pos == 0)
+ {
+ LOG_CHANNEL("PCP resetting stream");
+ ch->streamIndex++;
+ ch->rawData.init();
+ }
+
+ ch->headPack = pack;
+
+ ch->rawData.writePacket(pack,true);
+ ch->streamPos = pack.pos+pack.len;
+ }
+
+ }else if (pack.type == ChanPacket::T_DATA)
+ {
+ ch->rawData.writePacket(pack,true);
+ ch->streamPos = pack.pos+pack.len;
+ }
+
+ }
+
+ // update this parent packet stream position
+ if ((pack.pos) && (!bcs.streamPos || (pack.pos < bcs.streamPos)))
+ bcs.streamPos = pack.pos;
+
+}
+// -----------------------------------
+void PCPStream::readHostAtoms(AtomStream &atom, int numc, BroadcastState &bcs, ChanHit &hit, bool flg)
+{
+// ChanHit hit;
+ hit.init();
+ GnuID chanID = bcs.chanID; //use default
+
+ bool busy=false;
+
+ unsigned int ipNum=0;
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_HOST_IP)
+ {
+ unsigned int ip = atom.readInt();
+ hit.rhost[ipNum].ip = ip;
+ }else if (id == PCP_HOST_PORT)
+ {
+ int port = atom.readShort();
+ hit.rhost[ipNum++].port = port;
+
+ if (ipNum > 1)
+ ipNum = 1;
+ }
+ else if (id == PCP_HOST_NUML)
+ hit.numListeners = atom.readInt();
+ else if (id == PCP_HOST_NUMR)
+ hit.numRelays = atom.readInt();
+ else if (id == PCP_HOST_UPTIME)
+ hit.upTime = atom.readInt();
+ else if (id == PCP_HOST_OLDPOS)
+ hit.oldestPos = atom.readInt();
+ else if (id == PCP_HOST_NEWPOS)
+ hit.newestPos = atom.readInt();
+ else if (id == PCP_HOST_VERSION)
+ hit.version = atom.readInt();
+ else if (id == PCP_HOST_VERSION_VP)
+ hit.version_vp = atom.readInt();
+ else if (id == PCP_HOST_VERSION_EX_PREFIX)
+ atom.readBytes(hit.version_ex_prefix,2);
+ else if (id == PCP_HOST_VERSION_EX_NUMBER){
+ hit.version_ex_number = atom.readShort();
+ }
+ else if (id == PCP_HOST_FLAGS1)
+ {
+ int fl1 = atom.readChar();
+
+ hit.recv = (fl1 & PCP_HOST_FLAGS1_RECV) !=0;
+ hit.relay = (fl1 & PCP_HOST_FLAGS1_RELAY) !=0;
+ hit.direct = (fl1 & PCP_HOST_FLAGS1_DIRECT) !=0;
+ hit.cin = (fl1 & PCP_HOST_FLAGS1_CIN) !=0;
+ hit.tracker = (fl1 & PCP_HOST_FLAGS1_TRACKER) !=0;
+ hit.firewalled = (fl1 & PCP_HOST_FLAGS1_PUSH) !=0;
+
+
+ }else if (id == PCP_HOST_ID)
+ atom.readBytes(hit.sessionID.id,16);
+ else if (id == PCP_HOST_CHANID)
+ atom.readBytes(chanID.id,16);
+ else if (id == PCP_HOST_UPHOST_IP)
+ hit.uphost.ip = atom.readInt();
+ else if (id == PCP_HOST_UPHOST_PORT)
+ hit.uphost.port = atom.readInt();
+ else if (id == PCP_HOST_UPHOST_HOPS)
+ hit.uphostHops = atom.readInt();
+ else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ hit.host = hit.rhost[0];
+ hit.chanID = chanID;
+
+ hit.numHops = bcs.numHops;
+
+ hit.servent_id = bcs.servent_id;
+
+ if (flg){
+// LOG_DEBUG("readHostAtoms HITLISTLOCK ON-------------");
+ chanMgr->hitlistlock.on();
+ if (hit.recv)
+ chanMgr->addHit(hit);
+ else
+ chanMgr->delHit(hit);
+// LOG_DEBUG("readHostAtoms HITLISTLOCK OFF-------------");
+ chanMgr->hitlistlock.off();
+ }
+
+ if (hit.numHops == 1){
+ Servent *sv = servMgr->findServentByServentID(hit.servent_id);
+ if (sv){
+// LOG_DEBUG("set servent's waitPort = %d", hit.host.port);
+ sv->waitPort = hit.host.port;
+ }
+ }
+}
+
+// ------------------------------------------
+void PCPStream::readChanAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+/* Channel *ch=NULL;
+ ChanHitList *chl=NULL;
+ ChanInfo newInfo;
+
+ ch = chanMgr->findChannelByID(bcs.chanID);
+ chl = chanMgr->findHitListByID(bcs.chanID);
+
+ if (ch)
+ newInfo = ch->info;
+ else if (chl)
+ newInfo = chl->info;*/
+
+ Channel *ch=NULL;
+ ChanHitList *chl=NULL;
+ ChanInfo newInfo, chaInfo;
+
+ ch = this->parent;
+ if (ch){
+ newInfo = ch->info;
+ chaInfo = ch->info;
+ }
+
+ for(int i=0; i<numc; i++)
+ {
+
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if ((id == PCP_CHAN_PKT) && (ch))
+ {
+ readPktAtoms(ch,atom,c,bcs);
+ }else if (id == PCP_CHAN_INFO)
+ {
+ newInfo.readInfoAtoms(atom,c);
+
+ }else if (id == PCP_CHAN_TRACK)
+ {
+ newInfo.readTrackAtoms(atom,c);
+
+ }else if (id == PCP_CHAN_BCID)
+ {
+ atom.readBytes(newInfo.bcID.id,16);
+
+ }else if (id == PCP_CHAN_KEY) // depreciated
+ {
+ atom.readBytes(newInfo.bcID.id,16);
+ newInfo.bcID.id[0] = 0; // clear flags
+
+ }else if (id == PCP_CHAN_ID)
+ {
+ atom.readBytes(newInfo.id.id,16);
+
+ ch = chanMgr->findChannelByID(newInfo.id);
+ chl = chanMgr->findHitListByID(newInfo.id);
+
+ }else
+ {
+ LOG_DEBUG("PCP skip: %s,%d,%d",id.getString().str(),c,d);
+ atom.skip(c,d);
+ }
+ }
+
+ chl = chanMgr->findHitList(newInfo);
+
+ if (!chl)
+ chl = chanMgr->addHitList(newInfo);
+
+ if (chl)
+ {
+ chl->info.update(newInfo);
+
+ if (!servMgr->chanLog.isEmpty())
+ {
+ //if (chl->numListeners())
+ {
+ try
+ {
+ FileStream file;
+ file.openWriteAppend(servMgr->chanLog.cstr());
+
+ XML::Node *rn = new XML::Node("update time=\"%d\"",sys->getTime());
+ XML::Node *n = chl->info.createChannelXML();
+ n->add(chl->createXML(false));
+ n->add(chl->info.createTrackXML());
+ rn->add(n);
+
+ rn->write(file,0);
+ delete rn;
+ file.close();
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to update channel log: %s",e.msg);
+ }
+ }
+ }
+
+ }
+
+ if (ch && !ch->isBroadcasting())
+ ch->updateInfo(newInfo);
+
+
+}
+// ------------------------------------------
+int PCPStream::readBroadcastAtoms(AtomStream &atom,int numc,BroadcastState &bcs)
+{
+ ChanPacket pack;
+ int ttl=0;
+ int ver=0;
+ int ver_vp=0;
+ GnuID fromID,destID;
+ int r=0;
+ char ver_ex_prefix[2];
+ int ver_ex_number = 0;
+
+ fromID.clear();
+ destID.clear();
+
+ bcs.initPacketSettings();
+
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream patom(pmem);
+
+ patom.writeParent(PCP_BCST,numc);
+
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 id = atom.read(c,d);
+
+ if (id == PCP_BCST_TTL)
+ {
+ ttl = atom.readChar()-1;
+ patom.writeChar(id,ttl);
+
+ }else if (id == PCP_BCST_HOPS)
+ {
+ bcs.numHops = atom.readChar()+1;
+ patom.writeChar(id,bcs.numHops);
+
+ }else if (id == PCP_BCST_FROM)
+ {
+ atom.readBytes(fromID.id,16);
+ patom.writeBytes(id,fromID.id,16);
+
+ routeList.add(fromID);
+ }else if (id == PCP_BCST_GROUP)
+ {
+ bcs.group = atom.readChar();
+ patom.writeChar(id,bcs.group);
+ }else if (id == PCP_BCST_DEST)
+ {
+ atom.readBytes(destID.id,16);
+ patom.writeBytes(id,destID.id,16);
+ bcs.forMe = destID.isSame(servMgr->sessionID);
+
+ char idstr1[64];
+ char idstr2[64];
+
+ destID.toStr(idstr1);
+ servMgr->sessionID.toStr(idstr2);
+
+ }else if (id == PCP_BCST_CHANID)
+ {
+ atom.readBytes(bcs.chanID.id,16);
+ patom.writeBytes(id,bcs.chanID.id,16);
+ }else if (id == PCP_BCST_VERSION)
+ {
+ ver = atom.readInt();
+ patom.writeInt(id,ver);
+ }else if (id == PCP_BCST_VERSION_VP)
+ {
+ ver_vp = atom.readInt();
+ patom.writeInt(id,ver_vp);
+ }else if (id == PCP_BCST_VERSION_EX_PREFIX)
+ {
+ atom.readBytes(ver_ex_prefix,2);
+ patom.writeBytes(id,ver_ex_prefix,2);
+ }else if (id == PCP_BCST_VERSION_EX_NUMBER)
+ {
+ ver_ex_number = atom.readShort();
+ patom.writeShort(id,ver_ex_number);
+ }else if (id == PCP_HOST)
+ {
+ ChanHit hit;
+ readHostAtoms(atom,c,bcs,hit,false);
+ if (hit.uphost.ip == 0){
+// LOG_DEBUG("bcs servent_id = %d", bcs.servent_id);
+ if (bcs.numHops == 1){
+ hit.uphost.ip = servMgr->serverHost.ip;
+ hit.uphost.port = servMgr->serverHost.port;
+ hit.uphostHops = 1;
+ } else {
+ Servent *sv = servMgr->findServentByServentID(bcs.servent_id);
+ if (sv){
+ hit.uphost.ip = sv->getHost().ip;
+ hit.uphost.port = sv->waitPort;
+ hit.uphostHops = bcs.numHops - 1;
+ }
+ }
+ }
+ int oldPos = pmem.pos;
+ hit.writeAtoms(patom, hit.chanID);
+ pmem.pos = oldPos;
+ r = readAtom(patom,bcs);
+ } else {
+ // copy and process atoms
+ int oldPos = pmem.pos;
+ patom.writeAtoms(id,atom.io,c,d);
+ pmem.pos = oldPos;
+ r = readAtom(patom,bcs);
+ }
+ }
+
+ char fromStr[64];
+ fromStr[0] = 0;
+ if (fromID.isSet())
+ fromID.toStr(fromStr);
+ char destStr[64];
+ destStr[0] = 0;
+ if (destID.isSet())
+ destID.toStr(destStr);
+ char tmp[64];
+ bcs.chanID.toStr(tmp);
+
+// LOG_DEBUG(tmp);
+
+ if (ver_ex_number){
+ LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d(%c%c%04d), from=%s, dest=%s ttl=%d",
+ bcs.group,bcs.numHops,ver,ver_ex_prefix[0],ver_ex_prefix[1],ver_ex_number,fromStr,destStr,ttl);
+ } else if (ver_vp){
+ 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);
+ } else {
+ LOG_DEBUG("PCP bcst: group=%d, hops=%d, ver=%d, from=%s, dest=%s ttl=%d",bcs.group,bcs.numHops,ver,fromStr,destStr,ttl);
+ }
+
+ if (fromID.isSet())
+ if (fromID.isSame(servMgr->sessionID))
+ {
+ LOG_ERROR("BCST loopback");
+ return PCP_ERROR_BCST+PCP_ERROR_LOOPBACK;
+ }
+
+ // broadcast back out if ttl > 0
+ if ((ttl>0) && (!bcs.forMe))
+ {
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+ if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+ {
+ chanMgr->broadcastPacketUp(pack,bcs.chanID,remoteID,destID);
+ }
+
+ if (bcs.group & (/*PCP_BCST_GROUP_ROOT|*/PCP_BCST_GROUP_TRACKERS|PCP_BCST_GROUP_RELAYS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_COUT);
+ }
+
+ if (bcs.group & (PCP_BCST_GROUP_RELAYS|PCP_BCST_GROUP_TRACKERS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_CIN);
+ }
+
+ if (bcs.group & (PCP_BCST_GROUP_RELAYS))
+ {
+ servMgr->broadcastPacket(pack,bcs.chanID,remoteID,destID,Servent::T_RELAY);
+ }
+
+
+// LOG_DEBUG("ttl=%d",ttl);
+
+ } else {
+// LOG_DEBUG("ttl=%d",ttl);
+ }
+ return r;
+}
+
+
+// ------------------------------------------
+int PCPStream::procAtom(AtomStream &atom,ID4 id,int numc, int dlen,BroadcastState &bcs)
+{
+ int r=0;
+ ChanHit hit;
+ int rBan = 0;
+
+ if (id == PCP_CHAN)
+ {
+ readChanAtoms(atom,numc,bcs);
+ }else if (id == PCP_ROOT)
+ {
+ if (servMgr->isRoot)
+ throw StreamException("Unauthorized root message");
+ else
+ readRootAtoms(atom,numc,bcs);
+
+ }else if (id == PCP_HOST)
+ {
+ readHostAtoms(atom,numc,bcs,hit);
+ Channel *ch = chanMgr->findChannelByID(hit.chanID);
+ if (ch && (ch->isBroadcasting() || servMgr->vpDebug)){
+ if (servMgr->autoPort0Kick && (hit.numHops == 1) && (hit.firewalled || (!hit.relay && !hit.numRelays))){
+ char tmp[32];
+ hit.host.IPtoStr(tmp);
+ LOG_DEBUG("host that can't relay is disconnect: %s", tmp);
+ rBan = PCP_ERROR_BANNED;
+ }
+ if (servMgr->allowOnlyVP && (hit.numHops == 1) && !hit.version_vp){
+ char tmp[32];
+ hit.host.IPtoStr(tmp);
+ LOG_DEBUG("host that is not VP is disconnect: %s", tmp);
+ rBan = PCP_ERROR_BANNED;
+ }
+ }
+
+ }else if ((id == PCP_MESG_ASCII) || (id == PCP_MESG)) // PCP_MESG_ASCII to be depreciated
+ {
+ String msg;
+ atom.readString(msg.data,sizeof(msg.data),dlen);
+ LOG_DEBUG("PCP got text: %s",msg.cstr());
+ }else if (id == PCP_BCST)
+ {
+ r = readBroadcastAtoms(atom,numc,bcs);
+ }else if (id == PCP_HELO)
+ {
+ atom.skip(numc,dlen);
+ atom.writeParent(PCP_OLEH,1);
+ atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ }else if (id == PCP_PUSH)
+ {
+
+ readPushAtoms(atom,numc,bcs);
+ }else if (id == PCP_OK)
+ {
+ atom.readInt();
+
+ }else if (id == PCP_QUIT)
+ {
+ r = atom.readInt();
+ if (!r)
+ r = PCP_ERROR_QUIT;
+
+ }else if (id == PCP_ATOM)
+ {
+ for(int i=0; i<numc; i++)
+ {
+ int nc,nd;
+ ID4 aid = atom.read(nc,nd);
+ int ar = procAtom(atom,aid,nc,nd,bcs);
+ if (ar)
+ r = ar;
+ }
+
+ }else
+ {
+ LOG_CHANNEL("PCP skip: %s",id.getString().str());
+ atom.skip(numc,dlen);
+ }
+
+ if (!r)
+ r = rBan;
+
+ return r;
+
+}
+
+// ------------------------------------------
+int PCPStream::readAtom(AtomStream &atom,BroadcastState &bcs)
+{
+ int numc,dlen;
+ ID4 id = atom.read(numc,dlen);
+
+ return procAtom(atom,id,numc,dlen,bcs);
+}
+
+
--- /dev/null
+// ------------------------------------------------
+// File : pcp.h
+// Date: 1-mar-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _PCP_H
+#define _PCP_H
+
+// ------------------------------------------------
+
+
+#include "id.h"
+#include "cstream.h"
+#include "channel.h"
+
+// ------------------------------------------------
+
+class Servent;
+
+
+// ------------------------------------------------
+
+static const ID4 PCP_CONNECT = "pcp\n";
+
+static const ID4 PCP_OK = "ok";
+
+static const ID4 PCP_HELO = "helo";
+static const ID4 PCP_HELO_AGENT = "agnt";
+static const ID4 PCP_HELO_OSTYPE = "ostp";
+static const ID4 PCP_HELO_SESSIONID = "sid";
+static const ID4 PCP_HELO_PORT = "port";
+static const ID4 PCP_HELO_PING = "ping";
+static const ID4 PCP_HELO_PONG = "pong";
+static const ID4 PCP_HELO_REMOTEIP = "rip";
+static const ID4 PCP_HELO_VERSION = "ver";
+static const ID4 PCP_HELO_BCID = "bcid";
+static const ID4 PCP_HELO_DISABLE = "dis";
+
+static const ID4 PCP_OLEH = "oleh";
+
+static const ID4 PCP_MODE = "mode";
+static const ID4 PCP_MODE_GNUT06 = "gn06";
+
+static const ID4 PCP_ROOT = "root";
+static const ID4 PCP_ROOT_UPDINT = "uint";
+static const ID4 PCP_ROOT_CHECKVER = "chkv";
+static const ID4 PCP_ROOT_URL = "url";
+static const ID4 PCP_ROOT_UPDATE = "upd";
+static const ID4 PCP_ROOT_NEXT = "next";
+
+
+static const ID4 PCP_OS_LINUX = "lnux";
+static const ID4 PCP_OS_WINDOWS = "w32";
+static const ID4 PCP_OS_OSX = "osx";
+static const ID4 PCP_OS_WINAMP = "wamp";
+static const ID4 PCP_OS_ZAURUS = "zaur";
+
+static const ID4 PCP_GET = "get";
+static const ID4 PCP_GET_ID = "id";
+static const ID4 PCP_GET_NAME = "name";
+
+static const ID4 PCP_HOST = "host";
+static const ID4 PCP_HOST_ID = "id";
+static const ID4 PCP_HOST_IP = "ip";
+static const ID4 PCP_HOST_PORT = "port";
+static const ID4 PCP_HOST_NUML = "numl";
+static const ID4 PCP_HOST_NUMR = "numr";
+static const ID4 PCP_HOST_UPTIME = "uptm";
+static const ID4 PCP_HOST_TRACKER = "trkr";
+static const ID4 PCP_HOST_CHANID = "cid";
+static const ID4 PCP_HOST_VERSION = "ver";
+static const ID4 PCP_HOST_VERSION_VP = "vevp";
+static const ID4 PCP_HOST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_HOST_VERSION_EX_NUMBER = "vexn";
+static const ID4 PCP_HOST_FLAGS1 = "flg1";
+static const ID4 PCP_HOST_OLDPOS = "oldp";
+static const ID4 PCP_HOST_NEWPOS = "newp";
+static const ID4 PCP_HOST_UPHOST_IP = "upip";
+static const ID4 PCP_HOST_UPHOST_PORT = "uppt";
+static const ID4 PCP_HOST_UPHOST_HOPS = "uphp";
+
+static const ID4 PCP_QUIT = "quit";
+
+static const ID4 PCP_CHAN = "chan";
+static const ID4 PCP_CHAN_ID = "id";
+static const ID4 PCP_CHAN_BCID = "bcid";
+static const ID4 PCP_CHAN_KEY = "key";
+
+static const ID4 PCP_CHAN_PKT = "pkt";
+static const ID4 PCP_CHAN_PKT_TYPE = "type";
+static const ID4 PCP_CHAN_PKT_POS = "pos";
+static const ID4 PCP_CHAN_PKT_HEAD = "head";
+static const ID4 PCP_CHAN_PKT_DATA = "data";
+static const ID4 PCP_CHAN_PKT_META = "meta";
+
+static const ID4 PCP_CHAN_INFO = "info";
+static const ID4 PCP_CHAN_INFO_TYPE = "type";
+static const ID4 PCP_CHAN_INFO_BITRATE = "bitr";
+static const ID4 PCP_CHAN_INFO_GENRE = "gnre";
+static const ID4 PCP_CHAN_INFO_NAME = "name";
+static const ID4 PCP_CHAN_INFO_URL = "url";
+static const ID4 PCP_CHAN_INFO_DESC = "desc";
+static const ID4 PCP_CHAN_INFO_COMMENT = "cmnt";
+
+static const ID4 PCP_CHAN_TRACK = "trck";
+static const ID4 PCP_CHAN_TRACK_TITLE = "titl";
+static const ID4 PCP_CHAN_TRACK_CREATOR = "crea";
+static const ID4 PCP_CHAN_TRACK_URL = "url";
+static const ID4 PCP_CHAN_TRACK_ALBUM = "albm";
+
+static const ID4 PCP_MESG = "mesg";
+static const ID4 PCP_MESG_ASCII = "asci"; // ascii/sjis to be depreciated.. utf8/unicode is the only supported format from now.
+static const ID4 PCP_MESG_SJIS = "sjis";
+
+static const ID4 PCP_BCST = "bcst";
+static const ID4 PCP_BCST_TTL = "ttl";
+static const ID4 PCP_BCST_HOPS = "hops";
+static const ID4 PCP_BCST_FROM = "from";
+static const ID4 PCP_BCST_DEST = "dest";
+static const ID4 PCP_BCST_GROUP = "grp";
+static const ID4 PCP_BCST_CHANID = "cid";
+static const ID4 PCP_BCST_VERSION = "vers";
+static const ID4 PCP_BCST_VERSION_VP = "vrvp";
+static const ID4 PCP_BCST_VERSION_EX_PREFIX = "vexp";
+static const ID4 PCP_BCST_VERSION_EX_NUMBER = "vexn";
+
+static const ID4 PCP_PUSH = "push";
+static const ID4 PCP_PUSH_IP = "ip";
+static const ID4 PCP_PUSH_PORT = "port";
+static const ID4 PCP_PUSH_CHANID = "cid";
+
+static const ID4 PCP_SPKT = "spkt";
+
+static const ID4 PCP_ATOM = "atom";
+
+static const ID4 PCP_SESSIONID = "sid";
+
+static const int PCP_BCST_GROUP_ALL = (char)0xff;
+static const int PCP_BCST_GROUP_ROOT = 1;
+static const int PCP_BCST_GROUP_TRACKERS = 2;
+static const int PCP_BCST_GROUP_RELAYS = 4;
+
+
+static const int PCP_ERROR_QUIT = 1000;
+static const int PCP_ERROR_BCST = 2000;
+static const int PCP_ERROR_READ = 3000;
+static const int PCP_ERROR_WRITE = 4000;
+static const int PCP_ERROR_GENERAL = 5000;
+
+static const int PCP_ERROR_SKIP = 1;
+static const int PCP_ERROR_ALREADYCONNECTED = 2;
+static const int PCP_ERROR_UNAVAILABLE = 3;
+static const int PCP_ERROR_LOOPBACK = 4;
+static const int PCP_ERROR_NOTIDENTIFIED = 5;
+static const int PCP_ERROR_BADRESPONSE = 6;
+static const int PCP_ERROR_BADAGENT = 7;
+static const int PCP_ERROR_OFFAIR = 8;
+static const int PCP_ERROR_SHUTDOWN = 9;
+static const int PCP_ERROR_NOROOT = 10;
+static const int PCP_ERROR_BANNED = 11;
+
+static const int PCP_HOST_FLAGS1_TRACKER = 0x01;
+static const int PCP_HOST_FLAGS1_RELAY = 0x02;
+static const int PCP_HOST_FLAGS1_DIRECT = 0x04;
+static const int PCP_HOST_FLAGS1_PUSH = 0x08;
+static const int PCP_HOST_FLAGS1_RECV = 0x10;
+static const int PCP_HOST_FLAGS1_CIN = 0x20;
+static const int PCP_HOST_FLAGS1_PRIVATE = 0x40;
+
+
+// ----------------------------------------------
+class BroadcastState
+{
+public:
+ BroadcastState()
+ :numHops(0)
+ ,forMe(false)
+ ,streamPos(0)
+ ,group(0)
+ ,servent_id(0)
+ {
+ chanID.clear();
+ bcID.clear();
+ }
+
+
+ void initPacketSettings()
+ {
+ forMe = false;
+ group = 0;
+ numHops = 0;
+ bcID.clear();
+ chanID.clear();
+ }
+
+
+ GnuID chanID,bcID;
+ int numHops;
+ bool forMe;
+ unsigned int streamPos;
+ int group;
+ int servent_id;
+};
+
+// ----------------------------------------------
+class PCPStream : public ChannelStream
+{
+public:
+ PCPStream(GnuID &rid)
+ :routeList(1000)
+ {
+ init(rid);
+ }
+
+ void init(GnuID &);
+
+ virtual void kill()
+ {
+ inData.lock.on();
+ outData.lock.on();
+ }
+
+ virtual bool sendPacket(ChanPacket &,GnuID &);
+ virtual void flush(Stream &);
+ virtual void readHeader(Stream &,Channel *);
+ virtual int readPacket(Stream &,Channel *);
+ virtual void readEnd(Stream &,Channel *);
+
+ int readPacket(Stream &,BroadcastState &);
+ void flushOutput(Stream &in,BroadcastState &);
+ static void readVersion(Stream &);
+
+ int procAtom(AtomStream &,ID4,int,int,BroadcastState &);
+ int readAtom(AtomStream &,BroadcastState &);
+ void readChanAtoms(AtomStream &,int,BroadcastState &);
+// void readHostAtoms(AtomStream &, int, BroadcastState &);
+ void readHostAtoms(AtomStream &, int, BroadcastState &, ChanHit &, bool flg=true);
+ void readPushAtoms(AtomStream &, int,BroadcastState &);
+
+ void readPktAtoms(Channel *,AtomStream &,int,BroadcastState &);
+ void readRootAtoms(AtomStream &, int,BroadcastState &);
+
+ int readBroadcastAtoms(AtomStream &,int,BroadcastState &);
+
+ ChanPacketBuffer inData,outData;
+ unsigned int lastPacketTime;
+ unsigned int nextRootPacket;
+
+ //int error;
+ GnuIDList routeList;
+ GnuID remoteID;
+
+};
+
+#endif
--- /dev/null
+#include "sys.h"
+#include "peercast.h"
+#include "channel.h"
+#include "servmgr.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+
+// ---------------------------------
+// globals
+
+Sys *sys=NULL;
+ChanMgr *chanMgr;
+ServMgr *servMgr;
+
+PeercastInstance *peercastInst=NULL;
+PeercastApplication *peercastApp=NULL;
+
+
+// ---------------------------------
+void APICALL PeercastInstance::init()
+{
+ sys = createSys();
+ servMgr = new ServMgr();
+ chanMgr = new ChanMgr();
+
+ if (peercastApp->getIniFilename())
+ servMgr->loadSettings(peercastApp->getIniFilename());
+
+ servMgr->start();
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setNotifyMask(int mask)
+{
+ if (servMgr)
+ servMgr->notifyMask = mask;
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getNotifyMask()
+{
+ if (servMgr)
+ return servMgr->notifyMask;
+ else
+ return 0;
+}
+
+// --------------------------------------------------
+void APICALL PeercastInstance::setAutoConnect(bool on)
+{
+ if (servMgr)
+ servMgr->autoConnect = on;
+}
+// --------------------------------------------------
+bool APICALL PeercastInstance::getAutoConnect()
+{
+ if (servMgr)
+ return servMgr->autoConnect;
+ else
+ return false;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setMaxOutput(int kbps)
+{
+ if (servMgr)
+ servMgr->maxBitrateOut = kbps;
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getMaxOutput()
+{
+ if (servMgr)
+ return servMgr->maxBitrateOut;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setMaxRelays(int max)
+{
+ if (servMgr)
+ servMgr->setMaxRelays(max);
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getMaxRelays()
+{
+ if (servMgr)
+ return servMgr->maxRelays;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setActive(bool on)
+{
+ if (servMgr)
+ {
+ servMgr->autoConnect = on;
+ servMgr->autoServe = on;
+ }
+}
+// --------------------------------------------------
+bool APICALL PeercastInstance::getActive()
+{
+ if (servMgr)
+ return servMgr->autoConnect&&servMgr->autoServe;
+ else
+ return false;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::saveSettings()
+{
+ if (servMgr)
+ servMgr->saveSettings(peercastApp->getIniFilename());
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::quit()
+{
+ isQuitting = true;
+ if (chanMgr)
+ chanMgr->quit();
+ if (servMgr)
+ servMgr->quit();
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setServerPort(int port)
+{
+ if (servMgr)
+ {
+ servMgr->serverHost.port = port;
+ servMgr->restartServer = true;
+ }
+}
+// --------------------------------------------------
+int APICALL PeercastInstance::getServerPort()
+{
+ if (servMgr)
+ return servMgr->serverHost.port;
+ else
+ return 0;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::setServerPassword(const char *pwd)
+{
+ if (servMgr)
+ strcpy(servMgr->password,pwd);
+}
+// --------------------------------------------------
+const char *APICALL PeercastInstance::getServerPassword()
+{
+ return servMgr->password;
+}
+// --------------------------------------------------
+void APICALL PeercastInstance::callLocalURL(const char *url)
+{
+ if (sys && servMgr)
+ sys->callLocalURL(url,servMgr->serverHost.port);
+}
+
+
+// --------------------------------------------------
+void ADDLOG(const char *fmt,va_list ap,LogBuffer::TYPE type)
+{
+ if(sys)
+ {
+ const int MAX_LINELEN = 1024;
+
+ char str[MAX_LINELEN+1];
+ vsnprintf(str,MAX_LINELEN-1,fmt,ap);
+ str[MAX_LINELEN-1]=0;
+
+ if (type != LogBuffer::T_NONE)
+ sys->logBuf->write(str,type);
+
+ peercastApp->printLog(type,str);
+ }
+}
+// --------------------------------------------------
+void LOG(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+ va_end(ap);
+}
+
+// --------------------------------------------------
+void LOG_ERROR(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_ERROR)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_ERROR);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_DEBUG(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_DEBUG)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_DEBUG);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_NETWORK(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_NETWORK)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_NETWORK);
+ va_end(ap);
+ }
+ }
+}
+// --------------------------------------------------
+void LOG_CHANNEL(const char *fmt,...)
+{
+ if (servMgr)
+ {
+ if ((servMgr->showLog & (1<<LogBuffer::T_CHANNEL)) && (!servMgr->pauseLog))
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ ADDLOG(fmt,ap,LogBuffer::T_CHANNEL);
+ va_end(ap);
+ }
+ }
+}
--- /dev/null
+#ifndef _PEERCAST_H
+#define _PEERCAST_H
+
+
+//#define APICALL _stdcall
+#ifdef WIN32
+#define APICALL _cdecl
+#else
+#define APICALL
+#endif
+
+
+class ChanInfo;
+class Sys;
+
+#include "servmgr.h"
+
+
+// ------------------------------------------------------------
+// This is the interface from the application to the core.
+class PeercastInstance
+{
+public:
+ PeercastInstance()
+ :isQuitting(false)
+ {}
+
+ virtual void APICALL init();
+
+ virtual void APICALL setAutoConnect(bool);
+ virtual bool APICALL getAutoConnect();
+
+ virtual void APICALL setActive(bool);
+ virtual bool APICALL getActive();
+
+ virtual int APICALL getMaxOutput();
+ virtual void APICALL setMaxOutput(int);
+
+ virtual int APICALL getMaxRelays();
+ virtual void APICALL setMaxRelays(int);
+
+ virtual void APICALL setServerPort(int);
+ virtual int APICALL getServerPort();
+ virtual void APICALL setServerPassword(const char *);
+ virtual const char *APICALL getServerPassword();
+
+ virtual void APICALL saveSettings();
+
+ virtual void APICALL callLocalURL(const char *);
+
+ virtual void APICALL setNotifyMask(int);
+ virtual int APICALL getNotifyMask();
+
+ virtual void APICALL quit();
+
+ virtual Sys * APICALL createSys()=0;
+
+ bool isQuitting;
+
+};
+// ------------------------------------------------------------
+// This is the interface from the core to the application.
+class PeercastApplication
+{
+public:
+
+ virtual const char * APICALL getPath() {return "./";}
+ virtual const char * APICALL getIniFilename() {return "peercast.ini";}
+ virtual bool APICALL clearTemp() { return false; } //JP-EX
+ virtual void APICALL openLogFile() {} //JP-EX
+ virtual void APICALL getDirectory() {} //JP-EX
+ virtual void APICALL printLog(LogBuffer::TYPE, const char *) {}
+ virtual void APICALL addChannel(ChanInfo *) {}
+ virtual void APICALL delChannel(ChanInfo *) {}
+ virtual void APICALL resetChannels() {}
+ virtual void APICALL test(char *) {}
+ virtual const char *APICALL getClientTypeOS() = 0;
+ virtual void APICALL updateSettings() {}
+
+ virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *) {}
+ virtual void APICALL channelStart(ChanInfo *) {}
+ virtual void APICALL channelStop(ChanInfo *) {}
+ virtual void APICALL channelUpdate(ChanInfo *) {}
+};
+
+
+// ----------------------------------
+extern PeercastInstance *peercastInst;
+extern PeercastApplication *peercastApp;
+
+// ----------------------------------
+#ifdef WIN32
+extern "C"
+{
+__declspec( dllexport ) PeercastInstance * newPeercast(PeercastApplication *);
+};
+#endif
+
+// ----------------------------------
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : rtsp.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// RTSP protocol handling (experimental)
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "rtsp.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : rtsp.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _RTSP_H
+#define _RTSP_H
+
+#include "http.h"
+
+// ---------------------------------------------
+class RTSP : public HTTP
+{
+public:
+ RTSP(Stream &s):HTTP(s){}
+};
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : servent.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Servents are the actual connections between clients. They do the handshaking,
+// transfering of data and processing of GnuPackets. Each servent has one socket allocated
+// to it on connect, it uses this to transfer all of its data.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+// todo: make lan->yp not check firewall
+
+#include <stdlib.h>
+#include "servent.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "xml.h"
+#include "html.h"
+#include "http.h"
+#include "stats.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "atom.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+const int DIRECT_WRITE_TIMEOUT = 60;
+
+// -----------------------------------
+char *Servent::statusMsgs[]=
+{
+ "NONE",
+ "CONNECTING",
+ "PROTOCOL",
+ "HANDSHAKE",
+ "CONNECTED",
+ "CLOSING",
+ "LISTENING",
+ "TIMEOUT",
+ "REFUSED",
+ "VERIFIED",
+ "ERROR",
+ "WAIT",
+ "FREE"
+};
+
+// -----------------------------------
+char *Servent::typeMsgs[]=
+{
+ "NONE",
+ "INCOMING",
+ "SERVER",
+ "RELAY",
+ "DIRECT",
+ "COUT",
+ "CIN",
+ "PGNU"
+};
+// -----------------------------------
+bool Servent::isPrivate()
+{
+ Host h = getHost();
+ return servMgr->isFiltered(ServFilter::F_PRIVATE,h) || h.isLocalhost();
+}
+// -----------------------------------
+bool Servent::isAllowed(int a)
+{
+ Host h = getHost();
+
+ if (servMgr->isFiltered(ServFilter::F_BAN,h))
+ return false;
+
+ return (allow&a)!=0;
+}
+
+// -----------------------------------
+bool Servent::isFiltered(int f)
+{
+ Host h = getHost();
+ return servMgr->isFiltered(f,h);
+}
+
+int servent_count = 1;
+// -----------------------------------
+Servent::Servent(int index)
+:outPacketsPri(MAX_OUTPACKETS)
+,outPacketsNorm(MAX_OUTPACKETS)
+,seenIDs(MAX_HASH)
+,serventIndex(index)
+,sock(NULL)
+,next(NULL)
+{
+ reset();
+ servent_id = servent_count++;
+ lastSkipTime = 0;
+ lastSkipCount = 0;
+ waitPort = 0;
+}
+
+// -----------------------------------
+Servent::~Servent()
+{
+
+}
+// -----------------------------------
+void Servent::kill()
+{
+ thread.active = false;
+
+ setStatus(S_CLOSING);
+
+ if (pcpStream)
+ {
+ PCPStream *pcp = pcpStream;
+ pcpStream = NULL;
+ pcp->kill();
+ delete pcp;
+ }
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = chanMgr->findHitListByID(chanID);
+ if (chl) {
+ ChanHit *chh = chl->hit;
+ ChanHit *prev = NULL;
+ while (chh) {
+ if (chh->servent_id == this->servent_id){
+ if ((servMgr->kickKeepTime != 0) && (chh->firewalled == 1)){
+ chh->numHops = 0;
+ chh->numListeners = 0;
+ chh->numRelays = 0;
+ prev = chh;
+ chh = chh->next;
+ } else {
+ ChanHit *next = chh->next;
+ if (prev)
+ prev->next = next;
+ else
+ chl->hit = next;
+
+ char ip0str[64],ip1str[64];
+ chh->rhost[0].toStr(ip0str);
+ chh->rhost[1].toStr(ip1str);
+ LOG_DEBUG("Delete hit (servent_id=%d): F%dT%dR%d %s/%s",
+ chh->servent_id,chh->firewalled,chh->tracker,chh->relay,ip0str,ip1str);
+
+ delete chh;
+ chh = next;
+ }
+ } else {
+ prev = chh;
+ chh = chh->next;
+ }
+ }
+ }
+ chanMgr->hitlistlock.off();
+
+ if (sock)
+ {
+ sock->close();
+ delete sock;
+ sock = NULL;
+ }
+
+ if (pushSock)
+ {
+ pushSock->close();
+ delete pushSock;
+ pushSock = NULL;
+ }
+
+// thread.unlock();
+
+ if (type != T_SERVER)
+ {
+ reset();
+ setStatus(S_FREE);
+ }
+
+}
+// -----------------------------------
+void Servent::abort()
+{
+ thread.active = false;
+ if (sock)
+ {
+ sock->close();
+ }
+
+}
+
+// -----------------------------------
+void Servent::reset()
+{
+
+ remoteID.clear();
+
+ servPort = 0;
+
+ pcpStream = NULL;
+
+ flowControl = false;
+ networkID.clear();
+
+ chanID.clear();
+
+ outputProtocol = ChanInfo::SP_UNKNOWN;
+
+ agent.clear();
+ sock = NULL;
+ allow = ALLOW_ALL;
+ syncPos = 0;
+ addMetadata = false;
+ nsSwitchNum = 0;
+ pack.func = 255;
+ lastConnect = lastPing = lastPacket = 0;
+ loginPassword[0] = 0;
+ loginMount[0] = 0;
+ bytesPerSecond = 0;
+ priorityConnect = false;
+ pushSock = NULL;
+ sendHeader = true;
+
+ outPacketsNorm.reset();
+ outPacketsPri.reset();
+
+ seenIDs.clear();
+
+ status = S_NONE;
+ type = T_NONE;
+
+ channel_id = 0;
+}
+// -----------------------------------
+bool Servent::sendPacket(ChanPacket &pack,GnuID &cid,GnuID &sid,GnuID &did,Servent::TYPE t)
+{
+
+ if ( (type == t)
+ && (isConnected())
+ && (!cid.isSet() || chanID.isSame(cid))
+ && (!sid.isSet() || !sid.isSame(remoteID))
+ && (pcpStream != NULL)
+ )
+ {
+ return pcpStream->sendPacket(pack,did);
+ }
+ return false;
+}
+
+
+// -----------------------------------
+bool Servent::acceptGIV(ClientSocket *givSock)
+{
+ if (!pushSock)
+ {
+ pushSock = givSock;
+ return true;
+ }else
+ return false;
+}
+
+// -----------------------------------
+Host Servent::getHost()
+{
+ Host h(0,0);
+
+ if (sock)
+ h = sock->host;
+
+ return h;
+}
+
+// -----------------------------------
+bool Servent::outputPacket(GnuPacket &p, bool pri)
+{
+ lock.on();
+
+ bool r=false;
+ if (pri)
+ r = outPacketsPri.write(p);
+ else
+ {
+ if (servMgr->useFlowControl)
+ {
+ int per = outPacketsNorm.percentFull();
+ if (per > 50)
+ flowControl = true;
+ else if (per < 25)
+ flowControl = false;
+ }
+
+
+ bool send=true;
+ if (flowControl)
+ {
+ // if in flowcontrol, only allow packets with less of a hop count than already in queue
+ if (p.hops >= outPacketsNorm.findMinHop())
+ send = false;
+ }
+
+ if (send)
+ r = outPacketsNorm.write(p);
+ }
+
+ lock.off();
+ return r;
+}
+
+// -----------------------------------
+bool Servent::initServer(Host &h)
+{
+ try
+ {
+ checkFree();
+
+ status = S_WAIT;
+
+ createSocket();
+
+ sock->bind(h);
+
+ thread.data = this;
+
+ thread.func = serverProc;
+
+ type = T_SERVER;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Bad server: %s",e.msg);
+ kill();
+ return false;
+ }
+
+ return true;
+}
+// -----------------------------------
+void Servent::checkFree()
+{
+ if (sock)
+ throw StreamException("Socket already set");
+ if (thread.active)
+ throw StreamException("Thread already active");
+}
+// -----------------------------------
+void Servent::initIncoming(ClientSocket *s, unsigned int a)
+{
+
+ try{
+
+ checkFree();
+
+ type = T_INCOMING;
+ sock = s;
+ allow = a;
+ thread.data = this;
+ thread.func = incomingProc;
+
+ setStatus(S_PROTOCOL);
+
+ char ipStr[64];
+ sock->host.toStr(ipStr);
+ LOG_DEBUG("Incoming from %s",ipStr);
+
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+ }catch(StreamException &e)
+ {
+ //LOG_ERROR("!!FATAL!! Incoming error: %s",e.msg);
+ //servMgr->shutdownTimer = 1;
+ kill();
+
+ LOG_ERROR("INCOMING FAILED: %s",e.msg);
+
+ }
+}
+
+// -----------------------------------
+void Servent::initOutgoing(TYPE ty)
+{
+ try
+ {
+ checkFree();
+
+
+ type = ty;
+
+ thread.data = this;
+ thread.func = outgoingProc;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to start outgoing: %s",e.msg);
+ kill();
+ }
+}
+
+// -----------------------------------
+void Servent::initPCP(Host &rh)
+{
+ char ipStr[64];
+ rh.toStr(ipStr);
+ try
+ {
+ checkFree();
+
+ createSocket();
+
+ type = T_COUT;
+
+ sock->open(rh);
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw StreamException("Servent not allowed");
+
+ thread.data = this;
+ thread.func = outgoingProc;
+
+ LOG_DEBUG("Outgoing to %s",ipStr);
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Unable to open connection to %s - %s",ipStr,e.msg);
+ kill();
+ }
+}
+
+#if 0
+// -----------------------------------
+void Servent::initChannelFetch(Host &host)
+{
+ type = T_STREAM;
+
+ char ipStr[64];
+ host.toStr(ipStr);
+
+ checkFree();
+
+ createSocket();
+
+ sock->open(host);
+
+
+ if (!isAllowed(ALLOW_DATA))
+ throw StreamException("Servent not allowed");
+
+ sock->connect();
+}
+#endif
+
+// -----------------------------------
+void Servent::initGIV(Host &h, GnuID &id)
+{
+ char ipStr[64];
+ h.toStr(ipStr);
+ try
+ {
+ checkFree();
+
+ givID = id;
+
+ createSocket();
+
+ sock->open(h);
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw StreamException("Servent not allowed");
+
+ sock->connect();
+
+ thread.data = this;
+ thread.func = givProc;
+
+ type = T_RELAY;
+
+ if (!sys->startThread(&thread))
+ throw StreamException("Can`t start thread");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("GIV error to %s: %s",ipStr,e.msg);
+ kill();
+ }
+}
+// -----------------------------------
+void Servent::createSocket()
+{
+ if (sock)
+ LOG_ERROR("Servent::createSocket attempt made while active");
+
+ sock = sys->createSocket();
+}
+// -----------------------------------
+void Servent::setStatus(STATUS s)
+{
+ if (s != status)
+ {
+ status = s;
+
+ if ((s == S_HANDSHAKE) || (s == S_CONNECTED) || (s == S_LISTENING))
+ lastConnect = sys->getTime();
+ }
+
+}
+
+// -----------------------------------
+void Servent::handshakeOut()
+{
+ sock->writeLine(GNU_PEERCONN);
+
+ char str[64];
+
+ sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+ sock->writeLineF("%s %d",PCX_HS_PCP,1);
+
+ if (priorityConnect)
+ sock->writeLineF("%s %d",PCX_HS_PRIORITY,1);
+
+ if (networkID.isSet())
+ {
+ networkID.toStr(str);
+ sock->writeLineF("%s %s",PCX_HS_NETWORKID,str);
+ }
+
+ servMgr->sessionID.toStr(str);
+ sock->writeLineF("%s %s",PCX_HS_ID,str);
+
+
+ sock->writeLineF("%s %s",PCX_HS_OS,peercastApp->getClientTypeOS());
+
+ sock->writeLine("");
+
+ HTTP http(*sock);
+
+ int r = http.readResponse();
+
+ if (r != 200)
+ {
+ LOG_ERROR("Expected 200, got %d",r);
+ throw StreamException("Unexpected HTTP response");
+ }
+
+
+ bool versionValid = false;
+
+ GnuID clientID;
+ clientID.clear();
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG(http.cmdLine);
+
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(HTTP_HS_AGENT))
+ {
+ agent.set(arg);
+
+ if (strnicmp(arg,"PeerCast/",9)==0)
+ versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+ }else if (http.isHeader(PCX_HS_NETWORKID))
+ clientID.fromStr(arg);
+ }
+
+ if (!clientID.isSame(networkID))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (!versionValid)
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+ sock->writeLine(GNU_OK);
+ sock->writeLine("");
+
+}
+
+
+// -----------------------------------
+void Servent::processOutChannel()
+{
+}
+
+
+// -----------------------------------
+void Servent::handshakeIn()
+{
+
+ int osType=0;
+
+ HTTP http(*sock);
+
+
+ bool versionValid = false;
+ bool diffRootVer = false;
+
+ GnuID clientID;
+ clientID.clear();
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG("%s",http.cmdLine);
+
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(HTTP_HS_AGENT))
+ {
+ agent.set(arg);
+
+ if (strnicmp(arg,"PeerCast/",9)==0)
+ {
+ versionValid = (stricmp(arg+9,MIN_CONNECTVER)>=0);
+ diffRootVer = stricmp(arg+9,MIN_ROOTVER)<0;
+ }
+ }else if (http.isHeader(PCX_HS_NETWORKID))
+ {
+ clientID.fromStr(arg);
+
+ }else if (http.isHeader(PCX_HS_PRIORITY))
+ {
+ priorityConnect = atoi(arg)!=0;
+
+ }else if (http.isHeader(PCX_HS_ID))
+ {
+ GnuID id;
+ id.fromStr(arg);
+ if (id.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else if (http.isHeader(PCX_HS_OS))
+ {
+ if (stricmp(arg,PCX_OS_LINUX)==0)
+ osType = 1;
+ else if (stricmp(arg,PCX_OS_WIN32)==0)
+ osType = 2;
+ else if (stricmp(arg,PCX_OS_MACOSX)==0)
+ osType = 3;
+ else if (stricmp(arg,PCX_OS_WINAMP2)==0)
+ osType = 4;
+ }
+
+ }
+
+ if (!clientID.isSame(networkID))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ // if this is a priority connection and all incoming connections
+ // are full then kill an old connection to make room. Otherwise reject connection.
+ //if (!priorityConnect)
+ {
+ if (!isPrivate())
+ if (servMgr->pubInFull())
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+ }
+
+ if (!versionValid)
+ throw HTTPException(HTTP_SC_FORBIDDEN,403);
+
+ sock->writeLine(GNU_OK);
+
+ sock->writeLineF("%s %s",HTTP_HS_AGENT,PCX_OLDAGENT);
+
+ if (networkID.isSet())
+ {
+ char idStr[64];
+ networkID.toStr(idStr);
+ sock->writeLineF("%s %s",PCX_HS_NETWORKID,idStr);
+ }
+
+ if (servMgr->isRoot)
+ {
+ sock->writeLineF("%s %d",PCX_HS_FLOWCTL,servMgr->useFlowControl?1:0);
+ sock->writeLineF("%s %d",PCX_HS_MINBCTTL,chanMgr->minBroadcastTTL);
+ sock->writeLineF("%s %d",PCX_HS_MAXBCTTL,chanMgr->maxBroadcastTTL);
+ sock->writeLineF("%s %d",PCX_HS_RELAYBC,servMgr->relayBroadcast);
+ //sock->writeLine("%s %d",PCX_HS_FULLHIT,2);
+
+
+ if (diffRootVer)
+ {
+ sock->writeString(PCX_HS_DL);
+ sock->writeLine(PCX_DL_URL);
+ }
+
+ sock->writeLineF("%s %s",PCX_HS_MSG,servMgr->rootMsg.cstr());
+ }
+
+
+ char hostIP[64];
+ Host h = sock->host;
+ h.IPtoStr(hostIP);
+ sock->writeLineF("%s %s",PCX_HS_REMOTEIP,hostIP);
+
+
+ sock->writeLine("");
+
+
+ while (http.nextHeader());
+}
+
+// -----------------------------------
+bool Servent::pingHost(Host &rhost,GnuID &rsid)
+{
+ char ipstr[64];
+ rhost.toStr(ipstr);
+ LOG_DEBUG("Ping host %s: trying..",ipstr);
+ ClientSocket *s=NULL;
+ bool hostOK=false;
+ try
+ {
+ s = sys->createSocket();
+ if (!s)
+ return false;
+ else
+ {
+
+ s->setReadTimeout(15000);
+ s->setWriteTimeout(15000);
+ s->open(rhost);
+ s->connect();
+
+ AtomStream atom(*s);
+
+ atom.writeInt(PCP_CONNECT,1);
+ atom.writeParent(PCP_HELO,1);
+ atom.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+
+ GnuID sid;
+ sid.clear();
+
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+ if (id == PCP_OLEH)
+ {
+ for(int i=0; i<numc; i++)
+ {
+ int c,d;
+ ID4 pid = atom.read(c,d);
+ if (pid == PCP_SESSIONID)
+ atom.readBytes(sid.id,16,d);
+ else
+ atom.skip(c,d);
+ }
+ }else
+ {
+ LOG_DEBUG("Ping response: %s",id.getString().str());
+ throw StreamException("Bad ping response");
+ }
+
+ if (!sid.isSame(rsid))
+ throw StreamException("SIDs don`t match");
+
+ hostOK = true;
+ LOG_DEBUG("Ping host %s: OK",ipstr);
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_DEBUG("Ping host %s: %s",ipstr,e.msg);
+ }
+ if (s)
+ {
+ s->close();
+ delete s;
+ }
+
+ if (!hostOK)
+ rhost.port = 0;
+
+ return true;
+}
+
+WLock canStreamLock;
+
+// -----------------------------------
+bool Servent::handshakeStream(ChanInfo &chanInfo)
+{
+
+ HTTP http(*sock);
+
+
+ bool gotPCP=false;
+ unsigned int reqPos=0;
+
+ nsSwitchNum=0;
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ if (http.isHeader(PCX_HS_PCP))
+ gotPCP = atoi(arg)!=0;
+ else if (http.isHeader(PCX_HS_POS))
+ reqPos = atoi(arg);
+ else if (http.isHeader("icy-metadata"))
+ addMetadata = atoi(arg) > 0;
+ else if (http.isHeader(HTTP_HS_AGENT))
+ agent = arg;
+ else if (http.isHeader("Pragma"))
+ {
+ char *ssc = stristr(arg,"stream-switch-count=");
+ char *so = stristr(arg,"stream-offset");
+
+ if (ssc || so)
+ {
+ nsSwitchNum=1;
+ //nsSwitchNum = atoi(ssc+20);
+ }
+ }
+
+ LOG_DEBUG("Stream: %s",http.cmdLine);
+ }
+
+
+ if ((!gotPCP) && (outputProtocol == ChanInfo::SP_PCP))
+ outputProtocol = ChanInfo::SP_PEERCAST;
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ if ( (chanInfo.srcProtocol == ChanInfo::SP_MMS)
+ || (chanInfo.contentType == ChanInfo::T_WMA)
+ || (chanInfo.contentType == ChanInfo::T_WMV)
+ || (chanInfo.contentType == ChanInfo::T_ASX)
+ )
+ outputProtocol = ChanInfo::SP_MMS;
+ }
+
+
+ bool chanFound=false;
+ bool chanReady=false;
+
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ {
+ sendHeader = true;
+// if (reqPos)
+// {
+// streamPos = ch->rawData.findOldestPos(reqPos);
+// }else
+// {
+ streamPos = ch->rawData.getLatestPos();
+// }
+
+ chanID = chanInfo.id;
+ canStreamLock.on();
+ chanReady = canStream(ch);
+ if (!chanReady) type = T_INCOMING;
+ thread.active = chanReady;
+ setStatus(S_CONNECTED);
+ canStreamLock.off();
+ channel_id = ch->channel_id;
+
+ //JP-Patch add-s
+ if (servMgr->isCheckPushStream())
+ {
+ if (chanReady == true)
+ {
+ Host h = getHost();
+
+ if (!h.isLocalhost())
+ {
+ do
+ {
+ if (strstr(agent.cstr(),"PeerCast/0.119") != NULL)
+ {
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block v0.119 Servent : %s (%s)",strip,agent.cstr());
+ chanReady = false;
+ break;
+ }
+
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+ bool isfw = false;
+ int numRelay = 0;
+ for(int i=0; i<numHits; i++)
+ {
+ ChanHitList *chl = hits[i];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++)
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ if (hit->firewalled)
+ isfw = true;
+ numRelay = hit->numRelays;
+ }
+ }
+ }
+ }
+ if ((isfw == true) && (numRelay == 0))
+ {
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block firewalled Servent : %s",strip);
+ chanReady = false;
+ }*/
+
+ ChanHitList *chl = chanMgr->findHitList(chanInfo);
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ if ((hit->firewalled) && (hit->numRelays == 0)){
+ char strip[256];
+ h.toStr(strip);
+ LOG_ERROR("Block firewalled Servent : %s",strip);
+ chanReady = false;
+ }
+ }
+ hit = hit->next;
+ }
+ }while (0);
+ }
+ }
+ }
+ //JP-Patch add-e
+ }
+
+// LockBlock lockblock(chanMgr->hitlistlock);
+
+// lockblock.lockon();
+ ChanHitList *chl = chanMgr->findHitList(chanInfo);
+
+ if (chl)
+ {
+ chanFound = true;
+ }
+
+
+ bool result = false;
+
+ char idStr[64];
+ chanInfo.id.toStr(idStr);
+
+ char sidStr[64];
+ servMgr->sessionID.toStr(sidStr);
+
+ Host rhost = sock->host;
+
+
+
+
+ AtomStream atom(*sock);
+
+
+
+ if (!chanFound)
+ {
+ sock->writeLine(HTTP_SC_NOTFOUND);
+ sock->writeLine("");
+ LOG_DEBUG("Sending channel not found");
+ return false;
+ }
+
+
+ if (!chanReady)
+ {
+ if (outputProtocol == ChanInfo::SP_PCP)
+ {
+
+ char tbuf[8196];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ mem.writeLine(HTTP_SC_UNAVAILABLE);
+ mem.writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+ mem.writeLine("");
+ sock->write(tbuf, mem.getPosition());
+
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+ char ripStr[64];
+ rhost.toStr(ripStr);
+
+ LOG_DEBUG("Sending channel unavailable");
+
+ ChanHitSearch chs;
+
+ mem.rewind();
+ AtomStream atom2(mem);
+
+ int error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+
+ chanMgr->hitlistlock.on();
+
+ chl = chanMgr->findHitList(chanInfo);
+
+ if (chl)
+ {
+ ChanHit best;
+
+ // search for up to 8 other hits
+ int cnt=0;
+ for(int i=0; i<8; i++)
+ {
+ best.init();
+
+
+ // find best hit this network if local IP
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit this network if local IP");
+ }
+ }
+
+ // find best hit on same network
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit on same network");
+ }
+
+ }
+
+ // find best hit on other networks
+/* if (!best.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs)){
+ best = chs.best[0];
+ LOG_DEBUG("find best hit on other networks");
+ }
+
+ }*/
+
+ if (!best.host.ip)
+ break;
+
+ best.writeAtoms(atom2,chanInfo.id);
+ cnt++;
+ }
+
+ if (!best.host.ip){
+ char tmp[50];
+// chanMgr->hitlistlock.on();
+ int cnt = chs.getRelayHost(servMgr->serverHost, rhost, remoteID, chl);
+// chanMgr->hitlistlock.off();
+ for (int i = 0; i < cnt; i++){
+ chs.best[i].writeAtoms(atom2, chanInfo.id);
+ chs.best[i].host.toStr(tmp);
+ LOG_DEBUG("relay info: %s hops = %d", tmp, chs.best[i].numHops);
+ best.host.ip = chs.best[i].host.ip;
+ }
+ }
+
+ if (cnt)
+ {
+ LOG_DEBUG("Sent %d channel hit(s) to %s",cnt,ripStr);
+
+ }
+ else if (rhost.port)
+ {
+ // find firewalled host
+ chs.init();
+ chs.waitDelay = 30;
+ chs.useFirewalled = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ {
+ best = chs.best[0];
+ int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_RELAY);
+ LOG_DEBUG("Broadcasted channel push request to %d clients for %s",cnt,ripStr);
+ }
+ }
+
+ // if all else fails, use tracker
+ if (!best.host.ip)
+ {
+ // find best tracker on this network if local IP
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+
+ }
+
+ // find local tracker
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // find global tracker
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ if (chl->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ if (best.host.ip)
+ {
+ best.writeAtoms(atom2,chanInfo.id);
+ LOG_DEBUG("Sent 1 tracker hit to %s",ripStr);
+ }else if (rhost.port)
+ {
+ // find firewalled tracker
+ chs.init();
+ chs.useFirewalled = true;
+ chs.trackersOnly = true;
+ chs.excludeID = remoteID;
+ chs.waitDelay = 30;
+ if (chl->pickHits(chs))
+ {
+ best = chs.best[0];
+ int cnt = servMgr->broadcastPushRequest(best,rhost,chl->info.id,Servent::T_CIN);
+ LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,ripStr);
+ }
+ }
+
+ }
+
+
+ }
+
+ chanMgr->hitlistlock.off();
+
+ // return not available yet code
+ atom2.writeInt(PCP_QUIT,error);
+ sock->write(tbuf, mem.getPosition());
+ result = false;
+
+ /*
+ char c[512];
+ // wait disconnect from other host
+ try{
+ while(sock->read(c, sizeof(c))){
+ sys->sleep(10);
+ }
+ }catch(StreamException &e){
+ LOG_DEBUG("RelayInfoWait: %s",e.msg);
+ }
+ */
+ }else
+ {
+ LOG_DEBUG("Sending channel unavailable");
+ sock->writeLine(HTTP_SC_UNAVAILABLE);
+ sock->writeLine("");
+ result = false;
+ }
+
+ } else {
+
+ if (chanInfo.contentType != ChanInfo::T_MP3)
+ addMetadata=false;
+
+ if (addMetadata && (outputProtocol == ChanInfo::SP_HTTP)) // winamp mp3 metadata check
+ {
+
+ sock->writeLine(ICY_OK);
+
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("icy-name:%s",chanInfo.name.cstr());
+ sock->writeLineF("icy-br:%d",chanInfo.bitrate);
+ sock->writeLineF("icy-genre:%s",chanInfo.genre.cstr());
+ sock->writeLineF("icy-url:%s",chanInfo.url.cstr());
+ sock->writeLineF("icy-metaint:%d",chanMgr->icyMetaInterval);
+ sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+
+ }else
+ {
+
+ sock->writeLine(HTTP_SC_OK);
+
+ if ((chanInfo.contentType != ChanInfo::T_ASX) && (chanInfo.contentType != ChanInfo::T_WMV) && (chanInfo.contentType != ChanInfo::T_WMA))
+ {
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+ sock->writeLine("Accept-Ranges: none");
+
+ sock->writeLineF("x-audiocast-name: %s",chanInfo.name.cstr());
+ sock->writeLineF("x-audiocast-bitrate: %d",chanInfo.bitrate);
+ sock->writeLineF("x-audiocast-genre: %s",chanInfo.genre.cstr());
+ sock->writeLineF("x-audiocast-description: %s",chanInfo.desc.cstr());
+ sock->writeLineF("x-audiocast-url: %s",chanInfo.url.cstr());
+ sock->writeLineF("%s %s",PCX_HS_CHANNELID,idStr);
+ }
+
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ switch (chanInfo.contentType)
+ {
+ case ChanInfo::T_OGG:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XOGG);
+ break;
+ case ChanInfo::T_MP3:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MP3);
+ break;
+ case ChanInfo::T_MOV:
+ sock->writeLine("Connection: close");
+ sock->writeLine("Content-Length: 10000000");
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MOV);
+ break;
+ case ChanInfo::T_MPG:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MPG);
+ break;
+ case ChanInfo::T_NSV:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_NSV);
+ break;
+ case ChanInfo::T_ASX:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_ASX);
+ break;
+ case ChanInfo::T_WMA:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMA);
+ break;
+ case ChanInfo::T_WMV:
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_WMV);
+ break;
+ }
+ } else if (outputProtocol == ChanInfo::SP_MMS)
+ {
+ sock->writeLine("Server: Rex/9.0.0.2980");
+ sock->writeLine("Cache-Control: no-cache");
+ sock->writeLine("Pragma: no-cache");
+ sock->writeLine("Pragma: client-id=3587303426");
+ sock->writeLine("Pragma: features=\"broadcast,playlist\"");
+
+ if (nsSwitchNum)
+ {
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_MMS);
+ }else
+ {
+ sock->writeLine("Content-Type: application/vnd.ms.wms-hdr.asfv1");
+ if (ch)
+ sock->writeLineF("Content-Length: %d",ch->headPack.len);
+ sock->writeLine("Connection: Keep-Alive");
+ }
+
+ } else if (outputProtocol == ChanInfo::SP_PCP)
+ {
+ sock->writeLineF("%s %d",PCX_HS_POS,streamPos);
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPCP);
+
+ }else if (outputProtocol == ChanInfo::SP_PEERCAST)
+ {
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XPEERCAST);
+ }
+ }
+ sock->writeLine("");
+ result = true;
+
+ if (gotPCP)
+ {
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+ atom.writeInt(PCP_OK,0);
+ }
+
+ }
+
+
+
+ return result;
+}
+
+// -----------------------------------
+void Servent::handshakeGiv(GnuID &id)
+{
+ if (id.isSet())
+ {
+ char idstr[64];
+ id.toStr(idstr);
+ sock->writeLineF("GIV /%s",idstr);
+ }else
+ sock->writeLine("GIV");
+
+ sock->writeLine("");
+}
+
+
+// -----------------------------------
+void Servent::processGnutella()
+{
+ type = T_PGNU;
+
+ //if (servMgr->isRoot && !servMgr->needConnections())
+ if (servMgr->isRoot)
+ {
+ processRoot();
+ return;
+ }
+
+
+
+ gnuStream.init(sock);
+ setStatus(S_CONNECTED);
+
+ if (!servMgr->isRoot)
+ {
+ chanMgr->broadcastRelays(this, 1, 1);
+ GnuPacket *p;
+
+ if ((p=outPacketsNorm.curr()))
+ gnuStream.sendPacket(*p);
+ return;
+ }
+
+ gnuStream.ping(2);
+
+// if (type != T_LOOKUP)
+// chanMgr->broadcastRelays(this,chanMgr->minBroadcastTTL,2);
+
+ lastPacket = lastPing = sys->getTime();
+ bool doneBigPing=false;
+
+ const unsigned int abortTimeoutSecs = 60; // abort connection after 60 secs of no activitiy
+ const unsigned int packetTimeoutSecs = 30; // ping connection after 30 secs of no activity
+
+ unsigned int currBytes=0;
+ unsigned int lastWait=0;
+
+ unsigned int lastTotalIn=0,lastTotalOut=0;
+
+ while (thread.active && sock->active())
+ {
+
+ if (sock->readReady())
+ {
+ lastPacket = sys->getTime();
+
+ if (gnuStream.readPacket(pack))
+ {
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ GnuID routeID;
+ GnuStream::R_TYPE ret = GnuStream::R_PROCESS;
+
+ if (pack.func != GNU_FUNC_PONG)
+ if (servMgr->seenPacket(pack))
+ ret = GnuStream::R_DUPLICATE;
+
+ seenIDs.add(pack.id);
+
+
+ if (ret == GnuStream::R_PROCESS)
+ {
+ GnuID routeID;
+ ret = gnuStream.processPacket(pack,this,routeID);
+
+ if (flowControl && (ret == GnuStream::R_BROADCAST))
+ ret = GnuStream::R_DROP;
+
+ }
+
+ switch(ret)
+ {
+ case GnuStream::R_BROADCAST:
+ if (servMgr->broadcast(pack,this))
+ stats.add(Stats::NUMBROADCASTED);
+ else
+ stats.add(Stats::NUMDROPPED);
+ break;
+ case GnuStream::R_ROUTE:
+ if (servMgr->route(pack,routeID,NULL))
+ stats.add(Stats::NUMROUTED);
+ else
+ stats.add(Stats::NUMDROPPED);
+ break;
+ case GnuStream::R_ACCEPTED:
+ stats.add(Stats::NUMACCEPTED);
+ break;
+ case GnuStream::R_DUPLICATE:
+ stats.add(Stats::NUMDUP);
+ break;
+ case GnuStream::R_DEAD:
+ stats.add(Stats::NUMDEAD);
+ break;
+ case GnuStream::R_DISCARD:
+ stats.add(Stats::NUMDISCARDED);
+ break;
+ case GnuStream::R_BADVERSION:
+ stats.add(Stats::NUMOLD);
+ break;
+ case GnuStream::R_DROP:
+ stats.add(Stats::NUMDROPPED);
+ break;
+ }
+
+
+ LOG_NETWORK("packet in: %s-%s, %d bytes, %d hops, %d ttl, from %s",GNU_FUNC_STR(pack.func),GnuStream::getRouteStr(ret),pack.len,pack.hops,pack.ttl,ipstr);
+
+
+
+ }else{
+ LOG_ERROR("Bad packet");
+ }
+ }
+
+
+ GnuPacket *p;
+
+ if ((p=outPacketsPri.curr())) // priority packet
+ {
+ gnuStream.sendPacket(*p);
+ seenIDs.add(p->id);
+ outPacketsPri.next();
+ } else if ((p=outPacketsNorm.curr())) // or.. normal packet
+ {
+ gnuStream.sendPacket(*p);
+ seenIDs.add(p->id);
+ outPacketsNorm.next();
+ }
+
+ int lpt = sys->getTime()-lastPacket;
+
+ if (!doneBigPing)
+ {
+ if ((sys->getTime()-lastPing) > 15)
+ {
+ gnuStream.ping(7);
+ lastPing = sys->getTime();
+ doneBigPing = true;
+ }
+ }else{
+ if (lpt > packetTimeoutSecs)
+ {
+
+ if ((sys->getTime()-lastPing) > packetTimeoutSecs)
+ {
+ gnuStream.ping(1);
+ lastPing = sys->getTime();
+ }
+
+ }
+ }
+ if (lpt > abortTimeoutSecs)
+ throw TimeoutException();
+
+
+ unsigned int totIn = sock->totalBytesIn-lastTotalIn;
+ unsigned int totOut = sock->totalBytesOut-lastTotalOut;
+
+ unsigned int bytes = totIn+totOut;
+
+ lastTotalIn = sock->totalBytesIn;
+ lastTotalOut = sock->totalBytesOut;
+
+ const int serventBandwidth = 1000;
+
+ int delay = sys->idleSleepTime;
+ if ((bytes) && (serventBandwidth >= 8))
+ delay = (bytes*1000)/(serventBandwidth/8); // set delay relative packetsize
+
+ if (delay < (int)sys->idleSleepTime)
+ delay = sys->idleSleepTime;
+ //LOG("delay %d, in %d, out %d",delay,totIn,totOut);
+
+ sys->sleep(delay);
+ }
+
+}
+
+
+// -----------------------------------
+void Servent::processRoot()
+{
+ try
+ {
+
+ gnuStream.init(sock);
+ setStatus(S_CONNECTED);
+
+ gnuStream.ping(2);
+
+ unsigned int lastConnect = sys->getTime();
+
+ while (thread.active && sock->active())
+ {
+ if (gnuStream.readPacket(pack))
+ {
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ LOG_NETWORK("packet in: %d from %s",pack.func,ipstr);
+
+
+ if (pack.func == GNU_FUNC_PING) // if ping then pong back some hosts and close
+ {
+
+ Host hl[32];
+ int cnt = servMgr->getNewestServents(hl,32,sock->host);
+ if (cnt)
+ {
+ int start = sys->rnd() % cnt;
+ int max = cnt>8?8:cnt;
+
+ for(int i=0; i<max; i++)
+ {
+ GnuPacket pong;
+ pack.hops = 1;
+ pong.initPong(hl[start],false,pack);
+ gnuStream.sendPacket(pong);
+
+ char ipstr[64];
+ hl[start].toStr(ipstr);
+
+ //LOG_NETWORK("Pong %d: %s",start+1,ipstr);
+ start = (start+1) % cnt;
+ }
+ char str[64];
+ sock->host.toStr(str);
+ LOG_NETWORK("Sent %d pong(s) to %s",max,str);
+ }else
+ {
+ LOG_NETWORK("No Pongs to send");
+ //return;
+ }
+ }else if (pack.func == GNU_FUNC_PONG) // pong?
+ {
+ MemoryStream pong(pack.data,pack.len);
+
+ int ip,port;
+ port = pong.readShort();
+ ip = pong.readLong();
+ ip = SWAP4(ip);
+
+
+ Host h(ip,port);
+ if ((ip) && (port) && (h.globalIP()))
+ {
+
+ LOG_NETWORK("added pong: %d.%d.%d.%d:%d",ip>>24&0xff,ip>>16&0xff,ip>>8&0xff,ip&0xff,port);
+ servMgr->addHost(h,ServHost::T_SERVENT,sys->getTime());
+ }
+ //return;
+ } else if (pack.func == GNU_FUNC_HIT)
+ {
+ MemoryStream data(pack.data,pack.len);
+ ChanHit hit;
+ gnuStream.readHit(data,hit,pack.hops,pack.id);
+ }
+
+ //if (gnuStream.packetsIn > 5) // die if we get too many packets
+ // return;
+ }
+
+ if((sys->getTime()-lastConnect > 60))
+ break;
+ }
+
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Relay: %s",e.msg);
+ }
+
+
+}
+
+// -----------------------------------
+int Servent::givProc(ThreadInfo *thread)
+{
+// thread->lock();
+ Servent *sv = (Servent*)thread->data;
+ try
+ {
+ sv->handshakeGiv(sv->givID);
+ sv->handshakeIncoming();
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("GIV: %s",e.msg);
+ }
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+
+// -----------------------------------
+void Servent::handshakeOutgoingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent, bool isTrusted)
+{
+
+ bool nonFW = (servMgr->getFirewall() != ServMgr::FW_ON);
+ bool testFW = (servMgr->getFirewall() == ServMgr::FW_UNKNOWN);
+
+ bool sendBCID = isTrusted && chanMgr->isBroadcasting();
+
+ char tbuf[1024];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ AtomStream atom2(mem);
+ atom2.writeParent(PCP_HELO,3 + (testFW?1:0) + (nonFW?1:0) + (sendBCID?1:0));
+ atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+ atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+ atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ if (nonFW)
+ atom2.writeShort(PCP_HELO_PORT,servMgr->serverHost.port);
+ if (testFW)
+ atom2.writeShort(PCP_HELO_PING,servMgr->serverHost.port);
+ if (sendBCID)
+ atom2.writeBytes(PCP_HELO_BCID,chanMgr->broadcastID.id,16);
+ atom.io.write(tbuf, mem.getPosition());
+
+
+ LOG_DEBUG("PCP outgoing waiting for OLEH..");
+
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+ if (id != PCP_OLEH)
+ {
+ LOG_DEBUG("PCP outgoing reply: %s",id.getString().str());
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+ throw StreamException("Got unexpected PCP response");
+ }
+
+
+
+ char arg[64];
+
+ GnuID clientID;
+ clientID.clear();
+ rid.clear();
+ int version=0;
+ int disable=0;
+
+ Host thisHost;
+
+ // read OLEH response
+ for(int i=0; i<numc; i++)
+ {
+ int c,dlen;
+ ID4 id = atom.read(c,dlen);
+
+ if (id == PCP_HELO_AGENT)
+ {
+ atom.readString(arg,sizeof(arg),dlen);
+ agent.set(arg);
+
+ }else if (id == PCP_HELO_REMOTEIP)
+ {
+ thisHost.ip = atom.readInt();
+
+ }else if (id == PCP_HELO_PORT)
+ {
+ thisHost.port = atom.readShort();
+
+ }else if (id == PCP_HELO_VERSION)
+ {
+ version = atom.readInt();
+
+ }else if (id == PCP_HELO_DISABLE)
+ {
+ disable = atom.readInt();
+
+ }else if (id == PCP_HELO_SESSIONID)
+ {
+ atom.readBytes(rid.id,16);
+ if (rid.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else
+ {
+ LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+ atom.skip(c,dlen);
+ }
+
+ }
+
+
+ // update server ip/firewall status
+ if (isTrusted)
+ {
+ if (thisHost.isValid())
+ {
+ if ((servMgr->serverHost.ip != thisHost.ip) && (servMgr->forceIP.isEmpty()))
+ {
+ char ipstr[64];
+ thisHost.toStr(ipstr);
+ LOG_DEBUG("Got new ip: %s",ipstr);
+ servMgr->serverHost.ip = thisHost.ip;
+ }
+
+ if (servMgr->getFirewall() == ServMgr::FW_UNKNOWN)
+ {
+ if (thisHost.port && thisHost.globalIP())
+ servMgr->setFirewall(ServMgr::FW_OFF);
+ else
+ servMgr->setFirewall(ServMgr::FW_ON);
+ }
+ }
+
+ if (disable == 1)
+ {
+ LOG_ERROR("client disabled: %d",disable);
+ servMgr->isDisabled = true;
+ }else
+ {
+ servMgr->isDisabled = false;
+ }
+ }
+
+
+
+ if (!rid.isSet())
+ {
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+ throw StreamException("Remote host not identified");
+ }
+
+ LOG_DEBUG("PCP Outgoing handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::handshakeIncomingPCP(AtomStream &atom, Host &rhost, GnuID &rid, String &agent)
+{
+ int numc,numd;
+ ID4 id = atom.read(numc,numd);
+
+
+ if (id != PCP_HELO)
+ {
+ LOG_DEBUG("PCP incoming reply: %s",id.getString().str());
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADRESPONSE);
+ throw StreamException("Got unexpected PCP response");
+ }
+
+ char arg[64];
+
+ ID4 osType;
+
+ int version=0;
+
+ int pingPort=0;
+
+ GnuID bcID;
+ GnuID clientID;
+
+ bcID.clear();
+ clientID.clear();
+
+ rhost.port = 0;
+
+ for(int i=0; i<numc; i++)
+ {
+
+ int c,dlen;
+ ID4 id = atom.read(c,dlen);
+
+ if (id == PCP_HELO_AGENT)
+ {
+ atom.readString(arg,sizeof(arg),dlen);
+ agent.set(arg);
+
+ }else if (id == PCP_HELO_VERSION)
+ {
+ version = atom.readInt();
+
+ }else if (id == PCP_HELO_SESSIONID)
+ {
+ atom.readBytes(rid.id,16);
+ if (rid.isSame(servMgr->sessionID))
+ throw StreamException("Servent loopback");
+
+ }else if (id == PCP_HELO_BCID)
+ {
+ atom.readBytes(bcID.id,16);
+
+ }else if (id == PCP_HELO_OSTYPE)
+ {
+ osType = atom.readInt();
+ }else if (id == PCP_HELO_PORT)
+ {
+ rhost.port = atom.readShort();
+ }else if (id == PCP_HELO_PING)
+ {
+ pingPort = atom.readShort();
+ }else
+ {
+ LOG_DEBUG("PCP handshake skip: %s",id.getString().str());
+ atom.skip(c,dlen);
+ }
+
+ }
+
+ if (version)
+ LOG_DEBUG("Incoming PCP is %s : v%d", agent.cstr(),version);
+
+
+ if (!rhost.globalIP() && servMgr->serverHost.globalIP())
+ rhost.ip = servMgr->serverHost.ip;
+
+ if (pingPort)
+ {
+ char ripStr[64];
+ rhost.toStr(ripStr);
+ LOG_DEBUG("Incoming firewalled test request: %s ", ripStr);
+ rhost.port = pingPort;
+ if (!rhost.globalIP() || !pingHost(rhost,rid))
+ rhost.port = 0;
+ }
+
+ if (servMgr->isRoot)
+ {
+ if (bcID.isSet())
+ {
+ if (bcID.getFlags() & 1) // private
+ {
+ BCID *bcid = servMgr->findValidBCID(bcID);
+ if (!bcid || (bcid && !bcid->valid))
+ {
+ atom.writeParent(PCP_OLEH,1);
+ atom.writeInt(PCP_HELO_DISABLE,1);
+ throw StreamException("Client is banned");
+ }
+ }
+ }
+ }
+
+
+ char tbuf[1024];
+ MemoryStream mem(tbuf, sizeof(tbuf));
+ AtomStream atom2(mem);
+ atom2.writeParent(PCP_OLEH,5);
+ atom2.writeString(PCP_HELO_AGENT,PCX_AGENT);
+ atom2.writeBytes(PCP_HELO_SESSIONID,servMgr->sessionID.id,16);
+ atom2.writeInt(PCP_HELO_VERSION,PCP_CLIENT_VERSION);
+ atom2.writeInt(PCP_HELO_REMOTEIP,rhost.ip);
+ atom2.writeShort(PCP_HELO_PORT,rhost.port);
+
+ if (version)
+ {
+ if (version < PCP_CLIENT_MINVERSION)
+ {
+ atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_BADAGENT);
+ atom.io.write(tbuf, mem.getPosition());
+ throw StreamException("Agent is not valid");
+ }
+ }
+
+ if (!rid.isSet())
+ {
+ atom2.writeInt(PCP_QUIT,PCP_ERROR_QUIT+PCP_ERROR_NOTIDENTIFIED);
+ atom.io.write(tbuf, mem.getPosition());
+ throw StreamException("Remote host not identified");
+ }
+
+
+
+ if (servMgr->isRoot)
+ {
+ servMgr->writeRootAtoms(atom2,false);
+ }
+
+ atom.io.write(tbuf, mem.getPosition());
+
+ LOG_DEBUG("PCP Incoming handshake complete.");
+
+}
+
+// -----------------------------------
+void Servent::processIncomingPCP(bool suggestOthers)
+{
+ PCPStream::readVersion(*sock);
+
+
+ AtomStream atom(*sock);
+ Host rhost = sock->host;
+
+ handshakeIncomingPCP(atom,rhost,remoteID,agent);
+
+
+ bool alreadyConnected = (servMgr->findConnection(Servent::T_COUT,remoteID)!=NULL)
+ || (servMgr->findConnection(Servent::T_CIN,remoteID)!=NULL);
+ bool unavailable = servMgr->controlInFull();
+ bool offair = !servMgr->isRoot && !chanMgr->isBroadcasting();
+
+ char rstr[64];
+ rhost.toStr(rstr);
+
+ if (unavailable || alreadyConnected || offair)
+ {
+ int error;
+
+ if (alreadyConnected)
+ error = PCP_ERROR_QUIT+PCP_ERROR_ALREADYCONNECTED;
+ else if (unavailable)
+ error = PCP_ERROR_QUIT+PCP_ERROR_UNAVAILABLE;
+ else if (offair)
+ error = PCP_ERROR_QUIT+PCP_ERROR_OFFAIR;
+ else
+ error = PCP_ERROR_QUIT;
+
+
+ if (suggestOthers)
+ {
+
+ ChanHit best;
+ ChanHitSearch chs;
+
+ int cnt=0;
+ for(int i=0; i<8; i++)
+ {
+ best.init();
+
+ // find best hit on this network
+ if (!rhost.globalIP())
+ {
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // find best hit on same network
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.matchHost = rhost;
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ // else find best hit on other networks
+ if (!best.host.ip)
+ {
+ chs.init();
+ chs.waitDelay = 2;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ best = chs.best[0];
+ }
+
+ if (!best.host.ip)
+ break;
+
+ GnuID noID;
+ noID.clear();
+ best.writeAtoms(atom,noID);
+ cnt++;
+ }
+ if (cnt)
+ {
+ LOG_DEBUG("Sent %d tracker(s) to %s",cnt,rstr);
+ }
+ else if (rhost.port)
+ {
+ // send push request to best firewalled tracker on other network
+ chs.init();
+ chs.waitDelay = 30;
+ chs.excludeID = remoteID;
+ chs.trackersOnly = true;
+ chs.useFirewalled = true;
+ chs.useBusyControls = false;
+ if (chanMgr->pickHits(chs))
+ {
+ best = chs.best[0];
+ GnuID noID;
+ noID.clear();
+ int cnt = servMgr->broadcastPushRequest(best,rhost,noID,Servent::T_CIN);
+ LOG_DEBUG("Broadcasted tracker push request to %d clients for %s",cnt,rstr);
+ }
+ }else
+ {
+ LOG_DEBUG("No available trackers");
+ }
+ }
+
+
+ LOG_ERROR("Sending QUIT to incoming: %d",error);
+
+ atom.writeInt(PCP_QUIT,error);
+ return;
+ }
+
+
+ type = T_CIN;
+ setStatus(S_CONNECTED);
+
+ atom.writeInt(PCP_OK,0);
+
+ // ask for update
+ atom.writeParent(PCP_ROOT,1);
+ atom.writeParent(PCP_ROOT_UPDATE,0);
+
+ pcpStream = new PCPStream(remoteID);
+
+ int error = 0;
+ BroadcastState bcs;
+ while (!error && thread.active && !sock->eof())
+ {
+ error = pcpStream->readPacket(*sock,bcs);
+ sys->sleepIdle();
+
+ if (!servMgr->isRoot && !chanMgr->isBroadcasting())
+ error = PCP_ERROR_OFFAIR;
+ if (peercastInst->isQuitting)
+ error = PCP_ERROR_SHUTDOWN;
+ }
+
+ pcpStream->flush(*sock);
+
+ error += PCP_ERROR_QUIT;
+ atom.writeInt(PCP_QUIT,error);
+
+ LOG_DEBUG("PCP Incoming to %s closed: %d",rstr,error);
+
+}
+
+// -----------------------------------
+int Servent::outgoingProc(ThreadInfo *thread)
+{
+// thread->lock();
+ LOG_DEBUG("COUT started");
+
+ Servent *sv = (Servent*)thread->data;
+
+ GnuID noID;
+ noID.clear();
+ sv->pcpStream = new PCPStream(noID);
+
+ while (sv->thread.active)
+ {
+ sv->setStatus(S_WAIT);
+
+ if (chanMgr->isBroadcasting() && servMgr->autoServe)
+ {
+ ChanHit bestHit;
+ ChanHitSearch chs;
+ char ipStr[64];
+
+ do
+ {
+ bestHit.init();
+
+ if (servMgr->rootHost.isEmpty())
+ break;
+
+ if (sv->pushSock)
+ {
+ sv->sock = sv->pushSock;
+ sv->pushSock = NULL;
+ bestHit.host = sv->sock->host;
+ break;
+ }
+
+ GnuID noID;
+ noID.clear();
+ ChanHitList *chl = chanMgr->findHitListByID(noID);
+ if (chl)
+ {
+ // find local tracker
+ chs.init();
+ chs.matchHost = servMgr->serverHost;
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ if (!chl->pickHits(chs))
+ {
+ // else find global tracker
+ chs.init();
+ chs.waitDelay = MIN_TRACKER_RETRY;
+ chs.excludeID = servMgr->sessionID;
+ chs.trackersOnly = true;
+ chl->pickHits(chs);
+ }
+
+ if (chs.numResults)
+ {
+ bestHit = chs.best[0];
+ }
+ }
+
+
+ unsigned int ctime = sys->getTime();
+
+ if ((!bestHit.host.ip) && ((ctime-chanMgr->lastYPConnect) > MIN_YP_RETRY))
+ {
+ bestHit.host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+ bestHit.yp = true;
+ chanMgr->lastYPConnect = ctime;
+ }
+ sys->sleepIdle();
+
+ }while (!bestHit.host.ip && (sv->thread.active));
+
+
+ if (!bestHit.host.ip) // give up
+ {
+ LOG_ERROR("COUT giving up");
+ break;
+ }
+
+
+ bestHit.host.toStr(ipStr);
+
+ int error=0;
+ try
+ {
+
+ LOG_DEBUG("COUT to %s: Connecting..",ipStr);
+
+ if (!sv->sock)
+ {
+ sv->setStatus(S_CONNECTING);
+ sv->sock = sys->createSocket();
+ if (!sv->sock)
+ throw StreamException("Unable to create socket");
+ sv->sock->open(bestHit.host);
+ sv->sock->connect();
+
+ }
+
+ sv->sock->setReadTimeout(30000);
+ AtomStream atom(*sv->sock);
+
+ sv->setStatus(S_HANDSHAKE);
+
+ Host rhost = sv->sock->host;
+ atom.writeInt(PCP_CONNECT,1);
+ handshakeOutgoingPCP(atom,rhost,sv->remoteID,sv->agent,bestHit.yp);
+
+ sv->setStatus(S_CONNECTED);
+
+ LOG_DEBUG("COUT to %s: OK",ipStr);
+
+ sv->pcpStream->init(sv->remoteID);
+
+ BroadcastState bcs;
+ bcs.servent_id = sv->servent_id;
+ error = 0;
+ while (!error && sv->thread.active && !sv->sock->eof() && servMgr->autoServe)
+ {
+ error = sv->pcpStream->readPacket(*sv->sock,bcs);
+
+ sys->sleepIdle();
+
+ if (!chanMgr->isBroadcasting())
+ error = PCP_ERROR_OFFAIR;
+ if (peercastInst->isQuitting)
+ error = PCP_ERROR_SHUTDOWN;
+
+ if (sv->pcpStream->nextRootPacket)
+ if (sys->getTime() > (sv->pcpStream->nextRootPacket+30))
+ error = PCP_ERROR_NOROOT;
+ }
+ sv->setStatus(S_CLOSING);
+
+ sv->pcpStream->flush(*sv->sock);
+
+ error += PCP_ERROR_QUIT;
+ atom.writeInt(PCP_QUIT,error);
+
+ LOG_ERROR("COUT to %s closed: %d",ipStr,error);
+
+ }catch(TimeoutException &e)
+ {
+ LOG_ERROR("COUT to %s: timeout (%s)",ipStr,e.msg);
+ sv->setStatus(S_TIMEOUT);
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("COUT to %s: %s",ipStr,e.msg);
+ sv->setStatus(S_ERROR);
+ }
+
+ try
+ {
+ if (sv->sock)
+ {
+ sv->sock->close();
+ delete sv->sock;
+ sv->sock = NULL;
+ }
+
+ }catch(StreamException &) {}
+
+ // don`t discard this hit if we caused the disconnect (stopped broadcasting)
+ if (error != (PCP_ERROR_QUIT+PCP_ERROR_OFFAIR))
+ chanMgr->deadHit(bestHit);
+
+ }
+
+ sys->sleepIdle();
+ }
+
+ sv->kill();
+ sys->endThread(thread);
+ LOG_DEBUG("COUT ended");
+ return 0;
+}
+// -----------------------------------
+int Servent::incomingProc(ThreadInfo *thread)
+{
+// thread->lock();
+
+ Servent *sv = (Servent*)thread->data;
+
+ char ipStr[64];
+ sv->sock->host.toStr(ipStr);
+
+ try
+ {
+ sv->handshakeIncoming();
+ }catch(HTTPException &e)
+ {
+ try
+ {
+ sv->sock->writeLine(e.msg);
+ if (e.code == 401)
+ sv->sock->writeLine("WWW-Authenticate: Basic realm=\"PeerCast\"");
+ sv->sock->writeLine("");
+ }catch(StreamException &){}
+ LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Incoming from %s: %s",ipStr,e.msg);
+ }
+
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+// -----------------------------------
+void Servent::processServent()
+{
+ setStatus(S_HANDSHAKE);
+
+ handshakeIn();
+
+ if (!sock)
+ throw StreamException("Servent has no socket");
+
+ processGnutella();
+}
+
+// -----------------------------------
+void Servent::processStream(bool doneHandshake,ChanInfo &chanInfo)
+{
+ if (!doneHandshake)
+ {
+ setStatus(S_HANDSHAKE);
+
+ if (!handshakeStream(chanInfo))
+ return;
+ }
+
+ if (chanInfo.id.isSet())
+ {
+
+ chanID = chanInfo.id;
+
+ LOG_CHANNEL("Sending channel: %s ",ChanInfo::getProtocolStr(outputProtocol));
+
+ if (!waitForChannelHeader(chanInfo))
+ throw StreamException("Channel not ready");
+
+ servMgr->totalStreams++;
+
+ Host host = sock->host;
+ host.port = 0; // force to 0 so we ignore the incoming port
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ if (outputProtocol == ChanInfo::SP_HTTP)
+ {
+ if ((addMetadata) && (chanMgr->icyMetaInterval))
+ sendRawMetaChannel(chanMgr->icyMetaInterval);
+ else
+ sendRawChannel(true,true);
+
+ }else if (outputProtocol == ChanInfo::SP_MMS)
+ {
+ if (nsSwitchNum)
+ {
+ sendRawChannel(true,true);
+ }else
+ {
+ sendRawChannel(true,false);
+ }
+
+ }else if (outputProtocol == ChanInfo::SP_PCP)
+ {
+ sendPCPChannel();
+
+ } else if (outputProtocol == ChanInfo::SP_PEERCAST)
+ {
+ sendPeercastChannel();
+ }
+ }
+
+ setStatus(S_CLOSING);
+}
+
+// -----------------------------------------
+#if 0
+// debug
+ FileStream file;
+ file.openReadOnly("c://test.mp3");
+
+ LOG_DEBUG("raw file read");
+ char buf[4000];
+ int cnt=0;
+ while (!file.eof())
+ {
+ LOG_DEBUG("send %d",cnt++);
+ file.read(buf,sizeof(buf));
+ sock->write(buf,sizeof(buf));
+
+ }
+ file.close();
+ LOG_DEBUG("raw file sent");
+
+ return;
+// debug
+#endif
+// -----------------------------------
+bool Servent::waitForChannelHeader(ChanInfo &info)
+{
+ for(int i=0; i<30*10; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(info.id);
+ if (!ch)
+ return false;
+
+ if (ch->isPlaying() && (ch->rawData.writePos>0))
+ return true;
+
+ if (!thread.active || !sock->active())
+ break;
+ sys->sleep(100);
+ }
+ return false;
+}
+// -----------------------------------
+void Servent::sendRawChannel(bool sendHead, bool sendData)
+{
+ try
+ {
+
+ sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ setStatus(S_CONNECTED);
+
+ LOG_DEBUG("Starting Raw stream of %s at %d",ch->info.name.cstr(),streamPos);
+
+ if (sendHead)
+ {
+ ch->headPack.writeRaw(*sock);
+ streamPos = ch->headPack.pos + ch->headPack.len;
+ LOG_DEBUG("Sent %d bytes header ",ch->headPack.len);
+ }
+
+ if (sendData)
+ {
+
+ unsigned int streamIndex = ch->streamIndex;
+ unsigned int connectTime = sys->getTime();
+ unsigned int lastWriteTime = connectTime;
+
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ if (streamIndex != ch->streamIndex)
+ {
+ streamIndex = ch->streamIndex;
+ streamPos = ch->headPack.pos;
+ LOG_DEBUG("sendRaw got new stream index");
+ }
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if (syncPos != rawPack.sync)
+ LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+ syncPos = rawPack.sync+1;
+
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ {
+ rawPack.writeRaw(*sock);
+ lastWriteTime = sys->getTime();
+ }
+
+ if (rawPack.pos < streamPos)
+ LOG_DEBUG("raw: skip back %d",rawPack.pos-streamPos);
+ streamPos = rawPack.pos+rawPack.len;
+ } else if (sock->readReady()) {
+ char c;
+ int error = sock->readUpto(&c, 1);
+ if (error == 0) sock->close();
+ }
+ }
+
+ if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+ throw TimeoutException();
+
+ sys->sleepIdle();
+ }
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+
+#if 0
+// -----------------------------------
+void Servent::sendRawMultiChannel(bool sendHead, bool sendData)
+{
+ try
+ {
+ unsigned int chanStreamIndex[ChanMgr::MAX_CHANNELS];
+ unsigned int chanStreamPos[ChanMgr::MAX_CHANNELS];
+ GnuID chanIDs[ChanMgr::MAX_CHANNELS];
+ int numChanIDs=0;
+ for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+ {
+ Channel *ch = &chanMgr->channels[i];
+ if (ch->isPlaying())
+ chanIDs[numChanIDs++]=ch->info.id;
+ }
+
+
+
+ setStatus(S_CONNECTED);
+
+
+ if (sendHead)
+ {
+ for(int i=0; i<numChanIDs; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+ if (ch)
+ {
+ LOG_DEBUG("Starting RawMulti stream: %s",ch->info.name.cstr());
+ ch->headPack.writeRaw(*sock);
+ chanStreamPos[i] = ch->headPack.pos + ch->headPack.len;
+ chanStreamIndex[i] = ch->streamIndex;
+ LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+
+ }
+ }
+ }
+
+ if (sendData)
+ {
+
+ unsigned int connectTime=sys->getTime();
+
+ while ((thread.active) && sock->active())
+ {
+
+ for(int i=1; i<numChanIDs; i++)
+ {
+ Channel *ch = chanMgr->findChannelByID(chanIDs[i]);
+ if (ch)
+ {
+ if (chanStreamIndex[i] != ch->streamIndex)
+ {
+ chanStreamIndex[i] = ch->streamIndex;
+ chanStreamPos[i] = ch->headPack.pos;
+ LOG_DEBUG("sendRawMulti got new stream index for chan %d",i);
+ }
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(chanStreamPos[i],rawPack))
+ {
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ rawPack.writeRaw(*sock);
+
+
+ if (rawPack.pos < chanStreamPos[i])
+ LOG_DEBUG("raw: skip back %d",rawPack.pos-chanStreamPos[i]);
+ chanStreamPos[i] = rawPack.pos+rawPack.len;
+
+
+ //LOG("raw at %d: %d %d",streamPos,ch->rawData.getStreamPos(ch->rawData.firstPos),ch->rawData.getStreamPos(ch->rawData.lastPos));
+ }
+ }
+ break;
+ }
+
+
+ sys->sleepIdle();
+ }
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+#endif
+
+// -----------------------------------
+void Servent::sendRawMetaChannel(int interval)
+{
+
+ try
+ {
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ sock->setWriteTimeout(DIRECT_WRITE_TIMEOUT*1000);
+
+ setStatus(S_CONNECTED);
+
+ LOG_DEBUG("Starting Raw Meta stream of %s (metaint: %d) at %d",ch->info.name.cstr(),interval,streamPos);
+
+
+ String lastTitle,lastURL;
+
+ int lastMsgTime=sys->getTime();
+ bool showMsg=true;
+
+ char buf[16384];
+ int bufPos=0;
+
+ if ((interval > sizeof(buf)) || (interval < 1))
+ throw StreamException("Bad ICY Meta Interval value");
+
+ unsigned int connectTime = sys->getTime();
+ unsigned int lastWriteTime = connectTime;
+
+ streamPos = 0; // raw meta channel has no header (its MP3)
+
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+
+ if (syncPos != rawPack.sync)
+ LOG_ERROR("Send skip: %d",rawPack.sync-syncPos);
+ syncPos = rawPack.sync+1;
+
+ MemoryStream mem(rawPack.data,rawPack.len);
+
+ if (rawPack.type == ChanPacket::T_DATA)
+ {
+
+ int len = rawPack.len;
+ char *p = rawPack.data;
+ while (len)
+ {
+ int rl = len;
+ if ((bufPos+rl) > interval)
+ rl = interval-bufPos;
+ memcpy(&buf[bufPos],p,rl);
+ bufPos+=rl;
+ p+=rl;
+ len-=rl;
+
+ if (bufPos >= interval)
+ {
+ bufPos = 0;
+ sock->write(buf,interval);
+ lastWriteTime = sys->getTime();
+
+ if (chanMgr->broadcastMsgInterval)
+ if ((sys->getTime()-lastMsgTime) >= chanMgr->broadcastMsgInterval)
+ {
+ showMsg ^= true;
+ lastMsgTime = sys->getTime();
+ }
+
+ String *metaTitle = &ch->info.track.title;
+ if (!ch->info.comment.isEmpty() && (showMsg))
+ metaTitle = &ch->info.comment;
+
+
+ if (!metaTitle->isSame(lastTitle) || !ch->info.url.isSame(lastURL))
+ {
+
+ char tmp[1024];
+ String title,url;
+
+ title = *metaTitle;
+ url = ch->info.url;
+
+ title.convertTo(String::T_META);
+ url.convertTo(String::T_META);
+
+ sprintf(tmp,"StreamTitle='%s';StreamUrl='%s';\0",title.cstr(),url.cstr());
+ int len = ((strlen(tmp) + 15+1) / 16);
+ sock->writeChar(len);
+ sock->write(tmp,len*16);
+
+ lastTitle = *metaTitle;
+ lastURL = ch->info.url;
+
+ LOG_DEBUG("StreamTitle: %s, StreamURL: %s",lastTitle.cstr(),lastURL.cstr());
+
+ }else
+ {
+ sock->writeChar(0);
+ }
+
+ }
+ }
+ }
+ streamPos = rawPack.pos + rawPack.len;
+ }
+ }
+ if ((sys->getTime()-lastWriteTime) > DIRECT_WRITE_TIMEOUT)
+ throw TimeoutException();
+
+ sys->sleepIdle();
+
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+// -----------------------------------
+void Servent::sendPeercastChannel()
+{
+ try
+ {
+ setStatus(S_CONNECTED);
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ LOG_DEBUG("Starting PeerCast stream: %s",ch->info.name.cstr());
+
+ sock->writeTag("PCST");
+
+ ChanPacket pack;
+
+ ch->headPack.writePeercast(*sock);
+
+ pack.init(ChanPacket::T_META,ch->insertMeta.data,ch->insertMeta.len,ch->streamPos);
+ pack.writePeercast(*sock);
+
+ streamPos = 0;
+ unsigned int syncPos=0;
+ while ((thread.active) && sock->active())
+ {
+ ch = chanMgr->findChannelByID(chanID);
+ if (ch)
+ {
+
+ ChanPacket rawPack;
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if ((rawPack.type == ChanPacket::T_DATA) || (rawPack.type == ChanPacket::T_HEAD))
+ {
+ sock->writeTag("SYNC");
+ sock->writeShort(4);
+ sock->writeShort(0);
+ sock->write(&syncPos,4);
+ syncPos++;
+
+ rawPack.writePeercast(*sock);
+ }
+ streamPos = rawPack.pos + rawPack.len;
+ }
+ }
+ sys->sleepIdle();
+ }
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+}
+
+//WLock canStreamLock;
+
+// -----------------------------------
+void Servent::sendPCPChannel()
+{
+ bool skipCheck = false;
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+ if (!ch)
+ throw StreamException("Channel not found");
+
+ AtomStream atom(*sock);
+
+ pcpStream = new PCPStream(remoteID);
+ int error=0;
+
+ try
+ {
+
+ LOG_DEBUG("Starting PCP stream of channel at %d",streamPos);
+
+
+// setStatus(S_CONNECTED);
+
+ //canStreamLock.on();
+ //thread.active = canStream(ch);
+ //setStatus(S_CONNECTED);
+ //canStreamLock.off();
+
+ lastSkipTime = 0;
+ lastSkipCount = 0;
+ waitPort = 0;
+
+ if (thread.active){
+ atom.writeParent(PCP_CHAN,3 + ((sendHeader)?1:0));
+ atom.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ ch->info.writeInfoAtoms(atom);
+ ch->info.writeTrackAtoms(atom);
+ if (sendHeader)
+ {
+ atom.writeParent(PCP_CHAN_PKT,3);
+ atom.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+ atom.writeInt(PCP_CHAN_PKT_POS,ch->headPack.pos);
+ atom.writeBytes(PCP_CHAN_PKT_DATA,ch->headPack.data,ch->headPack.len);
+
+ streamPos = ch->headPack.pos+ch->headPack.len;
+ LOG_DEBUG("Sent %d bytes header",ch->headPack.len);
+ }
+ }
+
+ unsigned int streamIndex = ch->streamIndex;
+
+ ChanPacket rawPack;
+ char pbuf[ChanPacket::MAX_DATALEN*3];
+ MemoryStream mems(pbuf,sizeof(pbuf));
+ AtomStream atom2(mems);
+
+ while (thread.active)
+ {
+
+ Channel *ch = chanMgr->findChannelByID(chanID);
+
+ if (ch)
+ {
+
+ if (streamIndex != ch->streamIndex)
+ {
+ streamIndex = ch->streamIndex;
+ streamPos = ch->headPack.pos;
+ LOG_DEBUG("sendPCPStream got new stream index");
+ }
+
+ mems.rewind();
+
+ if (ch->rawData.findPacket(streamPos,rawPack))
+ {
+ if ((streamPos < rawPack.pos) && !rawPack.skip){
+ if (skipCheck){
+ char tmp[32];
+ getHost().IPtoStr(tmp);
+ LOG_NETWORK("##### send skipping ##### %d (%d, %d) -> %s", (rawPack.pos - streamPos), streamPos, rawPack.pos, tmp);
+
+ if (sys->getTime() == lastSkipTime) {
+ LOG_DEBUG("##### skip all buffer");
+ streamPos = ch->rawData.getLatestPos();
+ continue;
+ }
+
+ lastSkipTime = sys->getTime();
+ lastSkipCount++;
+ } else {
+ skipCheck = true;
+ }
+ }
+
+ if (rawPack.type == ChanPacket::T_HEAD)
+ {
+ atom2.writeParent(PCP_CHAN,2);
+ atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ atom2.writeParent(PCP_CHAN_PKT,3);
+ atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_HEAD);
+ atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+ atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+ sock->write(pbuf, mems.getPosition());
+ }else if (rawPack.type == ChanPacket::T_DATA)
+ {
+ atom2.writeParent(PCP_CHAN,2);
+ atom2.writeBytes(PCP_CHAN_ID,chanID.id,16);
+ atom2.writeParent(PCP_CHAN_PKT,3);
+ atom2.writeID4(PCP_CHAN_PKT_TYPE,PCP_CHAN_PKT_DATA);
+ atom2.writeInt(PCP_CHAN_PKT_POS,rawPack.pos);
+ atom2.writeBytes(PCP_CHAN_PKT_DATA,rawPack.data,rawPack.len);
+
+#ifdef WIN32
+ sock->bufferingWrite(pbuf, mems.getPosition());
+ lastSkipTime = sock->bufList.lastSkipTime;
+ lastSkipCount = sock->bufList.skipCount;
+#else
+ sock->write(pbuf, mems.getPosition());
+#endif
+ }
+
+ if (rawPack.pos < streamPos)
+ LOG_DEBUG("pcp: skip back %d",rawPack.pos-streamPos);
+
+ //LOG_DEBUG("Sending %d-%d (%d,%d,%d)",rawPack.pos,rawPack.pos+rawPack.len,ch->streamPos,ch->rawData.getLatestPos(),ch->rawData.getOldestPos());
+
+ streamPos = rawPack.pos+rawPack.len;
+ }
+ } else {
+ pcpStream->flush(*sock);
+ throw StreamException("Channel not found");
+ }
+
+#ifdef WIN32
+ sock->bufferingWrite(NULL, 0);
+ lastSkipTime = sock->bufList.lastSkipTime;
+ lastSkipCount = sock->bufList.skipCount;
+#endif
+ BroadcastState bcs;
+ bcs.servent_id = servent_id;
+// error = pcpStream->readPacket(*sock,bcs);
+ do {
+ error = pcpStream->readPacket(*sock,bcs);
+ if (error)
+ throw StreamException("PCP exception");
+ } while (sock->readReady() || pcpStream->outData.numPending());
+
+ sys->sleepIdle();
+
+ }
+
+ LOG_DEBUG("PCP channel stream closed normally.");
+
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Stream channel: %s",e.msg);
+ }
+
+ try
+ {
+ atom.writeInt(PCP_QUIT,error);
+ }catch(StreamException &) {}
+
+}
+
+// -----------------------------------
+int Servent::serverProc(ThreadInfo *thread)
+{
+// thread->lock();
+
+
+ Servent *sv = (Servent*)thread->data;
+
+ try
+ {
+ if (!sv->sock)
+ throw StreamException("Server has no socket");
+
+ sv->setStatus(S_LISTENING);
+
+
+ char servIP[64];
+ sv->sock->host.toStr(servIP);
+
+ if (servMgr->isRoot)
+ LOG_DEBUG("Root Server started: %s",servIP);
+ else
+ LOG_DEBUG("Server started: %s",servIP);
+
+
+ while ((thread->active) && (sv->sock->active()))
+ {
+ if (servMgr->numActiveOnPort(sv->sock->host.port) < servMgr->maxServIn)
+ {
+ ClientSocket *cs = sv->sock->accept();
+ if (cs)
+ {
+ LOG_DEBUG("accepted incoming");
+ Servent *ns = servMgr->allocServent();
+ if (ns)
+ {
+ servMgr->lastIncoming = sys->getTime();
+ ns->servPort = sv->sock->host.port;
+ ns->networkID = servMgr->networkID;
+ ns->initIncoming(cs,sv->allow);
+ }else
+ LOG_ERROR("Out of servents");
+ }
+ }
+ sys->sleep(100);
+ }
+ }catch(StreamException &e)
+ {
+ LOG_ERROR("Server Error: %s:%d",e.msg,e.err);
+ }
+
+
+ LOG_DEBUG("Server stopped");
+
+ sv->kill();
+ sys->endThread(thread);
+ return 0;
+}
+
+// -----------------------------------
+bool Servent::writeVariable(Stream &s, const String &var)
+{
+ char buf[1024];
+
+ if (var == "type")
+ strcpy(buf,getTypeStr());
+ else if (var == "status")
+ strcpy(buf,getStatusStr());
+ else if (var == "address")
+ {
+ if (servMgr->enableGetName) //JP-EX s
+ {
+ getHost().toStr(buf);
+ char h_ip[64];
+ Host h = getHost();
+ h.toStr(h_ip);
+
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+ bool ishit,isfw;
+ ishit = isfw = false;
+ int numRelay = 0;
+ if (numHits)
+ {
+ for(int k=0; k<numHits; k++)
+ {
+ ChanHitList *chl = hits[k];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++)
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h.ip == hit->host.ip))
+ {
+ ishit = true;
+ if (hit->firewalled)
+ isfw = true;
+ numRelay += hit->numRelays;
+ }
+ }
+ }
+ }
+ }
+ strcpy(buf,"");
+ if (ishit == true)
+ {
+ if (isfw == true)
+ {
+ if (numRelay== 0)
+ strcat(buf,"<font color=red>");
+ else
+ strcat(buf,"<font color=orange>");
+ }
+ else
+ strcat(buf,"<font color=green>");
+ }
+ strcat(buf,h_ip);
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,h.ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ if (ishit == true)
+ {
+ strcat(buf,"</font>");
+ }
+ } //JP-EX e*/
+
+
+ bool isfw = false;
+ bool isRelay = true;
+ int numRelay = 0;
+ ChanHitList *chl = chanMgr->findHitListByID(chanID);
+ if (chl){
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if (hit->host.isValid() && (h.ip == hit->host.ip)){
+ isfw = hit->firewalled;
+ isRelay = hit->relay;
+ numRelay = hit->numRelays;
+ break;
+ }
+ hit = hit->next;
+ }
+ }
+ strcpy(buf, "");
+ if (isfw){
+ if (numRelay == 0){
+ strcat(buf,"<font color=red>");
+ } else {
+ strcat(buf,"<font color=orange>");
+ }
+ } else {
+ if (!isRelay){
+ if (numRelay==0){
+ strcpy(buf,"<font color=purple>");
+ } else {
+ strcpy(buf,"<font color=blue>");
+ }
+ } else {
+ strcpy(buf,"<font color=green>");
+ }
+ }
+ strcat(buf,h_ip);
+ char h_name[128];
+ if (ClientSocket::getHostname(h_name,h.ip))
+ {
+ strcat(buf,"[");
+ strcat(buf,h_name);
+ strcat(buf,"]");
+ }
+ strcat(buf,"</font>");
+ }
+ else
+ getHost().toStr(buf);
+ }
+ else if (var == "agent")
+ strcpy(buf,agent.cstr());
+ else if (var == "bitrate")
+ {
+ if (sock)
+ {
+ unsigned int tot = sock->bytesInPerSec+sock->bytesOutPerSec;
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(tot));
+ }else
+ strcpy(buf,"0");
+ }else if (var == "uptime")
+ {
+ String uptime;
+ if (lastConnect)
+ uptime.setFromStopwatch(sys->getTime()-lastConnect);
+ else
+ uptime.set("-");
+ strcpy(buf,uptime.cstr());
+ }else if (var.startsWith("gnet."))
+ {
+
+ float ctime = (float)(sys->getTime()-lastConnect);
+ if (var == "gnet.packetsIn")
+ sprintf(buf,"%d",gnuStream.packetsIn);
+ else if (var == "gnet.packetsInPerSec")
+ sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsIn)/ctime:0);
+ else if (var == "gnet.packetsOut")
+ sprintf(buf,"%d",gnuStream.packetsOut);
+ else if (var == "gnet.packetsOutPerSec")
+ sprintf(buf,"%.1f",ctime>0?((float)gnuStream.packetsOut)/ctime:0);
+ else if (var == "gnet.normQueue")
+ sprintf(buf,"%d",outPacketsNorm.numPending());
+ else if (var == "gnet.priQueue")
+ sprintf(buf,"%d",outPacketsPri.numPending());
+ else if (var == "gnet.flowControl")
+ sprintf(buf,"%d",flowControl?1:0);
+ else if (var == "gnet.routeTime")
+ {
+ int nr = seenIDs.numUsed();
+ unsigned int tim = sys->getTime()-seenIDs.getOldest();
+
+ String tstr;
+ tstr.setFromStopwatch(tim);
+
+ if (nr)
+ strcpy(buf,tstr.cstr());
+ else
+ strcpy(buf,"-");
+ }
+ else
+ return false;
+
+ }else
+ return false;
+
+ s.writeString(buf);
+
+ return true;
+}
--- /dev/null
+// ------------------------------------------------
+// File : servent.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#ifndef _SERVENT_H
+#define _SERVENT_H
+
+// ----------------------------------
+#include "socket.h"
+#include "sys.h"
+#include "gnutella.h"
+#include "channel.h"
+#include "http.h"
+#include "rtsp.h"
+#include "pcp.h"
+
+class HTML;
+
+class AtomStream;
+
+// ----------------------------------
+// Servent handles the actual connection between clients
+class Servent
+{
+public:
+
+ enum
+ {
+ MAX_HASH = 500, // max. amount of packet hashes Servents can store
+ MAX_OUTPACKETS = 32 // max. output packets per queue (normal/priority)
+ };
+
+ enum TYPE
+ {
+ T_NONE, // Not allocated
+ T_INCOMING, // Unknown incoming
+ T_SERVER, // The main server
+ T_RELAY, // Outgoing relay
+ T_DIRECT, // Outgoing direct connection
+ T_COUT, // PCP out connection
+ T_CIN, // PCP in connection
+ T_PGNU // old protocol connection
+ };
+
+ enum STATUS
+ {
+ S_NONE,
+ S_CONNECTING,
+ S_PROTOCOL,
+ S_HANDSHAKE,
+ S_CONNECTED,
+ S_CLOSING,
+ S_LISTENING,
+ S_TIMEOUT,
+ S_REFUSED,
+ S_VERIFIED,
+ S_ERROR,
+ S_WAIT,
+ S_FREE
+ };
+
+ enum PROTOCOL
+ {
+ P_UNKNOWN,
+ P_GNUTELLA06,
+ P_PCP
+ };
+
+
+ enum SORT
+ {
+ SORT_NAME = 0,
+ SORT_BITRATE,
+ SORT_LISTENERS,
+ SORT_HOSTS,
+ SORT_TYPE,
+ SORT_GENRE
+ };
+
+ enum ALLOW
+ {
+ ALLOW_HTML = 0x01,
+ ALLOW_BROADCAST = 0x02,
+ ALLOW_NETWORK = 0x04,
+ ALLOW_DIRECT = 0x08,
+ ALLOW_ALL = 0xff
+ };
+
+ Servent(int);
+ ~Servent();
+
+ void reset();
+ bool initServer(Host &);
+ void initIncoming(ClientSocket *,unsigned int);
+ void initOutgoing(TYPE);
+ void initGIV(Host &, GnuID &);
+ void initPCP(Host &);
+
+ void checkFree();
+
+
+
+
+ // funcs for handling status/type
+ void setStatus(STATUS);
+ static char * getTypeStr(Servent::TYPE t) {return typeMsgs[t];}
+ char * getTypeStr() {return getTypeStr(type);}
+ char * getStatusStr() {return statusMsgs[status];}
+ int getOutput();
+ void addBytes(unsigned int);
+ bool isOlderThan(Servent *s)
+ {
+ if (s)
+ {
+ unsigned int t = sys->getTime();
+ return ((t-lastConnect) > (t-s->lastConnect));
+ }else
+ return true;
+ }
+
+
+
+ // static funcs that do the actual work in the servent thread
+ static THREAD_PROC serverProc(ThreadInfo *);
+ static THREAD_PROC outgoingProc(ThreadInfo *);
+ static THREAD_PROC incomingProc(ThreadInfo *);
+ static THREAD_PROC givProc(ThreadInfo *);
+ static THREAD_PROC pcpProc(ThreadInfo *);
+ static THREAD_PROC fetchProc(ThreadInfo *);
+
+ static bool pingHost(Host &,GnuID &);
+
+ bool getLocalURL(char *);
+ bool getLocalTypeURL(char *, ChanInfo::TYPE);
+
+ // various types of handshaking are needed
+ void handshakePLS(ChanHitList **, int, bool);
+ void handshakePLS(ChanInfo &, bool);
+
+ void handshakeHTML(char *);
+ void handshakeXML();
+ void handshakeCMD(char *);
+ bool handshakeAuth(HTTP &,const char *,bool);
+ void handshakeIn();
+ void handshakeOut();
+
+
+ void processOutPCP();
+ void processOutChannel();
+
+ bool handshakeStream(ChanInfo &);
+ void handshakeGiv(GnuID &);
+
+ void handshakeICY(Channel::SRC_TYPE,bool);
+ void handshakeIncoming();
+ void handshakePOST();
+ void handshakeRTSP(RTSP &);
+ void handshakeHTTP(HTTP &,bool);
+
+ void handshakeRemoteFile(const char *);
+ void handshakeLocalFile(const char *);
+
+ static void handshakeOutgoingPCP(AtomStream &,Host &,GnuID &,String &,bool);
+ static void handshakeIncomingPCP(AtomStream &,Host &,GnuID &,String &);
+
+ void processIncomingPCP(bool);
+
+ bool waitForChannelHeader(ChanInfo &);
+ ChanInfo findChannel(char *str,ChanInfo &);
+
+ bool writeVariable(Stream &, const String &);
+
+
+ // the "mainloop" of servents
+ void processGnutella();
+ void processRoot();
+ void processServent();
+ void processStream(bool,ChanInfo &);
+ void processPCP(bool,bool);
+
+ bool procAtoms(AtomStream &);
+ void procRootAtoms(AtomStream &,int);
+ void procHeloAtoms(AtomStream &,int,bool);
+ void procGetAtoms(AtomStream &,int);
+
+ void triggerChannel(char *,ChanInfo::PROTOCOL,bool);
+ void sendPeercastChannel();
+ void sendRawChannel(bool,bool);
+// void sendRawMultiChannel(bool,bool);
+ void sendRawMetaChannel(int);
+ void sendPCPChannel();
+ void checkPCPComms(Channel *, AtomStream &);
+
+ static void readICYHeader(HTTP &, ChanInfo &, char *);
+ bool canStream(Channel *);
+
+ bool isConnected() {return status == S_CONNECTED;}
+ bool isListening() {return status == S_LISTENING;}
+
+ bool isAllowed(int);
+ bool isFiltered(int);
+
+ // connection handling funcs
+ void createSocket();
+ void kill();
+ void abort();
+ bool isPrivate();
+ bool isLocal();
+
+
+ Host getHost();
+
+ bool outputPacket(GnuPacket &,bool);
+ bool hasSeenPacket(GnuPacket &p) {return seenIDs.contains(p.id);}
+ bool acceptGIV(ClientSocket *);
+ bool sendPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE);
+
+
+ TYPE type;
+ STATUS status;
+
+ static char *statusMsgs[],*typeMsgs[];
+ GnuStream gnuStream;
+ GnuPacket pack;
+ unsigned int lastConnect,lastPing,lastPacket;
+ String agent;
+
+ GnuIDList seenIDs;
+ GnuID networkID;
+ int serventIndex;
+
+ GnuID remoteID;
+
+ GnuID chanID;
+
+ GnuID givID;
+
+ ThreadInfo thread;
+
+
+ char loginPassword[64];
+ char loginMount[64];
+
+ bool priorityConnect;
+ bool addMetadata;
+ int nsSwitchNum;
+
+ unsigned int allow;
+
+ ClientSocket *sock,*pushSock;
+
+ WLock lock;
+
+ bool sendHeader;
+ unsigned int syncPos,streamPos;
+ int servPort;
+
+ ChanInfo::PROTOCOL outputProtocol;
+
+ GnuPacketBuffer outPacketsNorm,outPacketsPri;
+
+ unsigned int bytesPerSecond;
+ bool flowControl;
+
+ Servent *next;
+
+ PCPStream *pcpStream;
+ Cookie cookie;
+
+ int servent_id;
+ unsigned int lastSkipTime;
+ unsigned int lastSkipCount;
+ unsigned int waitPort;
+
+ int channel_id;
+};
+
+extern char *nextCGIarg(char *cp, char *cmd, char *arg);
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : servhs.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Servent handshaking, TODO: should be in its own class
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "html.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+static void termArgs(char *str)
+{
+ if (str)
+ {
+ int slen = strlen(str);
+ for(int i=0; i<slen; i++)
+ if (str[i]=='&') str[i] = 0;
+ }
+}
+// -----------------------------------
+char *nextCGIarg(char *cp, char *cmd, char *arg)
+{
+ if (!*cp)
+ return NULL;
+
+ int cnt=0;
+
+ // fetch command
+ while (*cp)
+ {
+ char c = *cp++;
+ if (c == '=')
+ break;
+ else
+ *cmd++ = c;
+
+ cnt++;
+ if (cnt >= (MAX_CGI_LEN-1))
+ break;
+ }
+ *cmd = 0;
+
+ cnt=0;
+ // fetch arg
+ while (*cp)
+ {
+ char c = *cp++;
+ if (c == '&')
+ break;
+ else
+ *arg++ = c;
+
+ cnt++;
+ if (cnt >= (MAX_CGI_LEN-1))
+ break;
+ }
+ *arg = 0;
+
+ return cp;
+}
+// -----------------------------------
+bool getCGIargBOOL(char *a)
+{
+ return (strcmp(a,"1")==0);
+}
+// -----------------------------------
+int getCGIargINT(char *a)
+{
+ return atoi(a);
+}
+
+// -----------------------------------
+void Servent::handshakeHTTP(HTTP &http, bool isHTTP)
+{
+ char *in = http.cmdLine;
+
+ if (http.isRequest("GET /"))
+ {
+ char *fn = in+4;
+
+ char *pt = strstr(fn,HTTP_PROTO1);
+ if (pt)
+ pt[-1] = 0;
+
+ if (strncmp(fn,"/admin?",7)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Admin client");
+ handshakeCMD(fn+7);
+
+ }else if (strncmp(fn,"/http/",6)==0)
+ {
+ String dirName = fn+6;
+
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (!handshakeAuth(http,fn,false))
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+
+
+ handshakeRemoteFile(dirName);
+
+
+ }else if (strncmp(fn,"/html/",6)==0)
+ {
+ String dirName = fn+1;
+
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ if (handshakeAuth(http,fn,true))
+ handshakeLocalFile(dirName);
+
+
+ }else if (strncmp(fn,"/admin/?",8)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("Admin client");
+ handshakeCMD(fn+8);
+
+ }else if (strncmp(fn,"/admin.cgi",10)==0)
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ char *pwdArg = getCGIarg(fn,"pass=");
+ char *songArg = getCGIarg(fn,"song=");
+ char *mountArg = getCGIarg(fn,"mount=");
+ char *urlArg = getCGIarg(fn,"url=");
+
+ if (pwdArg && songArg)
+ {
+ int i;
+ int slen = strlen(fn);
+ for(i=0; i<slen; i++)
+ if (fn[i]=='&') fn[i] = 0;
+
+ Channel *c=chanMgr->channel;
+ while (c)
+ {
+ if ((c->status == Channel::S_BROADCASTING) &&
+ (c->info.contentType == ChanInfo::T_MP3) )
+ {
+ // if we have a mount point then check for it, otherwise update all channels.
+ bool match=true;
+
+ if (mountArg)
+ match = strcmp(c->mount,mountArg)==0;
+
+ if (match)
+ {
+ ChanInfo newInfo = c->info;
+ newInfo.track.title.set(songArg,String::T_ESC);
+ newInfo.track.title.convertTo(String::T_UNICODE);
+
+ if (urlArg)
+ if (urlArg[0])
+ newInfo.track.contact.set(urlArg,String::T_ESC);
+ LOG_CHANNEL("Channel Shoutcast update: %s",songArg);
+ c->updateInfo(newInfo);
+ }
+ }
+ c=c->next;
+ }
+ }
+
+ }else if (strncmp(fn,"/pls/",5)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ ChanInfo info;
+ if (servMgr->getChannel(fn+5,info,isPrivate()))
+ handshakePLS(info,false);
+ else
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ }else if (strncmp(fn,"/stream/",8)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+
+ }else if (strncmp(fn,"/channel/",9)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+9,ChanInfo::SP_PCP,false);
+
+ }else
+ {
+ while (http.nextHeader());
+ http.writeLine(HTTP_SC_FOUND);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+ }
+ }
+ else if (http.isRequest("POST /"))
+ {
+ char *fn = in+5;
+
+ char *pt = strstr(fn,HTTP_PROTO1);
+ if (pt)
+ pt[-1] = 0;
+
+ if (strncmp(fn,"/pls/",5)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ ChanInfo info;
+ if (servMgr->getChannel(fn+5,info,isPrivate()))
+ handshakePLS(info,false);
+ else
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ }else if (strncmp(fn,"/stream/",8)==0)
+ {
+
+ if (!sock->host.isLocalhost())
+ if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
+
+ }else if (strncmp(fn,"/admin",7)==0)
+ {
+ if (!isAllowed(ALLOW_HTML))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Admin client");
+ while(http.nextHeader()){
+ LOG_DEBUG("%s",http.cmdLine);
+ }
+ char buf[8192];
+ if (sock->readLine(buf, sizeof(buf)) != 0){
+ handshakeCMD(buf);
+ }
+
+ }else
+ {
+ while (http.nextHeader());
+ http.writeLine(HTTP_SC_FOUND);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+ }
+ }else if (http.isRequest("GIV"))
+ {
+ HTTP http(*sock);
+
+ while (http.nextHeader()) ;
+
+ if (!isAllowed(ALLOW_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ GnuID id;
+ id.clear();
+
+ char *idstr = strstr(in,"/");
+ if (idstr)
+ id.fromStr(idstr+1);
+
+ char ipstr[64];
+ sock->host.toStr(ipstr);
+
+ if (id.isSet())
+ {
+ // at the moment we don`t really care where the GIV came from, so just give to chan. no. if its waiting.
+ Channel *ch = chanMgr->findChannelByID(id);
+
+ if (!ch)
+ throw HTTPException(HTTP_SC_NOTFOUND,404);
+
+ if (!ch->acceptGIV(sock))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr);
+
+ sock=NULL; // release this servent but dont close socket.
+ }else
+ {
+
+ if (!servMgr->acceptGIV(sock))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("Accepted GIV PCP from: %s",ipstr);
+ sock=NULL; // release this servent but dont close socket.
+ }
+
+ }else if (http.isRequest(PCX_PCP_CONNECT))
+ {
+
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ processIncomingPCP(true);
+
+ }else if (http.isRequest("PEERCAST CONNECT"))
+ {
+ if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ LOG_DEBUG("PEERCAST client");
+ processServent();
+
+ }else if (http.isRequest("SOURCE"))
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ char *mount = NULL;
+
+ char *ps;
+ if (ps=strstr(in,"ICE/1.0"))
+ {
+ mount = in+7;
+ *ps = 0;
+ LOG_DEBUG("ICE 1.0 client to %s",mount?mount:"unknown");
+ }else{
+ mount = in+strlen(in);
+ while (*--mount)
+ if (*mount == '/')
+ {
+ mount[-1] = 0; // password preceeds
+ break;
+ }
+ strcpy(loginPassword,in+7);
+
+ LOG_DEBUG("ICY client: %s %s",loginPassword,mount?mount:"unknown");
+ }
+
+ if (mount)
+ strcpy(loginMount,mount);
+
+ handshakeICY(Channel::SRC_ICECAST,isHTTP);
+ sock = NULL; // socket is taken over by channel, so don`t close it
+
+ }else if (http.isRequest(servMgr->password))
+ {
+ if (!isAllowed(ALLOW_BROADCAST))
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ strcpy(loginPassword,servMgr->password); // pwd already checked
+
+ sock->writeLine("OK2");
+ sock->writeLine("icy-caps:11");
+ sock->writeLine("");
+ LOG_DEBUG("ShoutCast client");
+
+ handshakeICY(Channel::SRC_SHOUTCAST,isHTTP);
+ sock = NULL; // socket is taken over by channel, so don`t close it
+
+ }else
+ {
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+ }
+
+}
+// -----------------------------------
+bool Servent::canStream(Channel *ch)
+{
+ if (ch==NULL)
+ return false;
+
+ if (servMgr->isDisabled)
+ return false;
+
+ if (!isPrivate())
+ {
+ Channel *c = chanMgr->channel;
+ int noRelay = 0;
+ unsigned int needRate = 0;
+ unsigned int allRate = 0;
+ while(c){
+ if (c->isPlaying()){
+ allRate += c->info.bitrate * c->localRelays();
+ if ((c != ch) && (c->localRelays() == 0)){
+ if(!isIndexTxt(c)) // for PCRaw (relay)
+ noRelay++;
+ needRate+=c->info.bitrate;
+ }
+ }
+ c = c->next;
+ }
+ int diff = servMgr->maxRelays - servMgr->numStreams(Servent::T_RELAY,false);
+ if (ch->localRelays()){
+ if (noRelay > diff){
+ noRelay = diff;
+ }
+ } else {
+ noRelay = 0;
+ needRate = 0;
+ }
+
+ // for PCRaw (relay) start.
+ bool force_off = true;
+
+ if(isIndexTxt(ch))
+ force_off = false;
+ // for PCRaw (relay) end.
+
+ LOG_DEBUG("Relay check: Max=%d Now=%d Need=%d ch=%d",
+ servMgr->maxBitrateOut, allRate, needRate, ch->info.bitrate);
+ if ( !ch->isPlaying()
+ || ch->isFull()
+// || servMgr->bitrateFull(needRate+ch->getBitrate())
+ || (allRate + needRate + ch->info.bitrate > servMgr->maxBitrateOut)
+ || ((type == T_RELAY) && servMgr->relaysFull() && force_off) // for PCRaw (relay) (force_off)
+ || ((type == T_RELAY) && (((servMgr->numStreams(Servent::T_RELAY,false) + noRelay) >= servMgr->maxRelays)) && force_off) // for PCRaw (relay) (force_off)
+ || ((type == T_DIRECT) && servMgr->directFull())
+ ){
+ LOG_DEBUG("Relay check: NG");
+ return false;
+ }
+ }
+
+ LOG_DEBUG("Relay check: OK");
+ return true;
+}
+// -----------------------------------
+void Servent::handshakeIncoming()
+{
+
+ setStatus(S_HANDSHAKE);
+
+ char buf[2048];
+ sock->readLine(buf,sizeof(buf));
+
+ char sb[64];
+ sock->host.toStr(sb);
+
+
+ if (stristr(buf,RTSP_PROTO1))
+ {
+ LOG_DEBUG("RTSP from %s '%s'",sb,buf);
+ RTSP rtsp(*sock);
+ rtsp.initRequest(buf);
+ handshakeRTSP(rtsp);
+ }else if (stristr(buf,HTTP_PROTO1))
+ {
+ LOG_DEBUG("HTTP from %s '%s'",sb,buf);
+ HTTP http(*sock);
+ http.initRequest(buf);
+ handshakeHTTP(http,true);
+ }else
+ {
+ LOG_DEBUG("Connect from %s '%s'",sb,buf);
+ HTTP http(*sock);
+ http.initRequest(buf);
+ handshakeHTTP(http,false);
+ }
+
+}
+// -----------------------------------
+void Servent::triggerChannel(char *str, ChanInfo::PROTOCOL proto,bool relay)
+{
+
+ ChanInfo info;
+// WLockBlock lb(&(chanMgr->channellock));
+
+// LOG_DEBUG("----------triggerChannel LOCK ON");
+// lb.on();
+ servMgr->getChannel(str,info,relay);
+// LOG_DEBUG("==========triggerChannel LOCK OFF");
+// lb.off();
+
+ if (proto == ChanInfo::SP_PCP)
+ type = T_RELAY;
+ else
+ type = T_DIRECT;
+
+ outputProtocol = proto;
+
+ processStream(false,info);
+
+}
+// -----------------------------------
+void writePLSHeader(Stream &s, PlayList::TYPE type)
+{
+ s.writeLine(HTTP_SC_OK);
+ s.writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+
+ const char *content;
+ switch(type)
+ {
+ case PlayList::T_PLS:
+ content = MIME_XM3U;
+ break;
+ case PlayList::T_ASX:
+ content = MIME_ASX;
+ break;
+ case PlayList::T_RAM:
+ content = MIME_RAM;
+ break;
+ default:
+ content = MIME_TEXT;
+ break;
+ }
+ s.writeLineF("%s %s",HTTP_HS_CONTENT,content);
+ s.writeLine("Content-Disposition: inline");
+ s.writeLine("Cache-Control: private" );
+ s.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+
+ s.writeLine("");
+}
+
+// -----------------------------------
+void Servent::handshakePLS(ChanInfo &info, bool doneHandshake)
+{
+ char url[256];
+
+ char in[128];
+
+ if (!doneHandshake)
+ while (sock->readLine(in,128));
+
+
+ if (getLocalTypeURL(url,info.contentType))
+ {
+
+ PlayList::TYPE type;
+
+ if ((info.contentType == ChanInfo::T_WMA) || (info.contentType == ChanInfo::T_WMV))
+ type = PlayList::T_ASX;
+ else if (info.contentType == ChanInfo::T_OGM)
+ type = PlayList::T_RAM;
+ else
+ type = PlayList::T_PLS;
+
+ writePLSHeader(*sock,type);
+
+ PlayList *pls;
+
+ pls = new PlayList(type,1);
+
+ pls->addChannel(url,info);
+
+ pls->write(*sock);
+
+ delete pls;
+ }
+}
+// -----------------------------------
+void Servent::handshakePLS(ChanHitList **cl, int num, bool doneHandshake)
+{
+ char url[256];
+ char in[128];
+
+ if (!doneHandshake)
+ while (sock->readLine(in,128));
+
+ if (getLocalURL(url))
+ {
+ writePLSHeader(*sock,PlayList::T_SCPLS);
+
+ PlayList *pls;
+
+ pls = new PlayList(PlayList::T_SCPLS,num);
+
+ for(int i=0; i<num; i++)
+ pls->addChannel(url,cl[i]->info);
+
+ pls->write(*sock);
+
+ delete pls;
+ }
+}
+// -----------------------------------
+bool Servent::getLocalURL(char *str)
+{
+ if (!sock)
+ throw StreamException("Not connected");
+
+
+ char ipStr[64];
+
+ Host h;
+
+ if (sock->host.localIP())
+ h = sock->getLocalHost();
+ else
+ h = servMgr->serverHost;
+
+ h.port = servMgr->serverHost.port;
+
+ h.toStr(ipStr);
+
+ sprintf(str,"http://%s",ipStr);
+ return true;
+}
+
+// -----------------------------------
+bool Servent::getLocalTypeURL(char *str, ChanInfo::TYPE type)
+{
+ if (!sock)
+ throw StreamException("Not connected");
+
+
+ char ipStr[64];
+
+ Host h;
+
+ if (sock->host.localIP())
+ h = sock->getLocalHost();
+ else
+ h = servMgr->serverHost;
+
+ h.port = servMgr->serverHost.port;
+
+ h.toStr(ipStr);
+ switch(type) {
+ case ChanInfo::T_WMA:
+ case ChanInfo::T_WMV:
+ sprintf(str,"mms://%s",ipStr);
+ break;
+ default:
+ sprintf(str,"http://%s",ipStr);
+ }
+ return true;
+}
+// -----------------------------------
+// Warning: testing RTSP/RTP stuff below.
+// .. moved over to seperate app now.
+// -----------------------------------
+void Servent::handshakePOST()
+{
+ char tmp[1024];
+ while (sock->readLine(tmp,sizeof(tmp)))
+ LOG_DEBUG("POST: %s",tmp);
+
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+
+
+// -----------------------------------
+void Servent::handshakeRTSP(RTSP &rtsp)
+{
+ throw HTTPException(HTTP_SC_BADREQUEST,400);
+}
+// -----------------------------------
+bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
+{
+ char user[1024],pass[1024];
+ user[0] = pass[0] = 0;
+
+ char *pwd = getCGIarg(args, "pass=");
+
+ if ((pwd) && strlen(servMgr->password))
+ {
+ String tmp = pwd;
+ char *as = strstr(tmp.cstr(),"&");
+ if (as) *as = 0;
+ if (strcmp(tmp,servMgr->password)==0)
+ {
+ while (http.nextHeader());
+ return true;
+ }
+ }
+
+ Cookie gotCookie;
+ cookie.clear();
+
+ while (http.nextHeader())
+ {
+ char *arg = http.getArgStr();
+ if (!arg)
+ continue;
+
+ switch (servMgr->authType)
+ {
+ case ServMgr::AUTH_HTTPBASIC:
+ if (http.isHeader("Authorization"))
+ http.getAuthUserPass(user,pass);
+ break;
+ case ServMgr::AUTH_COOKIE:
+ if (http.isHeader("Cookie"))
+ {
+ LOG_DEBUG("Got cookie: %s",arg);
+ char *idp=arg;
+ while ((idp = strstr(idp,"id=")))
+ {
+ idp+=3;
+ gotCookie.set(idp,sock->host.ip);
+ if (servMgr->cookieList.contains(gotCookie))
+ {
+ LOG_DEBUG("Cookie found");
+ cookie = gotCookie;
+ break;
+ }
+
+ }
+ }
+ break;
+ }
+ }
+
+ if (sock->host.isLocalhost())
+ return true;
+
+
+ switch (servMgr->authType)
+ {
+ case ServMgr::AUTH_HTTPBASIC:
+
+ if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password))
+ return true;
+ break;
+ case ServMgr::AUTH_COOKIE:
+ if (servMgr->cookieList.contains(cookie))
+ return true;
+ break;
+ }
+
+
+
+ if (servMgr->authType == ServMgr::AUTH_HTTPBASIC)
+ {
+ http.writeLine(HTTP_SC_UNAUTHORIZED);
+ http.writeLine("WWW-Authenticate: Basic realm=\"PeerCast Admin\"");
+ }else if (servMgr->authType == ServMgr::AUTH_COOKIE)
+ {
+ String file = servMgr->htmlPath;
+ file.append("/login.html");
+ if (local)
+ handshakeLocalFile(file);
+ else
+ handshakeRemoteFile(file);
+ }
+
+
+ return false;
+}
+
+// -----------------------------------
+void Servent::handshakeCMD(char *cmd)
+{
+ char result[MAX_CGI_LEN];
+ char arg[MAX_CGI_LEN];
+ char curr[MAX_CGI_LEN];
+
+ char jumpStr[128];
+ char *jumpArg=NULL;
+ bool retHTML=true;
+ strcpy(result,"OK");
+
+ HTTP http(*sock);
+ HTML html("",*sock);
+
+
+ if (!handshakeAuth(http,cmd,true))
+ return;
+
+ try
+ {
+ if (cmpCGIarg(cmd,"cmd=","redirect"))
+ {
+ char *j = getCGIarg(cmd,"url=");
+ if (j)
+ {
+ termArgs(cmd);
+ String url;
+ url.set(j,String::T_ESC);
+ url.convertTo(String::T_ASCII);
+
+ if (!url.contains("http://"))
+ url.prepend("http://");
+
+ html.setRefreshURL(url.cstr());
+ html.startHTML();
+ html.addHead();
+ html.startBody();
+ html.startTagEnd("h3","Please wait...");
+ html.end();
+ html.end();
+
+ }
+ }else{
+
+ if (cmpCGIarg(cmd,"cmd=","viewxml"))
+ {
+
+ handshakeXML();
+ retHTML = false;
+ }else if (cmpCGIarg(cmd,"cmd=","clearlog"))
+ {
+ sys->logBuf->clear();
+ sprintf(jumpStr,"/%s/viewlog.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","save"))
+ {
+
+ peercastInst->saveSettings();
+
+ sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }else if (cmpCGIarg(cmd,"cmd=","reg"))
+ {
+ char idstr[128];
+ chanMgr->broadcastID.toStr(idstr);
+ sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr);
+ jumpArg = jumpStr;
+ }else if (cmpCGIarg(cmd,"cmd=","edit_bcid"))
+ {
+ char *cp = cmd;
+ GnuID id;
+ BCID *bcid;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ else if (strcmp(curr,"del")==0)
+ servMgr->removeValidBCID(id);
+ else if (strcmp(curr,"valid")==0)
+ {
+ bcid = servMgr->findValidBCID(id);
+ if (bcid)
+ bcid->valid = getCGIargBOOL(arg);
+ }
+ }
+ peercastInst->saveSettings();
+ sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","add_bcid"))
+ {
+ BCID *bcid = new BCID();
+
+ char *cp = cmd;
+ bool result=false;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ bcid->id.fromStr(arg);
+ else if (strcmp(curr,"name")==0)
+ bcid->name.set(arg);
+ else if (strcmp(curr,"email")==0)
+ bcid->email.set(arg);
+ else if (strcmp(curr,"url")==0)
+ bcid->url.set(arg);
+ else if (strcmp(curr,"valid")==0)
+ bcid->valid = getCGIargBOOL(arg);
+ else if (strcmp(curr,"result")==0)
+ result = true;
+
+ }
+
+ LOG_DEBUG("Adding BCID : %s",bcid->name.cstr());
+ servMgr->addValidBCID(bcid);
+ peercastInst->saveSettings();
+ if (result)
+ {
+ http.writeLine(HTTP_SC_OK);
+ http.writeLine("");
+ http.writeString("OK");
+ }else
+ {
+ sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","apply"))
+ {
+ //servMgr->numFilters = 0;
+ ServFilter *currFilter=servMgr->filters;
+ bool beginfilt = false;
+
+ bool brRoot=false;
+ bool getUpd=false;
+ int showLog=0;
+ int allowServer1=0;
+ int allowServer2=0;
+ int newPort=servMgr->serverHost.port;
+ int enableGetName = 0;
+ int allowConnectPCST = 0;
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ // server
+ if (strcmp(curr,"serveractive")==0)
+ servMgr->autoServe = getCGIargBOOL(arg);
+ else if (strcmp(curr,"port")==0)
+ newPort = getCGIargINT(arg);
+ else if (strcmp(curr,"icymeta")==0)
+ {
+ int iv = getCGIargINT(arg);
+ if (iv < 0) iv = 0;
+ else if (iv > 16384) iv = 16384;
+
+ chanMgr->icyMetaInterval = iv;
+
+ }else if (strcmp(curr,"passnew")==0)
+ strcpy(servMgr->password,arg);
+ else if (strcmp(curr,"root")==0)
+ servMgr->isRoot = getCGIargBOOL(arg);
+ else if (strcmp(curr,"brroot")==0)
+ brRoot = getCGIargBOOL(arg);
+ else if (strcmp(curr,"getupd")==0)
+ getUpd = getCGIargBOOL(arg);
+ else if (strcmp(curr,"huint")==0)
+ chanMgr->setUpdateInterval(getCGIargINT(arg));
+ else if (strcmp(curr,"forceip")==0)
+ servMgr->forceIP = arg;
+ else if (strcmp(curr,"htmlPath")==0)
+ {
+ strcpy(servMgr->htmlPath,"html/");
+ strcat(servMgr->htmlPath,arg);
+ }else if (strcmp(curr,"djmsg")==0)
+ {
+ String msg;
+ msg.set(arg,String::T_ESC);
+ msg.convertTo(String::T_UNICODE);
+ chanMgr->setBroadcastMsg(msg);
+ }
+ else if (strcmp(curr,"pcmsg")==0)
+ {
+ servMgr->rootMsg.set(arg,String::T_ESC);
+ servMgr->rootMsg.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"minpgnu")==0)
+ servMgr->minGnuIncoming = atoi(arg);
+ else if (strcmp(curr,"maxpgnu")==0)
+ servMgr->maxGnuIncoming = atoi(arg);
+
+
+
+ // connections
+ else if (strcmp(curr,"maxcin")==0)
+ servMgr->maxControl = getCGIargINT(arg);
+
+ else if (strcmp(curr,"maxup")==0)
+ servMgr->maxBitrateOut = getCGIargINT(arg);
+ else if (strcmp(curr,"maxrelays")==0)
+ servMgr->setMaxRelays(getCGIargINT(arg));
+ else if (strcmp(curr,"maxdirect")==0)
+ servMgr->maxDirect = getCGIargINT(arg);
+ else if (strcmp(curr,"maxrelaypc")==0)
+ chanMgr->maxRelaysPerChannel = getCGIargINT(arg);
+ else if (strncmp(curr,"filt_",5)==0)
+ {
+ if (!beginfilt) {
+ servMgr->numFilters = 0;
+ beginfilt = true;
+ }
+ char *fs = curr+5;
+ {
+ if (strncmp(fs,"ip",2)==0) // ip must be first
+ {
+ currFilter = &servMgr->filters[servMgr->numFilters];
+ currFilter->init();
+ currFilter->host.fromStrIP(arg,DEFAULT_PORT);
+ if ((currFilter->host.ip) && (servMgr->numFilters < (ServMgr::MAX_FILTERS-1)))
+ {
+ servMgr->numFilters++;
+ servMgr->filters[servMgr->numFilters].init(); // clear new entry
+ }
+
+ }else if (strncmp(fs,"bn",2)==0)
+ currFilter->flags |= ServFilter::F_BAN;
+ else if (strncmp(fs,"pr",2)==0)
+ currFilter->flags |= ServFilter::F_PRIVATE;
+ else if (strncmp(fs,"nw",2)==0)
+ currFilter->flags |= ServFilter::F_NETWORK;
+ else if (strncmp(fs,"di",2)==0)
+ currFilter->flags |= ServFilter::F_DIRECT;
+ }
+ }
+
+ // client
+ else if (strcmp(curr,"clientactive")==0)
+ servMgr->autoConnect = getCGIargBOOL(arg);
+ else if (strcmp(curr,"yp")==0)
+ {
+ if (!PCP_FORCE_YP)
+ {
+ String str(arg,String::T_ESC);
+ str.convertTo(String::T_ASCII);
+ servMgr->rootHost = str;
+ }
+ }
+ else if (strcmp(curr,"yp2")==0)
+ {
+ if (!PCP_FORCE_YP)
+ {
+ String str(arg,String::T_ESC);
+ str.convertTo(String::T_ASCII);
+ servMgr->rootHost2 = str;
+ }
+ }
+ else if (strcmp(curr,"deadhitage")==0)
+ chanMgr->deadHitAge = getCGIargINT(arg);
+ else if (strcmp(curr,"refresh")==0)
+ servMgr->refreshHTML = getCGIargINT(arg);
+ else if (strcmp(curr,"auth")==0)
+ {
+ if (strcmp(arg,"cookie")==0)
+ servMgr->authType = ServMgr::AUTH_COOKIE;
+ else if (strcmp(arg,"http")==0)
+ servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+
+ }else if (strcmp(curr,"expire")==0)
+ {
+ if (strcmp(arg,"session")==0)
+ servMgr->cookieList.neverExpire = false;
+ else if (strcmp(arg,"never")==0)
+ servMgr->cookieList.neverExpire = true;
+ }
+
+ else if (strcmp(curr,"logDebug")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_DEBUG):0;
+ else if (strcmp(curr,"logErrors")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_ERROR):0;
+ else if (strcmp(curr,"logNetwork")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_NETWORK):0;
+ else if (strcmp(curr,"logChannel")==0)
+ showLog |= atoi(arg)?(1<<LogBuffer::T_CHANNEL):0;
+
+ else if (strcmp(curr,"allowHTML1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_HTML):0;
+ else if (strcmp(curr,"allowNetwork1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_NETWORK):0;
+ else if (strcmp(curr,"allowBroadcast1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_BROADCAST):0;
+ else if (strcmp(curr,"allowDirect1")==0)
+ allowServer1 |= atoi(arg)?(ALLOW_DIRECT):0;
+
+ else if (strcmp(curr,"allowHTML2")==0)
+ allowServer2 |= atoi(arg)?(ALLOW_HTML):0;
+ else if (strcmp(curr,"allowBroadcast2")==0)
+ allowServer2 |= atoi(arg)?(ALLOW_BROADCAST):0;
+
+ // JP-EX
+ else if (strcmp(curr, "autoRelayKeep") ==0)
+ servMgr->autoRelayKeep = getCGIargINT(arg);
+ else if (strcmp(curr, "autoMaxRelaySetting") ==0)
+ servMgr->autoMaxRelaySetting = getCGIargINT(arg);
+ else if (strcmp(curr, "autoBumpSkipCount") ==0)
+ servMgr->autoBumpSkipCount = getCGIargINT(arg);
+ else if (strcmp(curr, "kickPushStartRelays") ==0)
+ servMgr->kickPushStartRelays = getCGIargINT(arg);
+ else if (strcmp(curr, "kickPushInterval") ==0)
+ servMgr->kickPushInterval = getCGIargINT(arg);
+ else if (strcmp(curr, "allowConnectPCST") ==0)
+ allowConnectPCST = atoi(arg) ? 1 : 0;
+ else if (strcmp(curr, "enableGetName") ==0)
+ enableGetName = atoi(arg)? 1 : 0;
+ else if (strcmp(curr, "autoPort0Kick") ==0)
+ servMgr->autoPort0Kick = getCGIargBOOL(arg);
+ else if (strcmp(curr, "allowOnlyVP") ==0)
+ servMgr->allowOnlyVP = getCGIargBOOL(arg);
+ else if (strcmp(curr, "kickKeepTime") ==0)
+ servMgr->kickKeepTime = getCGIargINT(arg);
+
+ else if (strcmp(curr, "maxRelaysIndexTxt") ==0) // for PCRaw (relay)
+ servMgr->maxRelaysIndexTxt = getCGIargINT(arg);
+ }
+
+
+
+ servMgr->showLog = showLog;
+ servMgr->allowServer1 = allowServer1;
+ servMgr->allowServer2 = allowServer2;
+ servMgr->enableGetName = enableGetName;
+ servMgr->allowConnectPCST = allowConnectPCST;
+ if (!(servMgr->allowServer1 & ALLOW_HTML) && !(servMgr->allowServer2 & ALLOW_HTML))
+ servMgr->allowServer1 |= ALLOW_HTML;
+
+ if (servMgr->serverHost.port != newPort)
+ {
+ Host lh(ClientSocket::getIP(NULL),newPort);
+ char ipstr[64];
+ lh.toStr(ipstr);
+ sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath);
+
+ servMgr->serverHost.port = newPort;
+ servMgr->restartServer=true;
+ //html.setRefresh(3);
+ //html.setRefreshURL(jumpStr);
+ //html.startHTML();
+ //html.addHead();
+ // html.startBody();
+ // html.startTagEnd("h1","Please wait...");
+ // html.end();
+ //html.end();
+
+
+
+ //char ipstr[64];
+ //servMgr->serverHost.toStr(ipstr);
+ //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else
+ {
+ sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+
+ peercastInst->saveSettings();
+
+ peercastApp->updateSettings();
+
+ if ((servMgr->isRoot) && (brRoot))
+ servMgr->broadcastRootSettings(getUpd);
+
+
+
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","fetch"))
+ {
+
+ ChanInfo info;
+ String curl;
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"url")==0)
+ {
+ curl.set(arg,String::T_ESC);
+ curl.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"name")==0)
+ {
+ info.name.set(arg,String::T_ESC);
+ info.name.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"desc")==0)
+ {
+ info.desc.set(arg,String::T_ESC);
+ info.desc.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"genre")==0)
+ {
+ info.genre.set(arg,String::T_ESC);
+ info.genre.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"contact")==0)
+ {
+ info.url.set(arg,String::T_ESC);
+ info.url.convertTo(String::T_UNICODE);
+ }else if (strcmp(curr,"bitrate")==0)
+ {
+ info.bitrate = atoi(arg);
+ }else if (strcmp(curr,"type")==0)
+ {
+ info.contentType = ChanInfo::getTypeFromStr(arg);
+ }
+
+ }
+
+ info.bcID = chanMgr->broadcastID;
+
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ c->startURL(curl.cstr());
+
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","stopserv"))
+ {
+
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"index")==0)
+ {
+ Servent *s = servMgr->findServentByIndex(atoi(arg));
+ if (s)
+ s->abort();
+ }
+ }
+ sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","hitlist"))
+ {
+
+ bool stayConnected=hasCGIarg(cmd,"relay");
+
+ int index = 0;
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ {
+ char tmp[64];
+ sprintf(tmp,"c%d=",index);
+ if (cmpCGIarg(cmd,tmp,"1"))
+ {
+ Channel *c;
+ if (!(c=chanMgr->findChannelByID(chl->info.id)))
+ {
+ c = chanMgr->createChannel(chl->info,NULL);
+ if (!c)
+ throw StreamException("out of channels");
+ c->stayConnected = stayConnected;
+ c->startGet();
+ }
+ }
+ }
+ chl = chl->next;
+ index++;
+ }
+
+ char *findArg = getCGIarg(cmd,"keywords=");
+
+ if (hasCGIarg(cmd,"relay"))
+ {
+ sys->sleep(500);
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+ }else if (cmpCGIarg(cmd,"cmd=","clear"))
+ {
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"hostcache")==0)
+ servMgr->clearHostCache(ServHost::T_SERVENT);
+ else if (strcmp(curr,"hitlists")==0)
+ chanMgr->clearHitLists();
+ else if (strcmp(curr,"packets")==0)
+ {
+ stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND);
+ servMgr->numVersions = 0;
+ }
+ }
+
+ sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","upgrade"))
+ {
+ if (servMgr->downloadURL[0])
+ {
+ sprintf(jumpStr,"/admin?cmd=redirect&url=%s",servMgr->downloadURL);
+ jumpArg = jumpStr;
+ }
+
+
+
+
+ }else if (cmpCGIarg(cmd,"cmd=","connect"))
+ {
+
+
+ Servent *s = servMgr->servents;
+ {
+ char tmp[64];
+ sprintf(tmp,"c%d=",s->serventIndex);
+ if (cmpCGIarg(cmd,tmp,"1"))
+ {
+ if (hasCGIarg(cmd,"stop"))
+ s->thread.active = false;
+ }
+ s=s->next;
+ }
+ sprintf(jumpStr,"/%s/connections.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","shutdown"))
+ {
+ servMgr->shutdownTimer = 1;
+
+ }else if (cmpCGIarg(cmd,"cmd=","stop"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c){
+ c->thread.active = false;
+ c->thread.finish = true;
+ }
+
+ sys->sleep(500);
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","bump"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c)
+ c->bump = true;
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","keep"))
+ {
+ GnuID id;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ id.fromStr(arg);
+ }
+
+ Channel *c = chanMgr->findChannelByID(id);
+ if (c)
+ { //JP-Patch
+ //c->stayConnected = true;
+ if (!c->stayConnected)
+ {
+ //if (servMgr->getFirewall() == ServMgr::FW_OFF)
+ c->stayConnected = true;
+ }
+ else
+ c->stayConnected = false;
+ } //JP-Patch
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+ }else if (cmpCGIarg(cmd,"cmd=","relay"))
+ {
+ ChanInfo info;
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"id")==0)
+ info.id.fromStr(arg);
+ }
+
+
+ if (!chanMgr->findChannelByID(info.id))
+ {
+
+ ChanHitList *chl = chanMgr->findHitList(info);
+ if (!chl)
+ throw StreamException("channel not found");
+
+
+ Channel *c = chanMgr->createChannel(chl->info,NULL);
+ if (!c)
+ throw StreamException("out of channels");
+
+ c->stayConnected = true;
+ c->startGet();
+ }
+
+ sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+
+
+ }else if (cmpCGIarg(cmd,"net=","add"))
+ {
+
+ GnuID id;
+ id.clear();
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ if (strcmp(curr,"ip")==0)
+ {
+ Host h;
+ h.fromStrIP(arg,DEFAULT_PORT);
+ if (servMgr->addOutgoing(h,id,true))
+ LOG_NETWORK("Added connection: %s",arg);
+
+ }else if (strcmp(curr,"id")==0)
+ {
+ id.fromStr(arg);
+ }
+
+ }
+
+ }else if (cmpCGIarg(cmd,"cmd=","logout"))
+ {
+ jumpArg = "/";
+ servMgr->cookieList.remove(cookie);
+
+ }else if (cmpCGIarg(cmd,"cmd=","login"))
+ {
+ GnuID id;
+ char idstr[64];
+ id.generate();
+ id.toStr(idstr);
+
+ cookie.set(idstr,sock->host.ip);
+ servMgr->cookieList.add(cookie);
+
+ http.writeLine(HTTP_SC_FOUND);
+ if (servMgr->cookieList.neverExpire)
+ http.writeLineF("%s id=%s; path=/; expires=\"Mon, 01-Jan-3000 00:00:00 GMT\";",HTTP_HS_SETCOOKIE,idstr);
+ else
+ http.writeLineF("%s id=%s; path=/;",HTTP_HS_SETCOOKIE,idstr);
+ http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
+ http.writeLine("");
+
+ }else if (cmpCGIarg(cmd,"cmd=","setmeta"))
+ {
+ char *cp = cmd;
+ while (cp=nextCGIarg(cp,curr,arg))
+ {
+ if (strcmp(curr,"name")==0)
+ {
+/* String chname;
+ chname.set(arg,String::T_ESC);
+ chname.convertTo(String::T_ASCII);
+ for(int i=0; i<ChanMgr::MAX_CHANNELS; i++)
+ {
+ Channel *c = &chanMgr->channels[i];
+ if ((c->isActive()) && (c->status == Channel::S_BROADCASTING) && (strcmp(c->info.name.cstr(),chname.cstr())==0))
+ {
+ ChanInfo newInfo = c->info;
+
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ String chmeta;
+ chmeta.set(arg,String::T_ESC);
+ chmeta.convertTo(String::T_ASCII);
+ if (strcmp(curr,"desc")==0)
+ newInfo.desc = chmeta.cstr();
+ else if (strcmp(curr,"url")==0)
+ newInfo.url = chmeta.cstr();
+ else if (strcmp(curr,"genre")==0)
+ newInfo.genre = chmeta.cstr();
+ else if (strcmp(curr,"comment")==0)
+ newInfo.comment = chmeta.cstr();
+ else if (strcmp(curr,"t_contact")==0)
+ newInfo.track.contact = chmeta.cstr();
+ else if (strcmp(curr,"t_title")==0)
+ newInfo.track.title = chmeta.cstr();
+ else if (strcmp(curr,"t_artist")==0)
+ newInfo.track.artist = chmeta.cstr();
+ else if (strcmp(curr,"t_album")==0)
+ newInfo.track.album = chmeta.cstr();
+ else if (strcmp(curr,"t_genre")==0)
+ newInfo.track.genre = chmeta.cstr();
+ }
+ c->updateInfo(newInfo);
+ char idstr[64];
+ newInfo.id.toStr(idstr);
+ sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+ jumpArg = jumpStr;
+ break;
+ }
+ }*/
+ String chname;
+ chname.set(arg,String::T_ESC);
+ chname.convertTo(String::T_ASCII);
+
+ Channel *c = chanMgr->findChannelByName(chname.cstr());
+ if (c && (c->isActive()) && (c->status == Channel::S_BROADCASTING)){
+ ChanInfo newInfo = c->info;
+ while (cmd=nextCGIarg(cmd,curr,arg))
+ {
+ String chmeta;
+ chmeta.set(arg,String::T_ESC);
+ chmeta.convertTo(String::T_ASCII);
+ if (strcmp(curr,"desc")==0)
+ newInfo.desc = chmeta.cstr();
+ else if (strcmp(curr,"url")==0)
+ newInfo.url = chmeta.cstr();
+ else if (strcmp(curr,"genre")==0)
+ newInfo.genre = chmeta.cstr();
+ else if (strcmp(curr,"comment")==0)
+ newInfo.comment = chmeta.cstr();
+ else if (strcmp(curr,"t_contact")==0)
+ newInfo.track.contact = chmeta.cstr();
+ else if (strcmp(curr,"t_title")==0)
+ newInfo.track.title = chmeta.cstr();
+ else if (strcmp(curr,"t_artist")==0)
+ newInfo.track.artist = chmeta.cstr();
+ else if (strcmp(curr,"t_album")==0)
+ newInfo.track.album = chmeta.cstr();
+ else if (strcmp(curr,"t_genre")==0)
+ newInfo.track.genre = chmeta.cstr();
+ }
+ c->updateInfo(newInfo);
+ char idstr[64];
+ newInfo.id.toStr(idstr);
+ sprintf(jumpStr,"/%s/relayinfo.html?id=%s",servMgr->htmlPath,idstr);
+ jumpArg = jumpStr;
+ }
+ }
+ }
+ if (!jumpArg)
+ {
+ jumpArg = "/";
+ }
+
+ }else{
+
+ sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
+ jumpArg = jumpStr;
+ }
+ }
+
+ }catch(StreamException &e)
+ {
+ html.startTagEnd("h1","ERROR - %s",e.msg);
+ LOG_ERROR("html: %s",e.msg);
+ }
+
+
+ if (retHTML)
+ {
+ if (jumpArg)
+ {
+ String jmp(jumpArg,String::T_HTML);
+ jmp.convertTo(String::T_ASCII);
+ html.locateTo(jmp.cstr());
+ }
+ }
+
+
+}
+// -----------------------------------
+static XML::Node *createChannelXML(Channel *c)
+{
+ XML::Node *n = c->info.createChannelXML();
+ n->add(c->createRelayXML(true));
+ n->add(c->info.createTrackXML());
+// n->add(c->info.createServentXML());
+ return n;
+}
+// -----------------------------------
+static XML::Node *createChannelXML(ChanHitList *chl)
+{
+ XML::Node *n = chl->info.createChannelXML();
+ n->add(chl->createXML());
+ n->add(chl->info.createTrackXML());
+// n->add(chl->info.createServentXML());
+ return n;
+}
+// -----------------------------------
+void Servent::handshakeXML()
+{
+ int i;
+
+
+
+ XML xml;
+
+ XML::Node *rn = new XML::Node("peercast");
+ xml.setRoot(rn);
+
+
+ rn->add(new XML::Node("servent uptime=\"%d\"",servMgr->getUptime()));
+
+ rn->add(new XML::Node("bandwidth out=\"%d\" in=\"%d\"",
+ stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT),
+ stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)
+ ));
+
+ rn->add(new XML::Node("connections total=\"%d\" relays=\"%d\" direct=\"%d\"",servMgr->totalConnected(),servMgr->numStreams(Servent::T_RELAY,true),servMgr->numStreams(Servent::T_DIRECT,true)));
+
+ XML::Node *an = new XML::Node("channels_relayed total=\"%d\"",chanMgr->numChannels());
+ rn->add(an);
+
+ Channel *c = chanMgr->channel;
+ while (c)
+ {
+ if (c->isActive())
+ an->add(createChannelXML(c));
+ c=c->next;
+ }
+
+
+ // add public channels
+ {
+ XML::Node *fn = new XML::Node("channels_found total=\"%d\"",chanMgr->numHitLists());
+ rn->add(fn);
+
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ fn->add(createChannelXML(chl));
+ chl = chl->next;
+ }
+ }
+
+
+#if 0
+ if (servMgr->isRoot)
+ {
+ // add private channels
+ {
+ XML::Node *pn = new XML::Node("priv_channels");
+ rn->add(pn);
+
+ ChanHitList *chl = chanMgr->hitlist;
+ while (chl)
+ {
+ if (chl->isUsed())
+ if (chl->info.isPrivate())
+ pn->add(createChannelXML(chl));
+ chl = chl->next;
+ }
+ }
+ }
+#endif
+
+ XML::Node *hc = new XML::Node("host_cache");
+ for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+ {
+ ServHost *sh = &servMgr->hostCache[i];
+ if (sh->type != ServHost::T_NONE)
+ {
+ char ipstr[64];
+ sh->host.toStr(ipstr);
+
+ hc->add(new XML::Node("host ip=\"%s\" type=\"%s\" time=\"%d\"",ipstr,ServHost::getTypeStr(sh->type),sh->time));
+
+ }
+ }
+ rn->add(hc);
+
+
+ sock->writeLine(HTTP_SC_OK);
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML);
+ sock->writeLine("Connection: close");
+
+ sock->writeLine("");
+
+ xml.write(*sock);
+
+}
+// -----------------------------------
+void Servent::readICYHeader(HTTP &http, ChanInfo &info, char *pwd)
+{
+ char *arg = http.getArgStr();
+ if (!arg) return;
+
+ if (http.isHeader("x-audiocast-name") || http.isHeader("icy-name") || http.isHeader("ice-name"))
+ {
+ info.name.set(arg,String::T_ASCII);
+ info.name.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url"))
+ info.url.set(arg,String::T_ASCII);
+ else if (http.isHeader("x-audiocast-bitrate") || (http.isHeader("icy-br")) || http.isHeader("ice-bitrate") || http.isHeader("icy-bitrate"))
+ info.bitrate = atoi(arg);
+ else if (http.isHeader("x-audiocast-genre") || http.isHeader("ice-genre") || http.isHeader("icy-genre"))
+ {
+ info.genre.set(arg,String::T_ASCII);
+ info.genre.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description"))
+ {
+ info.desc.set(arg,String::T_ASCII);
+ info.desc.convertTo(String::T_UNICODE);
+
+ }else if (http.isHeader("Authorization"))
+ http.getAuthUserPass(NULL,pwd);
+ else if (http.isHeader(PCX_HS_CHANNELID))
+ info.id.fromStr(arg);
+ else if (http.isHeader("ice-password"))
+ {
+ if (pwd)
+ if (strlen(arg) < 64)
+ strcpy(pwd,arg);
+ }else if (http.isHeader("content-type"))
+ {
+ if (stristr(arg,MIME_OGG))
+ info.contentType = ChanInfo::T_OGG;
+ else if (stristr(arg,MIME_XOGG))
+ info.contentType = ChanInfo::T_OGG;
+
+ else if (stristr(arg,MIME_MP3))
+ info.contentType = ChanInfo::T_MP3;
+ else if (stristr(arg,MIME_XMP3))
+ info.contentType = ChanInfo::T_MP3;
+
+ else if (stristr(arg,MIME_WMA))
+ info.contentType = ChanInfo::T_WMA;
+ else if (stristr(arg,MIME_WMV))
+ info.contentType = ChanInfo::T_WMV;
+ else if (stristr(arg,MIME_ASX))
+ info.contentType = ChanInfo::T_ASX;
+
+ else if (stristr(arg,MIME_NSV))
+ info.contentType = ChanInfo::T_NSV;
+ else if (stristr(arg,MIME_RAW))
+ info.contentType = ChanInfo::T_RAW;
+
+ else if (stristr(arg,MIME_MMS))
+ info.srcProtocol = ChanInfo::SP_MMS;
+ else if (stristr(arg,MIME_XPCP))
+ info.srcProtocol = ChanInfo::SP_PCP;
+ else if (stristr(arg,MIME_XPEERCAST))
+ info.srcProtocol = ChanInfo::SP_PEERCAST;
+
+ else if (stristr(arg,MIME_XSCPLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_PLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_XPLS))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_M3U))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_MPEGURL))
+ info.contentType = ChanInfo::T_PLS;
+ else if (stristr(arg,MIME_TEXT))
+ info.contentType = ChanInfo::T_PLS;
+
+
+ }
+
+}
+
+// -----------------------------------
+void Servent::handshakeICY(Channel::SRC_TYPE type, bool isHTTP)
+{
+ ChanInfo info;
+
+ HTTP http(*sock);
+
+ // default to mp3 for shoutcast DSP (doesn`t send content-type)
+ if (type == Channel::SRC_SHOUTCAST)
+ info.contentType = ChanInfo::T_MP3;
+
+ while (http.nextHeader())
+ {
+ LOG_DEBUG("ICY %s",http.cmdLine);
+ readICYHeader(http,info,loginPassword);
+ }
+
+
+
+ // check password before anything else, if needed
+ if (strcmp(servMgr->password,loginPassword)!=0)
+ {
+ if (!sock->host.isLocalhost() || strlen(loginPassword))
+ throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
+ }
+
+
+ // we need a valid IP address before we start
+ servMgr->checkFirewall();
+
+
+ // attach channel ID to name, channel ID is also encoded with IP address
+ // to help prevent channel hijacking.
+
+
+ info.id = chanMgr->broadcastID;
+ info.id.encode(NULL,info.name.cstr(),loginMount,info.bitrate);
+
+ LOG_DEBUG("Incoming source: %s : %s",info.name.cstr(),ChanInfo::getTypeStr(info.contentType));
+
+
+ if (isHTTP)
+ sock->writeStringF("%s\n\n",HTTP_SC_OK);
+ else
+ sock->writeLine("OK");
+
+ Channel *c = chanMgr->findChannelByID(info.id);
+ if (c)
+ {
+ LOG_CHANNEL("ICY channel already active, closing old one");
+ c->thread.shutdown();
+ }
+
+
+ info.comment = chanMgr->broadcastMsg;
+ info.bcID = chanMgr->broadcastID;
+
+ c = chanMgr->createChannel(info,loginMount);
+ if (!c)
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+ c->startICY(sock,type);
+}
+
+
+// -----------------------------------
+void Servent::handshakeLocalFile(const char *fn)
+{
+ HTTP http(*sock);
+ String fileName;
+
+ if (servMgr->getModulePath) //JP-EX
+ {
+ peercastApp->getDirectory();
+ fileName = servMgr->modulePath;
+ }else
+ fileName = peercastApp->getPath();
+
+ fileName.append(fn);
+
+ LOG_DEBUG("Writing HTML file: %s",fileName.cstr());
+
+ HTML html("",*sock);
+
+ char *args = strstr(fileName.cstr(),"?");
+ if (args)
+ *args++=0;
+
+ if (fileName.contains(".htm"))
+ {
+ html.writeOK(MIME_HTML);
+ html.writeTemplate(fileName.cstr(),args);
+
+ }else if (fileName.contains(".css"))
+ {
+ html.writeOK(MIME_CSS);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".jpg"))
+ {
+ html.writeOK(MIME_JPEG);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".gif"))
+ {
+ html.writeOK(MIME_GIF);
+ html.writeRawFile(fileName.cstr());
+ }else if (fileName.contains(".png"))
+ {
+ html.writeOK(MIME_PNG);
+ html.writeRawFile(fileName.cstr());
+ }
+}
+
+// -----------------------------------
+void Servent::handshakeRemoteFile(const char *dirName)
+{
+ ClientSocket *rsock = sys->createSocket();
+ if (!rsock)
+ throw HTTPException(HTTP_SC_UNAVAILABLE,503);
+
+
+ const char *hostName = "www.peercast.org"; // hardwired for "security"
+
+ Host host;
+ host.fromStrName(hostName,80);
+
+
+ rsock->open(host);
+ rsock->connect();
+
+ HTTP rhttp(*rsock);
+
+ rhttp.writeLineF("GET /%s HTTP/1.0",dirName);
+ rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName);
+ rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+ rhttp.writeLine("");
+
+ String contentType;
+ bool isTemplate = false;
+ while (rhttp.nextHeader())
+ {
+ char *arg = rhttp.getArgStr();
+ if (arg)
+ {
+ if (rhttp.isHeader("content-type"))
+ contentType = arg;
+ }
+ }
+
+ MemoryStream mem(100*1024);
+ while (!rsock->eof())
+ {
+ int len=0;
+ char buf[4096];
+ len = rsock->readUpto(buf,sizeof(buf));
+ if (len==0)
+ break;
+ else
+ mem.write(buf,len);
+
+ }
+ rsock->close();
+
+ int fileLen = mem.getPosition();
+ mem.len = fileLen;
+ mem.rewind();
+
+
+ if (contentType.contains(MIME_HTML))
+ isTemplate = true;
+
+ sock->writeLine(HTTP_SC_OK);
+ sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
+ sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache");
+ sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr());
+
+ sock->writeLine("");
+
+ if (isTemplate)
+ {
+ HTML html("",*sock);
+ html.readTemplate(mem,sock,0);
+ }else
+ sock->write(mem.buf,fileLen);
+
+ mem.free2();
+}
--- /dev/null
+// ------------------------------------------------
+// File : servmgr.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Management class for handling multiple servent connections.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <stdlib.h>
+#include "servent.h"
+#include "servmgr.h"
+#include "inifile.h"
+#include "stats.h"
+#include "peercast.h"
+#include "pcp.h"
+#include "atom.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo ServMgr::serverThread,ServMgr::idleThread;
+
+// -----------------------------------
+ServMgr::ServMgr()
+{
+ validBCID = NULL;
+
+ authType = AUTH_COOKIE;
+ cookieList.init();
+
+ serventNum = 0;
+
+ startTime = sys->getTime();
+
+ allowServer1 = Servent::ALLOW_ALL;
+ allowServer2 = Servent::ALLOW_BROADCAST;
+
+ clearHostCache(ServHost::T_NONE);
+ password[0]=0;
+
+ allowGnutella = false;
+ useFlowControl = true;
+
+ maxServIn = 50;
+ minGnuIncoming = 10;
+ maxGnuIncoming = 20;
+
+ lastIncoming = 0;
+
+ maxBitrateOut = 540; //JP-Patch 0-> 540
+ maxRelays = MIN_RELAYS;
+ maxDirect = 0;
+ refreshHTML = 1800;
+
+ networkID.clear();
+
+ notifyMask = 0xffff;
+
+ tryoutDelay = 10;
+ numVersions = 0;
+
+ sessionID.generate();
+
+ isDisabled = false;
+ isRoot = false;
+
+ forceIP.clear();
+
+ strcpy(connectHost,"connect1.peercast.org");
+ strcpy(htmlPath,"html/ja");
+
+ rootHost = "yp.peercast.org";
+ rootHost2 = "";
+
+ serverHost.fromStrIP("127.0.0.1",DEFAULT_PORT);
+
+ firewalled = FW_UNKNOWN;
+ allowDirect = true;
+ autoConnect = true;
+ forceLookup = true;
+ autoServe = true;
+ forceNormal = false;
+
+ maxControl = 3;
+
+ queryTTL = 7;
+
+ totalStreams = 0;
+ firewallTimeout = 30;
+ pauseLog = false;
+ showLog = 0;
+
+ shutdownTimer = 0;
+
+ downloadURL[0] = 0;
+ rootMsg.clear();
+
+
+ restartServer=false;
+
+ setFilterDefaults();
+
+ servents = NULL;
+
+ modulePath[0] = 0; //JP-EX
+ kickPushStartRelays = 1; //JP-EX
+ kickPushInterval = 60; //JP-EX
+ kickPushTime = 0; //JP-EX
+ autoRelayKeep = 2; //JP-EX
+ autoMaxRelaySetting = 0; //JP-EX
+ autoBumpSkipCount = 50; //JP-EX
+ enableGetName = 1; //JP-EX
+ allowConnectPCST = 0; //JP-EX
+ getModulePath = true; //JP-EX
+ clearPLS = false; //JP-EX
+ writeLogFile = false; //JP-EX
+
+ autoPort0Kick = false;
+ allowOnlyVP = false;
+ kickKeepTime = 0;
+ vpDebug = false;
+ saveIniChannel = true;
+ saveGuiPos = false;
+ keepDownstreams = true;
+
+ chanLog="";
+
+ maxRelaysIndexTxt = 1; // for PCRaw (relay)
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(int index)
+{
+ int cnt = 0;
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ if (cnt == index)
+ return bcid;
+ cnt++;
+ bcid=bcid->next;
+ }
+ return 0;
+}
+// -----------------------------------
+BCID *ServMgr::findValidBCID(GnuID &id)
+{
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ if (bcid->id.isSame(id))
+ return bcid;
+ bcid=bcid->next;
+ }
+ return 0;
+}
+// -----------------------------------
+void ServMgr::removeValidBCID(GnuID &id)
+{
+ BCID *bcid = validBCID,*prev=0;
+ while (bcid)
+ {
+ if (bcid->id.isSame(id))
+ {
+ if (prev)
+ prev->next = bcid->next;
+ else
+ validBCID = bcid->next;
+ return;
+ }
+ prev = bcid;
+ bcid=bcid->next;
+ }
+}
+// -----------------------------------
+void ServMgr::addValidBCID(BCID *bcid)
+{
+ removeValidBCID(bcid->id);
+
+ bcid->next = validBCID;
+ validBCID = bcid;
+}
+
+// -----------------------------------
+void ServMgr::connectBroadcaster()
+{
+ if (!rootHost.isEmpty())
+ {
+ if (!numUsed(Servent::T_COUT))
+ {
+ Servent *sv = allocServent();
+ if (sv)
+ {
+ sv->initOutgoing(Servent::T_COUT);
+ sys->sleep(3000);
+ }
+ }
+ }
+}
+// -----------------------------------
+void ServMgr::addVersion(unsigned int ver)
+{
+ for(int i=0; i<numVersions; i++)
+ if (clientVersions[i] == ver)
+ {
+ clientCounts[i]++;
+ return;
+ }
+
+ if (numVersions < MAX_VERSIONS)
+ {
+ clientVersions[numVersions] = ver;
+ clientCounts[numVersions] = 1;
+ numVersions++;
+ }
+}
+
+// -----------------------------------
+void ServMgr::setFilterDefaults()
+{
+ numFilters = 0;
+
+ filters[numFilters].host.fromStrIP("255.255.255.255",0);
+// filters[numFilters].flags = ServFilter::F_NETWORK|ServFilter::F_DIRECT;
+ filters[numFilters].flags = ServFilter::F_NETWORK;
+
+ numFilters++;
+
+}
+
+// -----------------------------------
+void ServMgr::setPassiveSearch(unsigned int t)
+{
+// if ((t > 0) && (t < 60))
+// t = 60;
+// passiveSearch = t;
+}
+// -----------------------------------
+bool ServMgr::seenHost(Host &h, ServHost::TYPE type,unsigned int time)
+{
+ time = sys->getTime()-time;
+
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == type)
+ if (hostCache[i].host.ip == h.ip)
+ if (hostCache[i].time >= time)
+ return true;
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::addHost(Host &h, ServHost::TYPE type, unsigned int time)
+{
+ int i;
+ if (!h.isValid())
+ return;
+
+ ServHost *sh=NULL;
+
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == type)
+ if (hostCache[i].host.isSame(h))
+ {
+ sh = &hostCache[i];
+ break;
+ }
+
+ char str[64];
+ h.toStr(str);
+
+ if (!sh)
+ LOG_DEBUG("New host: %s - %s",str,ServHost::getTypeStr(type));
+ else
+ LOG_DEBUG("Old host: %s - %s",str,ServHost::getTypeStr(type));
+
+ h.value = 0; // make sure dead count is zero
+ if (!sh)
+ {
+
+
+ // find empty slot
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == ServHost::T_NONE)
+ {
+ sh = &hostCache[i];
+ break;
+ }
+
+ // otherwise, find oldest host and replace
+ if (!sh)
+ for(i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type != ServHost::T_NONE)
+ {
+ if (sh)
+ {
+ if (hostCache[i].time < sh->time)
+ sh = &hostCache[i];
+ }else{
+ sh = &hostCache[i];
+ }
+ }
+ }
+
+ if (sh)
+ sh->init(h,type,time);
+}
+
+// -----------------------------------
+void ServMgr::deadHost(Host &h,ServHost::TYPE t)
+{
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if (hostCache[i].type == t)
+ if (hostCache[i].host.ip == h.ip)
+ if (hostCache[i].host.port == h.port)
+ hostCache[i].init();
+}
+// -----------------------------------
+void ServMgr::clearHostCache(ServHost::TYPE type)
+{
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+ hostCache[i].init();
+}
+
+// -----------------------------------
+unsigned int ServMgr::numHosts(ServHost::TYPE type)
+{
+ unsigned int cnt = 0;
+ for(int i=0; i<MAX_HOSTCACHE; i++)
+ if ((hostCache[i].type == type) || (type == ServHost::T_NONE))
+ cnt++;
+ return cnt;
+}
+// -----------------------------------
+int ServMgr::getNewestServents(Host *hl,int max,Host &rh)
+{
+ int cnt=0;
+ for(int i=0; i<max; i++)
+ {
+ // find newest host not in list
+ ServHost *sh=NULL;
+ for(int j=0; j<MAX_HOSTCACHE; j++)
+ {
+ // find newest servent
+ if (hostCache[j].type == ServHost::T_SERVENT)
+ if (!(rh.globalIP() && !hostCache[j].host.globalIP()))
+ {
+ // and not in list already
+ bool found=false;
+ for(int k=0; k<cnt; k++)
+ if (hl[k].isSame(hostCache[j].host))
+ {
+ found=true;
+ break;
+ }
+
+ if (!found)
+ {
+ if (!sh)
+ {
+ sh = &hostCache[j];
+ }else{
+ if (hostCache[j].time > sh->time)
+ sh = &hostCache[j];
+ }
+ }
+ }
+ }
+
+ // add to list
+ if (sh)
+ hl[cnt++]=sh->host;
+ }
+
+ return cnt;
+}
+// -----------------------------------
+ServHost ServMgr::getOutgoingServent(GnuID &netid)
+{
+ ServHost host;
+
+ Host lh(ClientSocket::getIP(NULL),0);
+
+ // find newest host not in list
+ ServHost *sh=NULL;
+ for(int j=0; j<MAX_HOSTCACHE; j++)
+ {
+ ServHost *hc=&hostCache[j];
+ // find newest servent not already connected.
+ if (hc->type == ServHost::T_SERVENT)
+ {
+ if (!((lh.globalIP() && !hc->host.globalIP()) || lh.isSame(hc->host)))
+ {
+#if 0
+ if (!findServent(Servent::T_OUTGOING,hc->host,netid))
+ {
+ if (!sh)
+ {
+ sh = hc;
+ }else{
+ if (hc->time > sh->time)
+ sh = hc;
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ if (sh)
+ host = *sh;
+
+ return host;
+}
+// -----------------------------------
+Servent *ServMgr::findOldestServent(Servent::TYPE type, bool priv)
+{
+ Servent *oldest=NULL;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ if (s->thread.active)
+ if (s->isOlderThan(oldest))
+ if (s->isPrivate() == priv)
+ oldest = s;
+ s=s->next;
+ }
+ return oldest;
+}
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE type, Host &host, GnuID &netid)
+{
+ lock.on();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ {
+ Host h = s->getHost();
+ if (h.isSame(host) && s->networkID.isSame(netid))
+ {
+ lock.off();
+ return s;
+ }
+ }
+ s=s->next;
+ }
+ lock.off();
+ return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(unsigned int ip, unsigned short port, GnuID &netid)
+{
+ lock.on();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type != Servent::T_NONE)
+ {
+ Host h = s->getHost();
+ if ((h.ip == ip) && (h.port == port) && (s->networkID.isSame(netid)))
+ {
+ lock.off();
+ return s;
+ }
+ }
+ s=s->next;
+ }
+ lock.off();
+ return NULL;
+
+}
+
+// -----------------------------------
+Servent *ServMgr::findServent(Servent::TYPE t)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == t)
+ return s;
+ s=s->next;
+ }
+ return NULL;
+}
+// -----------------------------------
+Servent *ServMgr::findServentByIndex(int id)
+{
+ Servent *s = servents;
+ int cnt=0;
+ while (s)
+ {
+ if (cnt == id)
+ return s;
+ cnt++;
+ s=s->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::findServentByServentID(int id)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (id == s->servent_id){
+ return s;
+ }
+ s=s->next;
+ }
+ return NULL;
+}
+
+// -----------------------------------
+Servent *ServMgr::allocServent()
+{
+ lock.on();
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->status == Servent::S_FREE)
+ break;
+ s=s->next;
+ }
+
+ if (!s)
+ {
+ s = new Servent(++serventNum);
+ s->next = servents;
+ servents = s;
+
+ LOG_DEBUG("allocated servent %d",serventNum);
+ }else
+ LOG_DEBUG("reused servent %d",s->serventIndex);
+
+
+ s->reset();
+
+ lock.off();
+
+ return s;
+}
+// --------------------------------------------------
+void ServMgr::closeConnections(Servent::TYPE type)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == type)
+ sv->thread.active = false;
+ sv=sv->next;
+ }
+}
+
+// -----------------------------------
+unsigned int ServMgr::numConnected(int type,bool priv,unsigned int uptime)
+{
+ unsigned int cnt=0;
+
+ unsigned int ctime=sys->getTime();
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active)
+ if (s->isConnected())
+ if (s->type == type)
+ if (s->isPrivate()==priv)
+ if ((ctime-s->lastConnect) >= uptime)
+ cnt++;
+
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numConnected()
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active)
+ if (s->isConnected())
+ cnt++;
+
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numServents()
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numUsed(int type)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == type)
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActiveOnPort(int port)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active && s->sock && (s->servPort == port))
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+// -----------------------------------
+unsigned int ServMgr::numActive(Servent::TYPE tp)
+{
+ unsigned int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->thread.active && s->sock && (s->type == tp))
+ cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalOutput(bool all)
+{
+ unsigned int tot = 0;
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (all || !s->isPrivate())
+ if (s->sock)
+ tot += s->sock->bytesOutPerSec;
+ s=s->next;
+ }
+
+ return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::totalInput(bool all)
+{
+ unsigned int tot = 0;
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (all || !s->isPrivate())
+ if (s->sock)
+ tot += s->sock->bytesInPerSec;
+ s=s->next;
+ }
+
+ return tot;
+}
+
+// -----------------------------------
+unsigned int ServMgr::numOutgoing()
+{
+ int cnt=0;
+
+ Servent *s = servents;
+ while (s)
+ {
+// if ((s->type == Servent::T_INCOMING) ||
+// (s->type == Servent::T_OUTGOING))
+// cnt++;
+ s=s->next;
+ }
+ return cnt;
+}
+
+// -----------------------------------
+bool ServMgr::seenPacket(GnuPacket &p)
+{
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->isConnected())
+ if (s->seenIDs.contains(p.id))
+ return true;
+ s=s->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::quit()
+{
+ LOG_DEBUG("ServMgr is quitting..");
+
+ serverThread.shutdown();
+
+ idleThread.shutdown();
+
+ Servent *s = servents;
+ while (s)
+ {
+ try
+ {
+ if (s->thread.active)
+ {
+ s->thread.shutdown();
+ }
+
+ }catch(StreamException &)
+ {
+ }
+ s=s->next;
+ }
+}
+
+// -----------------------------------
+int ServMgr::broadcast(GnuPacket &pack,Servent *src)
+{
+ int cnt=0;
+ if (pack.ttl)
+ {
+ Servent *s = servents;
+ while (s)
+ {
+
+ if (s != src)
+ if (s->isConnected())
+ if (s->type == Servent::T_PGNU)
+ if (!s->seenIDs.contains(pack.id))
+ {
+
+ if (src)
+ if (!src->networkID.isSame(s->networkID))
+ continue;
+
+ if (s->outputPacket(pack,false))
+ cnt++;
+ }
+ s=s->next;
+ }
+ }
+
+ LOG_NETWORK("broadcast: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+
+ return cnt;
+}
+// -----------------------------------
+int ServMgr::route(GnuPacket &pack, GnuID &routeID, Servent *src)
+{
+ int cnt=0;
+ if (pack.ttl)
+ {
+ Servent *s = servents;
+ while (s)
+ {
+ if (s != src)
+ if (s->isConnected())
+ if (s->type == Servent::T_PGNU)
+ if (!s->seenIDs.contains(pack.id))
+ if (s->seenIDs.contains(routeID))
+ {
+ if (src)
+ if (!src->networkID.isSame(s->networkID))
+ continue;
+
+ if (s->outputPacket(pack,true))
+ cnt++;
+ }
+ s=s->next;
+ }
+
+ }
+
+ LOG_NETWORK("route: %s (%d) to %d servents",GNU_FUNC_STR(pack.func),pack.ttl,cnt);
+ return cnt;
+}
+// -----------------------------------
+bool ServMgr::checkForceIP()
+{
+ if (!forceIP.isEmpty())
+ {
+ unsigned int newIP = ClientSocket::getIP(forceIP.cstr());
+ if (serverHost.ip != newIP)
+ {
+ serverHost.ip = newIP;
+ char ipstr[64];
+ serverHost.IPtoStr(ipstr);
+ LOG_DEBUG("Server IP changed to %s",ipstr);
+ return true;
+ }
+ }
+ return false;
+}
+
+// -----------------------------------
+void ServMgr::checkFirewall()
+{
+ if ((getFirewall() == FW_UNKNOWN) && !servMgr->rootHost.isEmpty())
+ {
+
+ LOG_DEBUG("Checking firewall..");
+ Host host;
+ host.fromStrName(servMgr->rootHost.cstr(),DEFAULT_PORT);
+
+ ClientSocket *sock = sys->createSocket();
+ if (!sock)
+ throw StreamException("Unable to create socket");
+ sock->setReadTimeout(30000);
+ sock->open(host);
+ sock->connect();
+
+ AtomStream atom(*sock);
+
+ atom.writeInt(PCP_CONNECT,1);
+
+ GnuID remoteID;
+ String agent;
+ Servent::handshakeOutgoingPCP(atom,sock->host,remoteID,agent,true);
+
+ atom.writeInt(PCP_QUIT,PCP_ERROR_QUIT);
+
+ sock->close();
+ delete sock;
+ }
+}
+
+// -----------------------------------
+void ServMgr::setFirewall(FW_STATE state)
+{
+ if (firewalled != state)
+ {
+ char *str;
+ switch (state)
+ {
+ case FW_ON:
+ str = "ON";
+ break;
+ case FW_OFF:
+ str = "OFF";
+ break;
+ case FW_UNKNOWN:
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+
+ LOG_DEBUG("Firewall is set to %s",str);
+ firewalled = state;
+ }
+}
+// -----------------------------------
+bool ServMgr::isFiltered(int fl, Host &h)
+{
+ for(int i=0; i<numFilters; i++)
+ if (filters[i].flags & fl)
+ if (h.isMemberOf(filters[i].host))
+ return true;
+
+ return false;
+}
+
+#if 0
+// -----------------------------------
+bool ServMgr::canServeHost(Host &h)
+{
+ if (server)
+ {
+ Host sh = server->getHost();
+
+ if (sh.globalIP() || (sh.localIP() && h.localIP()))
+ return true;
+ }
+ return false;
+}
+#endif
+
+// --------------------------------------------------
+void writeServerSettings(IniFile &iniFile, unsigned int a)
+{
+ iniFile.writeBoolValue("allowHTML",a & Servent::ALLOW_HTML);
+ iniFile.writeBoolValue("allowBroadcast",a & Servent::ALLOW_BROADCAST);
+ iniFile.writeBoolValue("allowNetwork",a & Servent::ALLOW_NETWORK);
+ iniFile.writeBoolValue("allowDirect",a & Servent::ALLOW_DIRECT);
+}
+// --------------------------------------------------
+void writeFilterSettings(IniFile &iniFile, ServFilter &f)
+{
+ char ipstr[64];
+ f.host.IPtoStr(ipstr);
+ iniFile.writeStrValue("ip",ipstr);
+ iniFile.writeBoolValue("private",f.flags & ServFilter::F_PRIVATE);
+ iniFile.writeBoolValue("ban",f.flags & ServFilter::F_BAN);
+ iniFile.writeBoolValue("network",f.flags & ServFilter::F_NETWORK);
+ iniFile.writeBoolValue("direct",f.flags & ServFilter::F_DIRECT);
+}
+
+// --------------------------------------------------
+static void writeServHost(IniFile &iniFile, ServHost &sh)
+{
+ iniFile.writeSection("Host");
+
+ char ipStr[64];
+ sh.host.toStr(ipStr);
+ iniFile.writeStrValue("type",ServHost::getTypeStr(sh.type));
+ iniFile.writeStrValue("address",ipStr);
+ iniFile.writeIntValue("time",sh.time);
+
+ iniFile.writeLine("[End]");
+}
+
+#ifdef WIN32
+extern bool guiFlg;
+extern WINDOWPLACEMENT winPlace;
+extern HWND guiWnd;
+#endif
+
+// --------------------------------------------------
+void ServMgr::saveSettings(const char *fn)
+{
+ IniFile iniFile;
+ if (!iniFile.openWriteReplace(fn))
+ {
+ LOG_ERROR("Unable to open ini file");
+ }else{
+ LOG_DEBUG("Saving settings to: %s",fn);
+
+ char idStr[64];
+
+ iniFile.writeSection("Server");
+ iniFile.writeIntValue("serverPort",servMgr->serverHost.port);
+ iniFile.writeBoolValue("autoServe",servMgr->autoServe);
+ iniFile.writeStrValue("forceIP",servMgr->forceIP);
+ iniFile.writeBoolValue("isRoot",servMgr->isRoot);
+ iniFile.writeIntValue("maxBitrateOut",servMgr->maxBitrateOut);
+ iniFile.writeIntValue("maxRelays",servMgr->maxRelays);
+ iniFile.writeIntValue("maxDirect",servMgr->maxDirect);
+ iniFile.writeIntValue("maxRelaysPerChannel",chanMgr->maxRelaysPerChannel);
+ iniFile.writeIntValue("firewallTimeout",firewallTimeout);
+ iniFile.writeBoolValue("forceNormal",forceNormal);
+ iniFile.writeStrValue("rootMsg",rootMsg.cstr());
+ iniFile.writeStrValue("authType",servMgr->authType==ServMgr::AUTH_COOKIE?"cookie":"http-basic");
+ iniFile.writeStrValue("cookiesExpire",servMgr->cookieList.neverExpire==true?"never":"session");
+ iniFile.writeStrValue("htmlPath",servMgr->htmlPath);
+ iniFile.writeIntValue("minPGNUIncoming",servMgr->minGnuIncoming);
+ iniFile.writeIntValue("maxPGNUIncoming",servMgr->maxGnuIncoming);
+ iniFile.writeIntValue("maxServIn",servMgr->maxServIn);
+ iniFile.writeStrValue("chanLog",servMgr->chanLog.cstr());
+
+ networkID.toStr(idStr);
+ iniFile.writeStrValue("networkID",idStr);
+
+
+ iniFile.writeSection("Broadcast");
+ iniFile.writeIntValue("broadcastMsgInterval",chanMgr->broadcastMsgInterval);
+ iniFile.writeStrValue("broadcastMsg",chanMgr->broadcastMsg.cstr());
+ iniFile.writeIntValue("icyMetaInterval",chanMgr->icyMetaInterval);
+ chanMgr->broadcastID.toStr(idStr);
+ iniFile.writeStrValue("broadcastID",idStr);
+ iniFile.writeIntValue("hostUpdateInterval",chanMgr->hostUpdateInterval);
+ iniFile.writeIntValue("maxControlConnections",servMgr->maxControl);
+ iniFile.writeStrValue("rootHost",servMgr->rootHost.cstr());
+
+ iniFile.writeSection("Client");
+ iniFile.writeIntValue("refreshHTML",refreshHTML);
+ iniFile.writeIntValue("relayBroadcast",servMgr->relayBroadcast);
+ iniFile.writeIntValue("minBroadcastTTL",chanMgr->minBroadcastTTL);
+ iniFile.writeIntValue("maxBroadcastTTL",chanMgr->maxBroadcastTTL);
+ iniFile.writeIntValue("pushTries",chanMgr->pushTries);
+ iniFile.writeIntValue("pushTimeout",chanMgr->pushTimeout);
+ iniFile.writeIntValue("maxPushHops",chanMgr->maxPushHops);
+ iniFile.writeIntValue("autoQuery",chanMgr->autoQuery);
+ iniFile.writeIntValue("queryTTL",servMgr->queryTTL);
+
+
+ iniFile.writeSection("Privacy");
+ iniFile.writeStrValue("password",servMgr->password);
+ iniFile.writeIntValue("maxUptime",chanMgr->maxUptime);
+
+ //JP-EX
+ iniFile.writeSection("Extend");
+ iniFile.writeIntValue("autoRelayKeep",servMgr->autoRelayKeep);
+ iniFile.writeIntValue("autoMaxRelaySetting",servMgr->autoMaxRelaySetting);
+ iniFile.writeIntValue("autoBumpSkipCount",servMgr->autoBumpSkipCount);
+ iniFile.writeIntValue("kickPushStartRelays",servMgr->kickPushStartRelays);
+ iniFile.writeIntValue("kickPushInterval",servMgr->kickPushInterval);
+ iniFile.writeIntValue("allowConnectPCST",servMgr->allowConnectPCST);
+ iniFile.writeIntValue("enableGetName",servMgr->enableGetName);
+
+ iniFile.writeIntValue("maxRelaysIndexTxt", servMgr->maxRelaysIndexTxt); // for PCRaw (relay)
+
+ //JP-EX
+ iniFile.writeSection("Windows");
+ iniFile.writeBoolValue("getModulePath",servMgr->getModulePath);
+ iniFile.writeBoolValue("clearPLS",servMgr->clearPLS);
+ iniFile.writeBoolValue("writeLogFile",servMgr->writeLogFile);
+
+ //VP-EX
+ iniFile.writeStrValue("rootHost2",servMgr->rootHost2.cstr());
+ iniFile.writeBoolValue("autoPort0Kick",servMgr->autoPort0Kick);
+ iniFile.writeBoolValue("allowOnlyVP",servMgr->allowOnlyVP);
+ iniFile.writeIntValue("kickKeepTime",servMgr->kickKeepTime);
+ iniFile.writeBoolValue("vpDebug", servMgr->vpDebug);
+ iniFile.writeBoolValue("saveIniChannel", servMgr->saveIniChannel);
+#ifdef WIN32
+ iniFile.writeBoolValue("saveGuiPos", servMgr->saveGuiPos);
+ if (guiFlg){
+ GetWindowPlacement(guiWnd, &winPlace);
+ iniFile.writeIntValue("guiTop", winPlace.rcNormalPosition.top);
+ iniFile.writeIntValue("guiBottom", winPlace.rcNormalPosition.bottom);
+ iniFile.writeIntValue("guiLeft", winPlace.rcNormalPosition.left);
+ iniFile.writeIntValue("guiRight", winPlace.rcNormalPosition.right);
+ }
+#endif
+ int i;
+
+ for(i=0; i<servMgr->numFilters; i++)
+ {
+ iniFile.writeSection("Filter");
+ writeFilterSettings(iniFile,servMgr->filters[i]);
+ iniFile.writeLine("[End]");
+ }
+
+ iniFile.writeSection("Notify");
+ iniFile.writeBoolValue("PeerCast",notifyMask&NT_PEERCAST);
+ iniFile.writeBoolValue("Broadcasters",notifyMask&NT_BROADCASTERS);
+ iniFile.writeBoolValue("TrackInfo",notifyMask&NT_TRACKINFO);
+ iniFile.writeLine("[End]");
+
+
+ iniFile.writeSection("Server1");
+ writeServerSettings(iniFile,allowServer1);
+ iniFile.writeLine("[End]");
+
+ iniFile.writeSection("Server2");
+ writeServerSettings(iniFile,allowServer2);
+ iniFile.writeLine("[End]");
+
+
+
+ iniFile.writeSection("Debug");
+ iniFile.writeBoolValue("logDebug",(showLog&(1<<LogBuffer::T_DEBUG))!=0);
+ iniFile.writeBoolValue("logErrors",(showLog&(1<<LogBuffer::T_ERROR))!=0);
+ iniFile.writeBoolValue("logNetwork",(showLog&(1<<LogBuffer::T_NETWORK))!=0);
+ iniFile.writeBoolValue("logChannel",(showLog&(1<<LogBuffer::T_CHANNEL))!=0);
+ iniFile.writeBoolValue("pauseLog",pauseLog);
+ iniFile.writeIntValue("idleSleepTime",sys->idleSleepTime);
+
+
+ if (servMgr->validBCID)
+ {
+ BCID *bcid = servMgr->validBCID;
+ while (bcid)
+ {
+ iniFile.writeSection("ValidBCID");
+ char idstr[128];
+ bcid->id.toStr(idstr);
+ iniFile.writeStrValue("id",idstr);
+ iniFile.writeStrValue("name",bcid->name.cstr());
+ iniFile.writeStrValue("email",bcid->email.cstr());
+ iniFile.writeStrValue("url",bcid->url.cstr());
+ iniFile.writeBoolValue("valid",bcid->valid);
+ iniFile.writeLine("[End]");
+
+ bcid=bcid->next;
+ }
+ }
+
+ if (servMgr->saveIniChannel){
+ Channel *c = chanMgr->channel;
+ while (c)
+ {
+ char idstr[64];
+ if (c->isActive() && c->stayConnected)
+ {
+ c->getIDStr(idstr);
+
+ iniFile.writeSection("RelayChannel");
+ iniFile.writeStrValue("name",c->getName());
+ iniFile.writeStrValue("genre",c->info.genre.cstr());
+ if (!c->sourceURL.isEmpty())
+ iniFile.writeStrValue("sourceURL",c->sourceURL.cstr());
+ iniFile.writeStrValue("sourceProtocol",ChanInfo::getProtocolStr(c->info.srcProtocol));
+ iniFile.writeStrValue("contentType",ChanInfo::getTypeStr(c->info.contentType));
+ iniFile.writeIntValue("bitrate",c->info.bitrate);
+ iniFile.writeStrValue("contactURL",c->info.url.cstr());
+ iniFile.writeStrValue("id",idstr);
+ iniFile.writeBoolValue("stayConnected",c->stayConnected);
+
+ ChanHitList *chl = chanMgr->findHitListByID(c->info.id);
+ if (chl)
+ {
+
+ ChanHitSearch chs;
+ chs.trackersOnly = true;
+ if (chl->pickHits(chs))
+ {
+ char ipStr[64];
+ chs.best[0].host.toStr(ipStr);
+ iniFile.writeStrValue("tracker",ipStr);
+ }
+ }
+ iniFile.writeLine("[End]");
+ }
+ c=c->next;
+ }
+ }
+
+
+
+#if 0
+ Servent *s = servents;
+ while (s)
+ {
+ if (s->type == Servent::T_OUTGOING)
+ if (s->isConnected())
+ {
+ ServHost sh;
+ Host h = s->getHost();
+ sh.init(h,ServHost::T_SERVENT,0,s->networkID);
+ writeServHost(iniFile,sh);
+ }
+ s=s->next;
+ }
+#endif
+
+ for(i=0; i<ServMgr::MAX_HOSTCACHE; i++)
+ {
+ ServHost *sh = &servMgr->hostCache[i];
+ if (sh->type != ServHost::T_NONE)
+ writeServHost(iniFile,*sh);
+ }
+
+ iniFile.close();
+ }
+}
+// --------------------------------------------------
+unsigned int readServerSettings(IniFile &iniFile, unsigned int a)
+{
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("allowHTML"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_HTML:a&~Servent::ALLOW_HTML;
+ else if (iniFile.isName("allowDirect"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_DIRECT:a&~Servent::ALLOW_DIRECT;
+ else if (iniFile.isName("allowNetwork"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_NETWORK:a&~Servent::ALLOW_NETWORK;
+ else if (iniFile.isName("allowBroadcast"))
+ a = iniFile.getBoolValue()?a|Servent::ALLOW_BROADCAST:a&~Servent::ALLOW_BROADCAST;
+ }
+ return a;
+}
+// --------------------------------------------------
+void readFilterSettings(IniFile &iniFile, ServFilter &sv)
+{
+ sv.host.init();
+
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("ip"))
+ sv.host.fromStrIP(iniFile.getStrValue(),0);
+ else if (iniFile.isName("private"))
+ sv.flags = (sv.flags & ~ServFilter::F_PRIVATE) | (iniFile.getBoolValue()?ServFilter::F_PRIVATE:0);
+ else if (iniFile.isName("ban"))
+ sv.flags = (sv.flags & ~ServFilter::F_BAN) | (iniFile.getBoolValue()?ServFilter::F_BAN:0);
+ else if (iniFile.isName("allow") || iniFile.isName("network"))
+ sv.flags = (sv.flags & ~ServFilter::F_NETWORK) | (iniFile.getBoolValue()?ServFilter::F_NETWORK:0);
+ else if (iniFile.isName("direct"))
+ sv.flags = (sv.flags & ~ServFilter::F_DIRECT) | (iniFile.getBoolValue()?ServFilter::F_DIRECT:0);
+ }
+
+}
+// --------------------------------------------------
+void ServMgr::loadSettings(const char *fn)
+{
+ IniFile iniFile;
+
+ if (!iniFile.openReadOnly(fn))
+ saveSettings(fn);
+
+
+ servMgr->numFilters = 0;
+ showLog = 0;
+
+ if (iniFile.openReadOnly(fn))
+ {
+ while (iniFile.readNext())
+ {
+ // server settings
+ if (iniFile.isName("serverPort"))
+ servMgr->serverHost.port = iniFile.getIntValue();
+ else if (iniFile.isName("autoServe"))
+ servMgr->autoServe = iniFile.getBoolValue();
+ else if (iniFile.isName("autoConnect"))
+ servMgr->autoConnect = iniFile.getBoolValue();
+ else if (iniFile.isName("icyPassword")) // depreciated
+ strcpy(servMgr->password,iniFile.getStrValue());
+ else if (iniFile.isName("forceIP"))
+ servMgr->forceIP = iniFile.getStrValue();
+ else if (iniFile.isName("isRoot"))
+ servMgr->isRoot = iniFile.getBoolValue();
+ else if (iniFile.isName("broadcastID"))
+ {
+ chanMgr->broadcastID.fromStr(iniFile.getStrValue());
+ chanMgr->broadcastID.id[0] = PCP_BROADCAST_FLAGS; // hacky, but we need to fix old clients
+
+ }else if (iniFile.isName("htmlPath"))
+ strcpy(servMgr->htmlPath,iniFile.getStrValue());
+ else if (iniFile.isName("maxPGNUIncoming"))
+ servMgr->maxGnuIncoming = iniFile.getIntValue();
+ else if (iniFile.isName("minPGNUIncoming"))
+ servMgr->minGnuIncoming = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxControlConnections"))
+ {
+ servMgr->maxControl = iniFile.getIntValue();
+
+ }
+ else if (iniFile.isName("maxBitrateOut"))
+ servMgr->maxBitrateOut = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxStreamsOut")) // depreciated
+ servMgr->setMaxRelays(iniFile.getIntValue());
+ else if (iniFile.isName("maxRelays"))
+ servMgr->setMaxRelays(iniFile.getIntValue());
+ else if (iniFile.isName("maxDirect"))
+ servMgr->maxDirect = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxStreamsPerChannel")) // depreciated
+ chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+ else if (iniFile.isName("maxRelaysPerChannel"))
+ chanMgr->maxRelaysPerChannel = iniFile.getIntValue();
+
+ else if (iniFile.isName("firewallTimeout"))
+ firewallTimeout = iniFile.getIntValue();
+ else if (iniFile.isName("forceNormal"))
+ forceNormal = iniFile.getBoolValue();
+ else if (iniFile.isName("broadcastMsgInterval"))
+ chanMgr->broadcastMsgInterval = iniFile.getIntValue();
+ else if (iniFile.isName("broadcastMsg"))
+ chanMgr->broadcastMsg.set(iniFile.getStrValue(),String::T_ASCII);
+ else if (iniFile.isName("hostUpdateInterval"))
+ chanMgr->hostUpdateInterval = iniFile.getIntValue();
+ else if (iniFile.isName("icyMetaInterval"))
+ chanMgr->icyMetaInterval = iniFile.getIntValue();
+ else if (iniFile.isName("maxServIn"))
+ servMgr->maxServIn = iniFile.getIntValue();
+ else if (iniFile.isName("chanLog"))
+ servMgr->chanLog.set(iniFile.getStrValue(),String::T_ASCII);
+
+ else if (iniFile.isName("rootMsg"))
+ rootMsg.set(iniFile.getStrValue());
+ else if (iniFile.isName("networkID"))
+ networkID.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("authType"))
+ {
+ char *t = iniFile.getStrValue();
+ if (stricmp(t,"cookie")==0)
+ servMgr->authType = ServMgr::AUTH_COOKIE;
+ else if (stricmp(t,"http-basic")==0)
+ servMgr->authType = ServMgr::AUTH_HTTPBASIC;
+ }else if (iniFile.isName("cookiesExpire"))
+ {
+ char *t = iniFile.getStrValue();
+ if (stricmp(t,"never")==0)
+ servMgr->cookieList.neverExpire = true;
+ else if (stricmp(t,"session")==0)
+ servMgr->cookieList.neverExpire = false;
+
+
+ }
+
+ // privacy settings
+ else if (iniFile.isName("password"))
+ strcpy(servMgr->password,iniFile.getStrValue());
+ else if (iniFile.isName("maxUptime"))
+ chanMgr->maxUptime = iniFile.getIntValue();
+
+ // client settings
+
+ else if (iniFile.isName("rootHost"))
+ {
+ if (!PCP_FORCE_YP)
+ servMgr->rootHost = iniFile.getStrValue();
+
+ }else if (iniFile.isName("deadHitAge"))
+ chanMgr->deadHitAge = iniFile.getIntValue();
+ else if (iniFile.isName("tryoutDelay"))
+ servMgr->tryoutDelay = iniFile.getIntValue();
+ else if (iniFile.isName("refreshHTML"))
+ refreshHTML = iniFile.getIntValue();
+ else if (iniFile.isName("relayBroadcast"))
+ {
+ servMgr->relayBroadcast = iniFile.getIntValue();
+ if (servMgr->relayBroadcast < 30)
+ servMgr->relayBroadcast = 30;
+ }
+ else if (iniFile.isName("minBroadcastTTL"))
+ chanMgr->minBroadcastTTL = iniFile.getIntValue();
+ else if (iniFile.isName("maxBroadcastTTL"))
+ chanMgr->maxBroadcastTTL = iniFile.getIntValue();
+ else if (iniFile.isName("pushTimeout"))
+ chanMgr->pushTimeout = iniFile.getIntValue();
+ else if (iniFile.isName("pushTries"))
+ chanMgr->pushTries = iniFile.getIntValue();
+ else if (iniFile.isName("maxPushHops"))
+ chanMgr->maxPushHops = iniFile.getIntValue();
+ else if (iniFile.isName("autoQuery"))
+ {
+ chanMgr->autoQuery = iniFile.getIntValue();
+ if ((chanMgr->autoQuery < 300) && (chanMgr->autoQuery > 0))
+ chanMgr->autoQuery = 300;
+ }
+ else if (iniFile.isName("queryTTL"))
+ {
+ servMgr->queryTTL = iniFile.getIntValue();
+ }
+
+ //JP-Extend
+ else if (iniFile.isName("autoRelayKeep"))
+ servMgr->autoRelayKeep = iniFile.getIntValue();
+ else if (iniFile.isName("autoMaxRelaySetting"))
+ servMgr->autoMaxRelaySetting = iniFile.getIntValue();
+ else if (iniFile.isName("autoBumpSkipCount"))
+ servMgr->autoBumpSkipCount = iniFile.getIntValue();
+ else if (iniFile.isName("kickPushStartRelays"))
+ servMgr->kickPushStartRelays = iniFile.getIntValue();
+ else if (iniFile.isName("kickPushInterval"))
+ {
+ servMgr->kickPushInterval = iniFile.getIntValue();
+ if (servMgr->kickPushInterval < 60)
+ servMgr->kickPushInterval = 0;
+ }
+ else if (iniFile.isName("allowConnectPCST"))
+ servMgr->allowConnectPCST = iniFile.getIntValue();
+ else if (iniFile.isName("enableGetName"))
+ servMgr->enableGetName = iniFile.getIntValue();
+
+ else if (iniFile.isName("maxRelaysIndexTxt")) // for PCRaw (relay)
+ servMgr->maxRelaysIndexTxt = iniFile.getIntValue();
+
+ //JP-Windows
+ else if (iniFile.isName("getModulePath"))
+ servMgr->getModulePath = iniFile.getBoolValue();
+ else if (iniFile.isName("clearPLS"))
+ servMgr->clearPLS = iniFile.getBoolValue();
+ else if (iniFile.isName("writeLogFile"))
+ servMgr->writeLogFile = iniFile.getBoolValue();
+
+ //VP-EX
+ else if (iniFile.isName("rootHost2"))
+ {
+ if (!PCP_FORCE_YP)
+ servMgr->rootHost2 = iniFile.getStrValue();
+ }
+ else if (iniFile.isName("autoPort0Kick"))
+ servMgr->autoPort0Kick = iniFile.getBoolValue();
+ else if (iniFile.isName("allowOnlyVP"))
+ servMgr->allowOnlyVP = iniFile.getBoolValue();
+ else if (iniFile.isName("kickKeepTime"))
+ servMgr->kickKeepTime = iniFile.getIntValue();
+ else if (iniFile.isName("vpDebug"))
+ servMgr->vpDebug = iniFile.getBoolValue();
+ else if (iniFile.isName("saveIniChannel"))
+ servMgr->saveIniChannel = iniFile.getBoolValue();
+#ifdef WIN32
+ else if (iniFile.isName("saveGuiPos"))
+ servMgr->saveGuiPos = iniFile.getBoolValue();
+ else if (iniFile.isName("guiTop"))
+ winPlace.rcNormalPosition.top = iniFile.getIntValue();
+ else if (iniFile.isName("guiBottom"))
+ winPlace.rcNormalPosition.bottom = iniFile.getIntValue();
+ else if (iniFile.isName("guiLeft"))
+ winPlace.rcNormalPosition.left = iniFile.getIntValue();
+ else if (iniFile.isName("guiRight")){
+ winPlace.rcNormalPosition.right = iniFile.getIntValue();
+ winPlace.length = sizeof(winPlace);
+ winPlace.flags = 0;
+ winPlace.showCmd = 1;
+ winPlace.ptMinPosition.x = -1;
+ winPlace.ptMinPosition.y = -1;
+ winPlace.ptMaxPosition.x = -1;
+ winPlace.ptMaxPosition.y = -1;
+ if (servMgr->saveGuiPos){
+ guiFlg = true;
+ }
+ }
+#endif
+
+ // debug
+ else if (iniFile.isName("logDebug"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_DEBUG:0;
+ else if (iniFile.isName("logErrors"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_ERROR:0;
+ else if (iniFile.isName("logNetwork"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_NETWORK:0;
+ else if (iniFile.isName("logChannel"))
+ showLog |= iniFile.getBoolValue() ? 1<<LogBuffer::T_CHANNEL:0;
+ else if (iniFile.isName("pauseLog"))
+ pauseLog = iniFile.getBoolValue();
+ else if (iniFile.isName("idleSleepTime"))
+ sys->idleSleepTime = iniFile.getIntValue();
+ else if (iniFile.isName("[Server1]"))
+ allowServer1 = readServerSettings(iniFile,allowServer1);
+ else if (iniFile.isName("[Server2]"))
+ allowServer2 = readServerSettings(iniFile,allowServer2);
+ else if (iniFile.isName("[Filter]"))
+ {
+ readFilterSettings(iniFile,filters[numFilters]);
+
+ if (numFilters < (MAX_FILTERS-1))
+ numFilters++;
+ }
+ else if (iniFile.isName("[Notify]"))
+ {
+ notifyMask = NT_UPGRADE;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("PeerCast"))
+ notifyMask |= iniFile.getBoolValue()?NT_PEERCAST:0;
+ else if (iniFile.isName("Broadcasters"))
+ notifyMask |= iniFile.getBoolValue()?NT_BROADCASTERS:0;
+ else if (iniFile.isName("TrackInfo"))
+ notifyMask |= iniFile.getBoolValue()?NT_TRACKINFO:0;
+ }
+
+ }
+ else if (iniFile.isName("[RelayChannel]"))
+ {
+ ChanInfo info;
+ bool stayConnected=false;
+ String sourceURL;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("name"))
+ info.name.set(iniFile.getStrValue());
+ else if (iniFile.isName("id"))
+ info.id.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("sourceType"))
+ info.srcProtocol = ChanInfo::getProtocolFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("contentType"))
+ info.contentType = ChanInfo::getTypeFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("stayConnected"))
+ stayConnected = iniFile.getBoolValue();
+ else if (iniFile.isName("sourceURL"))
+ sourceURL.set(iniFile.getStrValue());
+ else if (iniFile.isName("genre"))
+ info.genre.set(iniFile.getStrValue());
+ else if (iniFile.isName("contactURL"))
+ info.url.set(iniFile.getStrValue());
+ else if (iniFile.isName("bitrate"))
+ info.bitrate = atoi(iniFile.getStrValue());
+ else if (iniFile.isName("tracker"))
+ {
+ ChanHit hit;
+ hit.init();
+ hit.tracker = true;
+ hit.host.fromStrName(iniFile.getStrValue(),DEFAULT_PORT);
+ hit.rhost[0] = hit.host;
+ hit.rhost[1] = hit.host;
+ hit.chanID = info.id;
+ hit.recv = true;
+ chanMgr->addHit(hit);
+ }
+
+ }
+ if (sourceURL.isEmpty())
+ {
+ chanMgr->createRelay(info,stayConnected);
+ }else
+ {
+ info.bcID = chanMgr->broadcastID;
+ Channel *c = chanMgr->createChannel(info,NULL);
+ if (c)
+ c->startURL(sourceURL.cstr());
+ }
+ } else if (iniFile.isName("[Host]"))
+ {
+ Host h;
+ ServHost::TYPE type=ServHost::T_NONE;
+ bool firewalled=false;
+ unsigned int time=0;
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("address"))
+ h.fromStrIP(iniFile.getStrValue(),DEFAULT_PORT);
+ else if (iniFile.isName("type"))
+ type = ServHost::getTypeFromStr(iniFile.getStrValue());
+ else if (iniFile.isName("time"))
+ time = iniFile.getIntValue();
+ }
+ servMgr->addHost(h,type,time);
+
+ } else if (iniFile.isName("[ValidBCID]"))
+ {
+ BCID *bcid = new BCID();
+ while (iniFile.readNext())
+ {
+ if (iniFile.isName("[End]"))
+ break;
+ else if (iniFile.isName("id"))
+ bcid->id.fromStr(iniFile.getStrValue());
+ else if (iniFile.isName("name"))
+ bcid->name.set(iniFile.getStrValue());
+ else if (iniFile.isName("email"))
+ bcid->email.set(iniFile.getStrValue());
+ else if (iniFile.isName("url"))
+ bcid->url.set(iniFile.getStrValue());
+ else if (iniFile.isName("valid"))
+ bcid->valid = iniFile.getBoolValue();
+ }
+ servMgr->addValidBCID(bcid);
+ }
+ }
+ }
+
+ if (!numFilters)
+ setFilterDefaults();
+
+}
+
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(GnuID &cid, Servent::TYPE tp, bool all)
+{
+ int cnt = 0;
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == tp)
+ if (sv->chanID.isSame(cid))
+ if (all || !sv->isPrivate())
+ cnt++;
+ sv=sv->next;
+ }
+ return cnt;
+}
+// --------------------------------------------------
+unsigned int ServMgr::numStreams(Servent::TYPE tp, bool all)
+{
+ int cnt = 0;
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == tp)
+ if (all || !sv->isPrivate())
+ {
+ // for PCRaw (relay) start.
+ if(tp == Servent::T_RELAY)
+ {
+ Channel *ch = chanMgr->findChannelByID(sv->chanID);
+
+ // index.txt\82Í\83J\83E\83\93\83g\82µ\82È\82¢
+ if(!isIndexTxt(ch))
+ cnt++;
+ }
+ else
+ // for PCRaw (relay) end.
+ {
+ cnt++;
+ }
+ }
+ sv=sv->next;
+ }
+ return cnt;
+}
+
+// --------------------------------------------------
+bool ServMgr::getChannel(char *str,ChanInfo &info, bool relay)
+{
+ // remove file extension (only added for winamp)
+ //char *ext = strstr(str,".");
+ //if (ext) *ext = 0;
+
+ procConnectArgs(str,info);
+
+ WLockBlock wb(&(chanMgr->channellock));
+
+ wb.on();
+ Channel *ch;
+
+ ch = chanMgr->findChannelByNameID(info);
+ if (ch && ch->thread.active)
+ {
+
+ if (!ch->isPlaying())
+ {
+ if (relay)
+ {
+ ch->info.lastPlayStart = 0; // force reconnect
+ ch->info.lastPlayEnd = 0;
+ }else
+ return false;
+ }
+
+ info = ch->info; // get updated channel info
+
+ return true;
+ }else
+ {
+ if (relay)
+ {
+ wb.off();
+ ch = chanMgr->findAndRelay(info);
+ if (ch)
+ {
+ // \81«Exception point
+ info = ch->info; //get updated channel info
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+// --------------------------------------------------
+int ServMgr::findChannel(ChanInfo &info)
+{
+#if 0
+ char idStr[64];
+ info.id.toStr(idStr);
+
+
+ if (info.id.isSet())
+ {
+ // if we have an ID then try and connect to known hosts carrying channel.
+ ServHost sh = getOutgoingServent(info.id);
+ addOutgoing(sh.host,info.id,true);
+ }
+
+ GnuPacket pack;
+
+ XML xml;
+ XML::Node *n = info.createQueryXML();
+ xml.setRoot(n);
+ pack.initFind(NULL,&xml,servMgr->queryTTL);
+
+ addReplyID(pack.id);
+ int cnt = broadcast(pack,NULL);
+
+ LOG_NETWORK("Querying network: %s %s - %d servents",info.name.cstr(),idStr,cnt);
+
+ return cnt;
+#endif
+ return 0;
+}
+// --------------------------------------------------
+// add outgoing network connection from string (ip:port format)
+bool ServMgr::addOutgoing(Host h, GnuID &netid, bool pri)
+{
+#if 0
+ if (h.ip)
+ {
+ if (!findServent(h.ip,h.port,netid))
+ {
+ Servent *sv = allocServent();
+ if (sv)
+ {
+ if (pri)
+ sv->priorityConnect = true;
+ sv->networkID = netid;
+ sv->initOutgoing(h,Servent::T_OUTGOING);
+ return true;
+ }
+ }
+ }
+#endif
+ return false;
+}
+// --------------------------------------------------
+Servent *ServMgr::findConnection(Servent::TYPE t,GnuID &sid)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->isConnected())
+ if (sv->type == t)
+ if (sv->remoteID.isSame(sid))
+ return sv;
+ sv=sv->next;
+ }
+ return NULL;
+}
+
+// --------------------------------------------------
+void ServMgr::procConnectArgs(char *str,ChanInfo &info)
+{
+ char arg[MAX_CGI_LEN];
+ char curr[MAX_CGI_LEN];
+
+ char *args = strstr(str,"?");
+ if (args)
+ *args++=0;
+
+ info.initNameID(str);
+
+ if (args)
+ {
+
+ while (args=nextCGIarg(args,curr,arg))
+ {
+ LOG_DEBUG("cmd: %s, arg: %s",curr,arg);
+
+ if (strcmp(curr,"sip")==0)
+ // sip - add network connection to client with channel
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ if (addOutgoing(h,servMgr->networkID,true))
+ LOG_NETWORK("Added connection: %s",arg);
+
+ }else if (strcmp(curr,"pip")==0)
+ // pip - add private network connection to client with channel
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ if (addOutgoing(h,info.id,true))
+ LOG_NETWORK("Added private connection: %s",arg);
+ }else if (strcmp(curr,"ip")==0)
+ // ip - add hit
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ ChanHit hit;
+ hit.init();
+ hit.host = h;
+ hit.rhost[0] = h;
+ hit.rhost[1].init();
+ hit.chanID = info.id;
+ hit.recv = true;
+
+ chanMgr->addHit(hit);
+ }else if (strcmp(curr,"tip")==0)
+ // tip - add tracker hit
+ {
+ Host h;
+ h.fromStrName(arg,DEFAULT_PORT);
+ chanMgr->hitlistlock.on();
+ chanMgr->addHit(h,info.id,true);
+ chanMgr->hitlistlock.off();
+
+ }
+
+
+ }
+ }
+}
+
+// --------------------------------------------------
+bool ServMgr::start()
+{
+ char idStr[64];
+
+
+ const char *priv;
+#if PRIVATE_BROADCASTER
+ priv = "(private)";
+#else
+ priv = "";
+#endif
+#ifdef VERSION_EX
+ LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING_EX,peercastApp->getClientTypeOS(),priv);
+#else
+ LOG_DEBUG("Peercast %s, %s %s",PCX_VERSTRING,peercastApp->getClientTypeOS(),priv);
+#endif
+
+ sessionID.toStr(idStr);
+ LOG_DEBUG("SessionID: %s",idStr);
+
+ chanMgr->broadcastID.toStr(idStr);
+ LOG_DEBUG("BroadcastID: %s",idStr);
+ checkForceIP();
+
+
+ serverThread.func = ServMgr::serverProc;
+ if (!sys->startThread(&serverThread))
+ return false;
+
+ idleThread.func = ServMgr::idleProc;
+ if (!sys->startThread(&idleThread))
+ return false;
+
+ return true;
+}
+// --------------------------------------------------
+int ServMgr::clientProc(ThreadInfo *thread)
+{
+#if 0
+ thread->lock();
+
+ GnuID netID;
+ netID = servMgr->networkID;
+
+ while(thread->active)
+ {
+ if (servMgr->autoConnect)
+ {
+ if (servMgr->needConnections() || servMgr->forceLookup)
+ {
+ if (servMgr->needHosts() || servMgr->forceLookup)
+ {
+ // do lookup to find some hosts
+
+ Host lh;
+ lh.fromStrName(servMgr->connectHost,DEFAULT_PORT);
+
+
+ if (!servMgr->findServent(lh.ip,lh.port,netID))
+ {
+ Servent *sv = servMgr->allocServent();
+ if (sv)
+ {
+ LOG_DEBUG("Lookup: %s",servMgr->connectHost);
+ sv->networkID = netID;
+ sv->initOutgoing(lh,Servent::T_LOOKUP);
+ servMgr->forceLookup = false;
+ }
+ }
+ }
+
+ for(int i=0; i<MAX_TRYOUT; i++)
+ {
+ if (servMgr->outUsedFull())
+ break;
+ if (servMgr->tryFull())
+ break;
+
+
+ ServHost sh = servMgr->getOutgoingServent(netID);
+
+ if (!servMgr->addOutgoing(sh.host,netID,false))
+ servMgr->deadHost(sh.host,ServHost::T_SERVENT);
+ sys->sleep(servMgr->tryoutDelay);
+ break;
+ }
+ }
+ }else{
+#if 0
+ Servent *s = servMgr->servents;
+ while (s)
+ {
+
+ if (s->type == Servent::T_OUTGOING)
+ s->thread.active = false;
+ s=s->next;
+ }
+#endif
+ }
+ sys->sleepIdle();
+ }
+ thread->unlock();
+#endif
+ return 0;
+}
+// -----------------------------------
+bool ServMgr::acceptGIV(ClientSocket *sock)
+{
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->type == Servent::T_COUT)
+ {
+ if (sv->acceptGIV(sock))
+ return true;
+ }
+ sv=sv->next;
+ }
+ return false;
+}
+
+// -----------------------------------
+int ServMgr::broadcastPushRequest(ChanHit &hit, Host &to, GnuID &chanID, Servent::TYPE type)
+{
+ ChanPacket pack;
+ MemoryStream pmem(pack.data,sizeof(pack.data));
+ AtomStream atom(pmem);
+
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,8);
+#else
+ atom.writeParent(PCP_BCST,10);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_ALL);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeBytes(PCP_BCST_DEST,hit.sessionID.id,16);
+ atom.writeBytes(PCP_BCST_FROM,servMgr->sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ atom.writeParent(PCP_PUSH,3);
+ atom.writeInt(PCP_PUSH_IP,to.ip);
+ atom.writeShort(PCP_PUSH_PORT,to.port);
+ atom.writeBytes(PCP_PUSH_CHANID,chanID.id,16);
+
+
+ pack.len = pmem.pos;
+ pack.type = ChanPacket::T_PCP;
+
+
+ GnuID noID;
+ noID.clear();
+
+ return servMgr->broadcastPacket(pack,noID,servMgr->sessionID,hit.sessionID,type);
+}
+
+// --------------------------------------------------
+void ServMgr::writeRootAtoms(AtomStream &atom, bool getUpdate)
+{
+ atom.writeParent(PCP_ROOT,5 + (getUpdate?1:0));
+ atom.writeInt(PCP_ROOT_UPDINT,chanMgr->hostUpdateInterval);
+ atom.writeString(PCP_ROOT_URL,"download.php");
+ atom.writeInt(PCP_ROOT_CHECKVER,PCP_ROOT_VERSION);
+ atom.writeInt(PCP_ROOT_NEXT,chanMgr->hostUpdateInterval);
+ atom.writeString(PCP_MESG_ASCII,rootMsg.cstr());
+ if (getUpdate)
+ atom.writeParent(PCP_ROOT_UPDATE,0);
+
+}
+// --------------------------------------------------
+void ServMgr::broadcastRootSettings(bool getUpdate)
+{
+ if (isRoot)
+ {
+
+ ChanPacket pack;
+ MemoryStream mem(pack.data,sizeof(pack.data));
+ AtomStream atom(mem);
+#ifndef VERSION_EX
+ atom.writeParent(PCP_BCST,7);
+#else
+ atom.writeParent(PCP_BCST,9);
+#endif
+ atom.writeChar(PCP_BCST_GROUP,PCP_BCST_GROUP_TRACKERS);
+ atom.writeChar(PCP_BCST_HOPS,0);
+ atom.writeChar(PCP_BCST_TTL,7);
+ atom.writeBytes(PCP_BCST_FROM,sessionID.id,16);
+ atom.writeInt(PCP_BCST_VERSION,PCP_CLIENT_VERSION);
+ atom.writeInt(PCP_BCST_VERSION_VP,PCP_CLIENT_VERSION_VP);
+#ifdef VERSION_EX
+ atom.writeBytes(PCP_BCST_VERSION_EX_PREFIX,PCP_CLIENT_VERSION_EX_PREFIX,2);
+ atom.writeShort(PCP_BCST_VERSION_EX_NUMBER,PCP_CLIENT_VERSION_EX_NUMBER);
+#endif
+ writeRootAtoms(atom,getUpdate);
+
+ mem.len = mem.pos;
+ mem.rewind();
+ pack.len = mem.len;
+
+ GnuID noID;
+ noID.clear();
+
+ broadcastPacket(pack,noID,servMgr->sessionID,noID,Servent::T_CIN);
+ }
+}
+// --------------------------------------------------
+int ServMgr::broadcastPacket(ChanPacket &pack,GnuID &chanID,GnuID &srcID, GnuID &destID, Servent::TYPE type)
+{
+ int cnt=0;
+
+ Servent *sv = servents;
+ while (sv)
+ {
+ if (sv->sendPacket(pack,chanID,srcID,destID,type))
+ cnt++;
+ sv=sv->next;
+ }
+ return cnt;
+}
+
+// --------------------------------------------------
+int ServMgr::idleProc(ThreadInfo *thread)
+{
+
+// thread->lock();
+
+ unsigned int lastPasvFind=0;
+ unsigned int lastBroadcast=0;
+
+
+ // nothing much to do for the first couple of seconds, so just hang around.
+ sys->sleep(2000);
+
+ unsigned int lastBWcheck=0;
+ unsigned int bytesIn=0,bytesOut=0;
+
+ unsigned int lastBroadcastConnect = 0;
+ unsigned int lastRootBroadcast = 0;
+
+ unsigned int lastForceIPCheck = 0;
+
+ while(thread->active)
+ {
+ stats.update();
+
+
+
+ unsigned int ctime = sys->getTime();
+
+
+ if (!servMgr->forceIP.isEmpty())
+ {
+ if ((ctime-lastForceIPCheck) > 60)
+ {
+ if (servMgr->checkForceIP())
+ {
+ GnuID noID;
+ noID.clear();
+ chanMgr->broadcastTrackerUpdate(noID,true);
+ }
+ lastForceIPCheck = ctime;
+ }
+ }
+
+
+ if (chanMgr->isBroadcasting())
+ {
+ if ((ctime-lastBroadcastConnect) > 30)
+ {
+ servMgr->connectBroadcaster();
+ lastBroadcastConnect = ctime;
+ }
+ }
+
+ if (servMgr->isRoot)
+ {
+ if ((servMgr->lastIncoming) && ((ctime-servMgr->lastIncoming) > 60*60))
+ {
+ peercastInst->saveSettings();
+ sys->exit();
+ }
+
+ if ((ctime-lastRootBroadcast) > chanMgr->hostUpdateInterval)
+ {
+ servMgr->broadcastRootSettings(true);
+ lastRootBroadcast = ctime;
+ }
+ }
+
+
+ // clear dead hits
+ chanMgr->clearDeadHits(true);
+
+ if (servMgr->kickPushStartRelays && servMgr->kickPushInterval) //JP-EX
+ {
+ servMgr->banFirewalledHost();
+ }
+
+ if (servMgr->shutdownTimer)
+ {
+ if (--servMgr->shutdownTimer <= 0)
+ {
+ peercastInst->saveSettings();
+ sys->exit();
+ }
+ }
+
+ // shutdown idle channels
+ if (chanMgr->numIdleChannels() > ChanMgr::MAX_IDLE_CHANNELS)
+ chanMgr->closeOldestIdle();
+
+
+ sys->sleep(500);
+ }
+
+ sys->endThread(thread);
+// thread->unlock();
+ return 0;
+}
+
+// --------------------------------------------------
+int ServMgr::serverProc(ThreadInfo *thread)
+{
+
+// thread->lock();
+
+ Servent *serv = servMgr->allocServent();
+ Servent *serv2 = servMgr->allocServent();
+
+ unsigned int lastLookupTime=0;
+
+
+ while (thread->active)
+ {
+
+ if (servMgr->restartServer)
+ {
+ serv->abort(); // force close
+ serv2->abort(); // force close
+ servMgr->quit();
+
+ servMgr->restartServer = false;
+ }
+
+ if (servMgr->autoServe)
+ {
+ serv->allow = servMgr->allowServer1;
+ serv2->allow = servMgr->allowServer2;
+
+
+ if ((!serv->sock) || (!serv2->sock))
+ {
+ LOG_DEBUG("Starting servers");
+// servMgr->forceLookup = true;
+
+ //if (servMgr->serverHost.ip != 0)
+ {
+
+ if (servMgr->forceNormal)
+ servMgr->setFirewall(ServMgr::FW_OFF);
+ else
+ servMgr->setFirewall(ServMgr::FW_UNKNOWN);
+
+ Host h = servMgr->serverHost;
+
+ if (!serv->sock)
+ serv->initServer(h);
+
+ h.port++;
+ if (!serv2->sock)
+ serv2->initServer(h);
+
+
+ }
+ }
+ }else{
+ // stop server
+ serv->abort(); // force close
+ serv2->abort(); // force close
+
+ // cancel incoming connectuions
+ Servent *s = servMgr->servents;
+ while (s)
+ {
+ if (s->type == Servent::T_INCOMING)
+ s->thread.active = false;
+ s=s->next;
+ }
+
+ servMgr->setFirewall(ServMgr::FW_ON);
+ }
+
+ sys->sleepIdle();
+
+ }
+
+ sys->endThread(thread);
+// thread->unlock();
+ return 0;
+}
+
+// -----------------------------------
+void ServMgr::setMaxRelays(int max)
+{
+ if (max < MIN_RELAYS)
+ max = MIN_RELAYS;
+ maxRelays = max;
+}
+
+// -----------------------------------
+XML::Node *ServMgr::createServentXML()
+{
+
+ return new XML::Node("servent agent=\"%s\" ",PCX_AGENT);
+}
+
+// --------------------------------------------------
+const char *ServHost::getTypeStr(TYPE t)
+{
+ switch(t)
+ {
+ case T_NONE: return "NONE";
+ case T_STREAM: return "STREAM";
+ case T_CHANNEL: return "CHANNEL";
+ case T_SERVENT: return "SERVENT";
+ case T_TRACKER: return "TRACKER";
+ }
+ return "UNKNOWN";
+}
+// --------------------------------------------------
+ServHost::TYPE ServHost::getTypeFromStr(const char *s)
+{
+ if (stricmp(s,"NONE")==0)
+ return T_NONE;
+ else if (stricmp(s,"SERVENT")==0)
+ return T_SERVENT;
+ else if (stricmp(s,"STREAM")==0)
+ return T_STREAM;
+ else if (stricmp(s,"CHANNEL")==0)
+ return T_CHANNEL;
+ else if (stricmp(s,"TRACKER")==0)
+ return T_TRACKER;
+
+ return T_NONE;
+}
+
+
+// --------------------------------------------------
+bool ServFilter::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "network")
+ strcpy(buf,(flags & F_NETWORK)?"1":"0");
+ else if (var == "private")
+ strcpy(buf,(flags & F_PRIVATE)?"1":"0");
+ else if (var == "direct")
+ strcpy(buf,(flags & F_DIRECT)?"1":"0");
+ else if (var == "banned")
+ strcpy(buf,(flags & F_BAN)?"1":"0");
+ else if (var == "ip")
+ host.IPtoStr(buf);
+ else
+ return false;
+
+
+ out.writeString(buf);
+ return true;
+}
+// --------------------------------------------------
+bool BCID::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+
+ if (var == "id")
+ id.toStr(buf);
+ else if (var == "name")
+ strcpy(buf,name.cstr());
+ else if (var == "email")
+ strcpy(buf,email.cstr());
+ else if (var == "url")
+ strcpy(buf,url.cstr());
+ else if (var == "valid")
+ strcpy(buf,valid?"Yes":"No");
+ else
+ return false;
+
+
+ out.writeString(buf);
+ return true;
+}
+
+
+// --------------------------------------------------
+bool ServMgr::writeVariable(Stream &out, const String &var)
+{
+ char buf[1024];
+ String str;
+
+ if (var == "version")
+#ifdef VERSION_EX
+ strcpy(buf,PCX_VERSTRING_EX);
+#else
+ strcpy(buf,PCX_VERSTRING);
+#endif
+ else if (var == "uptime")
+ {
+ str.setFromStopwatch(getUptime());
+ str.convertTo(String::T_HTML);
+ strcpy(buf,str.cstr());
+ }else if (var == "numRelays")
+ sprintf(buf,"%d",numStreams(Servent::T_RELAY,true));
+ else if (var == "numDirect")
+ sprintf(buf,"%d",numStreams(Servent::T_DIRECT,true));
+ else if (var == "totalConnected")
+ sprintf(buf,"%d",totalConnected());
+ else if (var == "numServHosts")
+ sprintf(buf,"%d",numHosts(ServHost::T_SERVENT));
+ else if (var == "numServents")
+ sprintf(buf,"%d",numServents());
+ else if (var == "serverPort")
+ sprintf(buf,"%d",serverHost.port);
+ else if (var == "serverIP")
+ serverHost.IPtoStr(buf);
+ else if (var == "ypAddress")
+ strcpy(buf,rootHost.cstr());
+ else if (var == "password")
+ strcpy(buf,password);
+ else if (var == "isFirewalled")
+ sprintf(buf,"%d",getFirewall()==FW_ON?1:0);
+ else if (var == "firewallKnown")
+ sprintf(buf,"%d",getFirewall()==FW_UNKNOWN?0:1);
+ else if (var == "rootMsg")
+ strcpy(buf,rootMsg);
+ else if (var == "isRoot")
+ sprintf(buf,"%d",isRoot?1:0);
+ else if (var == "isPrivate")
+ sprintf(buf,"%d",(PCP_BROADCAST_FLAGS&1)?1:0);
+ else if (var == "forceYP")
+ sprintf(buf,"%d",PCP_FORCE_YP?1:0);
+ else if (var == "refreshHTML")
+ sprintf(buf,"%d",refreshHTML?refreshHTML:0x0fffffff);
+ else if (var == "maxRelays")
+ sprintf(buf,"%d",maxRelays);
+ else if (var == "maxDirect")
+ sprintf(buf,"%d",maxDirect);
+ else if (var == "maxBitrateOut")
+ sprintf(buf,"%d",maxBitrateOut);
+ else if (var == "maxControlsIn")
+ sprintf(buf,"%d",maxControl);
+ else if (var == "numFilters")
+ sprintf(buf,"%d",numFilters+1);
+ else if (var == "maxPGNUIn")
+ sprintf(buf,"%d",maxGnuIncoming);
+ else if (var == "minPGNUIn")
+ sprintf(buf,"%d",minGnuIncoming);
+ else if (var == "numActive1")
+ sprintf(buf,"%d",numActiveOnPort(serverHost.port));
+ else if (var == "numActive2")
+ sprintf(buf,"%d",numActiveOnPort(serverHost.port+1));
+ else if (var == "numPGNU")
+ sprintf(buf,"%d",numConnected(Servent::T_PGNU));
+ else if (var == "numCIN")
+ sprintf(buf,"%d",numConnected(Servent::T_CIN));
+ else if (var == "numCOUT")
+ sprintf(buf,"%d",numConnected(Servent::T_COUT));
+ else if (var == "numIncoming")
+ sprintf(buf,"%d",numActive(Servent::T_INCOMING));
+ else if (var == "numValidBCID")
+ {
+ int cnt = 0;
+ BCID *bcid = validBCID;
+ while (bcid)
+ {
+ cnt++;
+ bcid=bcid->next;
+ }
+ sprintf(buf,"%d",cnt);
+ }
+
+ else if (var == "disabled")
+ sprintf(buf,"%d",isDisabled);
+
+ // JP-EX
+ else if (var.startsWith("autoRelayKeep")) {
+ if (var == "autoRelayKeep.0")
+ strcpy(buf, (autoRelayKeep == 0) ? "1":"0");
+ else if (var == "autoRelayKeep.1")
+ strcpy(buf, (autoRelayKeep == 1) ? "1":"0");
+ else if (var == "autoRelayKeep.2")
+ strcpy(buf, (autoRelayKeep == 2) ? "1":"0");
+ } else if (var == "autoMaxRelaySetting")
+ sprintf(buf,"%d",autoMaxRelaySetting);
+ else if (var == "autoBumpSkipCount")
+ sprintf(buf,"%d",autoBumpSkipCount);
+ else if (var == "kickPushStartRelays")
+ sprintf(buf,"%d",kickPushStartRelays);
+ else if (var == "kickPushInterval")
+ sprintf(buf,"%d",kickPushInterval);
+ else if (var == "allowConnectPCST")
+ strcpy(buf, (allowConnectPCST == 1) ? "1":"0");
+ else if (var == "enableGetName")
+ strcpy(buf, (enableGetName == 1)? "1":"0");
+
+ // VP-EX
+ else if (var == "ypAddress2")
+ strcpy(buf,rootHost2.cstr());
+ else if (var.startsWith("autoPort0Kick")) {
+ if (var == "autoPort0Kick.0")
+ strcpy(buf, (autoPort0Kick == 0) ? "1":"0");
+ else if (var == "autoPort0Kick.1")
+ strcpy(buf, (autoPort0Kick == 1) ? "1":"0");
+ }
+ else if (var.startsWith("allowOnlyVP")) {
+ if (var == "allowOnlyVP.0")
+ strcpy(buf, (allowOnlyVP == 0) ? "1":"0");
+ else if (var == "allowOnlyVP.1")
+ strcpy(buf, (allowOnlyVP == 1) ? "1":"0");
+ }
+ else if (var == "kickKeepTime")
+ sprintf(buf, "%d",kickKeepTime);
+
+ else if (var == "serverPort1")
+ sprintf(buf,"%d",serverHost.port);
+ else if (var == "serverLocalIP")
+ {
+ Host lh(ClientSocket::getIP(NULL),0);
+ char ipStr[64];
+ lh.IPtoStr(ipStr);
+ strcpy(buf,ipStr);
+ }else if (var == "upgradeURL")
+ strcpy(buf,servMgr->downloadURL);
+ else if (var == "serverPort2")
+ sprintf(buf,"%d",serverHost.port+1);
+ else if (var.startsWith("allow."))
+ {
+ if (var == "allow.HTML1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_HTML)?"1":"0");
+ else if (var == "allow.HTML2")
+ strcpy(buf,(allowServer2&Servent::ALLOW_HTML)?"1":"0");
+ else if (var == "allow.broadcasting1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_BROADCAST)?"1":"0");
+ else if (var == "allow.broadcasting2")
+ strcpy(buf,(allowServer2&Servent::ALLOW_BROADCAST)?"1":"0");
+ else if (var == "allow.network1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_NETWORK)?"1":"0");
+ else if (var == "allow.direct1")
+ strcpy(buf,(allowServer1&Servent::ALLOW_DIRECT)?"1":"0");
+ }else if (var.startsWith("auth."))
+ {
+ if (var == "auth.useCookies")
+ strcpy(buf,(authType==AUTH_COOKIE)?"1":"0");
+ else if (var == "auth.useHTTP")
+ strcpy(buf,(authType==AUTH_HTTPBASIC)?"1":"0");
+ else if (var == "auth.useSessionCookies")
+ strcpy(buf,(cookieList.neverExpire==false)?"1":"0");
+
+ }else if (var.startsWith("log."))
+ {
+ if (var == "log.debug")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_DEBUG))?"1":"0");
+ else if (var == "log.errors")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_ERROR))?"1":"0");
+ else if (var == "log.gnet")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_NETWORK))?"1":"0");
+ else if (var == "log.channel")
+ strcpy(buf,(showLog&(1<<LogBuffer::T_CHANNEL))?"1":"0");
+ else
+ return false;
+ }else if (var == "test")
+ {
+ out.writeUTF8(0x304b);
+ out.writeUTF8(0x304d);
+ out.writeUTF8(0x304f);
+ out.writeUTF8(0x3051);
+ out.writeUTF8(0x3053);
+
+ out.writeUTF8(0x0041);
+ out.writeUTF8(0x0042);
+ out.writeUTF8(0x0043);
+ out.writeUTF8(0x0044);
+
+ out.writeChar('a');
+ out.writeChar('b');
+ out.writeChar('c');
+ out.writeChar('d');
+ return true;
+
+ }else if (var == "maxRelaysIndexTxt") // for PCRaw (relay)
+ sprintf(buf, "%d", maxRelaysIndexTxt);
+ else
+ return false;
+
+ out.writeString(buf);
+ return true;
+}
+// --------------------------------------------------
+//JP-EX
+bool ServMgr::isCheckPushStream()
+{
+ if (servMgr->kickPushStartRelays)
+ if (servMgr->numStreams(Servent::T_RELAY,false)>=(servMgr->kickPushStartRelays-1))
+ return true;
+
+ return false;
+}
+// --------------------------------------------------
+//JP-EX
+void ServMgr::banFirewalledHost()
+{
+ unsigned int kickpushtime = sys->getTime();
+ if ((kickpushtime-servMgr->kickPushTime) > servMgr->kickPushInterval)
+ {
+ servMgr->kickPushTime = kickpushtime;
+ Servent *s = servMgr->servents;
+ LOG_DEBUG("Servent scan start.");
+ while (s)
+ {
+ if (s->type != Servent::T_NONE)
+ {
+ Host h = s->getHost();
+ int ip = h.ip;
+ int port = h.port;
+ Host h2(ip,port);
+ unsigned int tnum = 0;
+
+ if (s->lastConnect)
+ tnum = sys->getTime() - s->lastConnect;
+ if ((s->type==Servent::T_RELAY) && (s->status==Servent::S_CONNECTED) && (tnum>servMgr->kickPushInterval))
+ {
+/* ChanHitList *hits[ChanMgr::MAX_HITLISTS];
+ int numHits=0;
+ for(int i=0; i<ChanMgr::MAX_HITLISTS; i++)
+ {
+ ChanHitList *chl = &chanMgr->hitlists[i];
+ if (chl->isUsed())
+ hits[numHits++] = chl;
+ }
+
+ bool isfw = false;
+ int numRelay = 0;
+ if (numHits)
+ {
+ for(int k=0; k<numHits; k++)
+ {
+ ChanHitList *chl = hits[k];
+ if (chl->isUsed())
+ {
+ for (int j=0; j<ChanHitList::MAX_HITS; j++ )
+ {
+ ChanHit *hit = &chl->hits[j];
+ if (hit->host.isValid() && (h2.ip == hit->host.ip))
+ {
+ if (hit->firewalled)
+ isfw = true;
+ numRelay = hit->numRelays;
+ }
+ }
+ }
+ }
+ }
+ if ((isfw==true) && (numRelay==0))
+ {
+ char hostName[256];
+ h2.toStr(hostName);
+ if (servMgr->isCheckPushStream())
+ {
+ s->thread.active = false;
+ LOG_ERROR("Stop firewalled Servent : %s",hostName);
+ }
+ }*/
+
+ chanMgr->hitlistlock.on();
+ ChanHitList *chl = chanMgr->findHitListByID(s->chanID);
+ if (chl){
+ ChanHit *hit = chl->hit;
+ while(hit){
+ if ((hit->numHops == 1) && hit->host.isValid() && (h2.ip == hit->host.ip) && hit->firewalled /*&& !hit->numRelays*/)
+ {
+ char hostName[256];
+ h2.toStr(hostName);
+ if (servMgr->isCheckPushStream())
+ {
+ s->thread.active = false;
+ LOG_ERROR("Stop firewalled Servent : %s",hostName);
+ }
+ }
+ hit = hit->next;
+ }
+
+ }
+ chanMgr->hitlistlock.off();
+
+
+ }
+ }
+ s=s->next;
+ }
+ LOG_DEBUG("Servent scan finished.");
+ }
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : servmgr.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SERVMGR_H
+#define _SERVMGR_H
+
+#include "servent.h"
+
+// ----------------------------------
+
+const int MIN_YP_RETRY = 20;
+const int MIN_TRACKER_RETRY = 10;
+const int MIN_RELAY_RETRY = 5;
+
+// ----------------------------------
+class BCID
+{
+public:
+ BCID()
+ :next(0),valid(true)
+ {}
+
+ bool writeVariable(Stream &, const String &);
+
+ GnuID id;
+ String name,email,url;
+ bool valid;
+ BCID *next;
+};
+
+
+// ----------------------------------
+class ServHost
+{
+public:
+ enum TYPE
+ {
+ T_NONE,
+ T_STREAM,
+ T_CHANNEL,
+ T_SERVENT,
+ T_TRACKER
+ };
+
+ ServHost() {init();}
+ void init()
+ {
+ host.init();
+ time = 0;
+ type = T_NONE;
+ }
+ void init(Host &h, TYPE tp, unsigned int tim)
+ {
+ init();
+ host = h;
+ type = tp;
+ if (tim)
+ time = tim;
+ else
+ time = sys->getTime();
+ }
+
+ static const char *getTypeStr(TYPE);
+ static TYPE getTypeFromStr(const char *);
+
+ TYPE type;
+ Host host;
+ unsigned int time;
+};
+// ----------------------------------
+class ServFilter
+{
+public:
+ enum
+ {
+ F_PRIVATE = 0x01,
+ F_BAN = 0x02,
+ F_NETWORK = 0x04,
+ F_DIRECT = 0x08
+ };
+
+ ServFilter() {init();}
+ void init()
+ {
+ flags = 0;
+ host.init();
+ }
+
+ bool writeVariable(Stream &, const String &);
+
+ Host host;
+ unsigned int flags;
+};
+
+// ----------------------------------
+// ServMgr keeps track of Servents
+class ServMgr
+{
+
+
+
+public:
+
+ enum NOTIFY_TYPE
+ {
+ NT_UPGRADE = 0x0001,
+ NT_PEERCAST = 0x0002,
+ NT_BROADCASTERS = 0x0004,
+ NT_TRACKINFO = 0x0008
+ };
+
+ enum FW_STATE
+ {
+ FW_OFF,
+ FW_ON,
+ FW_UNKNOWN
+ };
+ enum {
+
+ MAX_HOSTCACHE = 100, // max. amount of hosts in cache
+ MIN_HOSTS = 3, // min. amount of hosts that should be kept in cache
+
+ MAX_OUTGOING = 3, // max. number of outgoing servents to use
+ MAX_INCOMING = 6, // max. number of public incoming servents to use
+ MAX_TRYOUT = 10, // max. number of outgoing servents to try connect
+ MIN_CONNECTED = 3, // min. amount of connected hosts that should be kept
+
+ MIN_RELAYS = 1,
+
+ MAX_FILTERS = 50,
+
+ MAX_VERSIONS = 16,
+
+ MAX_PREVIEWTIME = 300, // max. seconds preview per channel available (direct connections)
+ MAX_PREVIEWWAIT = 300, // max. seconds wait between previews
+
+ };
+
+ enum AUTH_TYPE
+ {
+ AUTH_COOKIE,
+ AUTH_HTTPBASIC
+ };
+
+
+
+ ServMgr();
+
+ bool start();
+
+ Servent *findServent(unsigned int,unsigned short,GnuID &);
+ Servent *findServent(Servent::TYPE);
+ Servent *findServent(Servent::TYPE,Host &,GnuID &);
+ Servent *findOldestServent(Servent::TYPE,bool);
+ Servent *findServentByIndex(int);
+ Servent *findServentByServentID(int);
+
+ bool writeVariable(Stream &, const String &);
+ Servent *allocServent();
+ unsigned int numUsed(int);
+ unsigned int numStreams(GnuID &, Servent::TYPE,bool);
+ unsigned int numStreams(Servent::TYPE,bool);
+ unsigned int numConnected(int,bool,unsigned int);
+ unsigned int numConnected(int t,int tim = 0)
+ {
+ return numConnected(t,false,tim)+numConnected(t,true,tim);
+ }
+ unsigned int numConnected();
+ unsigned int numServents();
+
+ unsigned int totalConnected()
+ {
+ //return numConnected(Servent::T_OUTGOING) + numConnected(Servent::T_INCOMING);
+ return numConnected();
+ }
+ unsigned int numOutgoing();
+ bool isFiltered(int,Host &h);
+ bool addOutgoing(Host,GnuID &,bool);
+ Servent *findConnection(Servent::TYPE,GnuID &);
+
+
+ static THREAD_PROC serverProc(ThreadInfo *);
+ static THREAD_PROC clientProc(ThreadInfo *);
+ static THREAD_PROC trackerProc(ThreadInfo *);
+ static THREAD_PROC idleProc(ThreadInfo *);
+
+ int broadcast(GnuPacket &,Servent * = NULL);
+ int route(GnuPacket &, GnuID &, Servent * = NULL);
+
+ XML::Node *createServentXML();
+
+ void connectBroadcaster();
+ void procConnectArgs(char *,ChanInfo &);
+
+ void quit();
+ void closeConnections(Servent::TYPE);
+
+ void checkFirewall();
+
+ // host cache
+ void addHost(Host &,ServHost::TYPE,unsigned int);
+ int getNewestServents(Host *,int, Host &);
+ ServHost getOutgoingServent(GnuID &);
+ void deadHost(Host &,ServHost::TYPE);
+ unsigned int numHosts(ServHost::TYPE);
+ void clearHostCache(ServHost::TYPE);
+ bool seenHost(Host &,ServHost::TYPE,unsigned int);
+
+ void setMaxRelays(int);
+ void setFirewall(FW_STATE);
+ bool checkForceIP();
+ FW_STATE getFirewall() {return firewalled;}
+ void saveSettings(const char *);
+ void loadSettings(const char *);
+ void setPassiveSearch(unsigned int);
+ int findChannel(ChanInfo &);
+ bool getChannel(char *,ChanInfo &,bool);
+ void setFilterDefaults();
+
+ bool acceptGIV(ClientSocket *);
+ void addVersion(unsigned int);
+
+ void broadcastRootSettings(bool);
+ int broadcastPushRequest(ChanHit &, Host &, GnuID &, Servent::TYPE);
+ void writeRootAtoms(AtomStream &,bool);
+
+ int broadcastPacket(ChanPacket &,GnuID &,GnuID &,GnuID &,Servent::TYPE type);
+
+ void addValidBCID(BCID *);
+ void removeValidBCID(GnuID &);
+ BCID *findValidBCID(GnuID &);
+ BCID *findValidBCID(int);
+
+ unsigned int getUptime()
+ {
+ return sys->getTime()-startTime;
+ }
+
+ bool seenPacket(GnuPacket &);
+
+
+ bool needHosts()
+ {
+ return false;
+ //return numHosts(ServHost::T_SERVENT) < maxTryout;
+ }
+
+ unsigned int numActiveOnPort(int);
+ unsigned int numActive(Servent::TYPE);
+
+ bool needConnections()
+ {
+ return numConnected(Servent::T_PGNU,60) < minGnuIncoming;
+ }
+ bool tryFull()
+ {
+ return false;
+ //return maxTryout ? numUsed(Servent::T_OUTGOING) > maxTryout: false;
+ }
+
+ bool pubInOver()
+ {
+ return numConnected(Servent::T_PGNU) > maxGnuIncoming;
+// return maxIncoming ? numConnected(Servent::T_INCOMING,false) > maxIncoming : false;
+ }
+ bool pubInFull()
+ {
+ return numConnected(Servent::T_PGNU) >= maxGnuIncoming;
+// return maxIncoming ? numConnected(Servent::T_INCOMING,false) >= maxIncoming : false;
+ }
+
+ bool outUsedFull()
+ {
+ return false;
+// return maxOutgoing ? numUsed(Servent::T_OUTGOING) >= maxOutgoing: false;
+ }
+ bool outOver()
+ {
+ return false;
+// return maxOutgoing ? numConnected(Servent::T_OUTGOING) > maxOutgoing : false;
+ }
+
+ bool controlInFull()
+ {
+ return numConnected(Servent::T_CIN)>=maxControl;
+ }
+
+ bool outFull()
+ {
+ return false;
+// return maxOutgoing ? numConnected(Servent::T_OUTGOING) >= maxOutgoing : false;
+ }
+
+ bool relaysFull()
+ {
+ return numStreams(Servent::T_RELAY,false) >= maxRelays;
+ }
+ bool directFull()
+ {
+ return numStreams(Servent::T_DIRECT,false) >= maxDirect;
+ }
+
+ bool bitrateFull(unsigned int br)
+ {
+ return maxBitrateOut ? (BYTES_TO_KBPS(totalOutput(false))+br) > maxBitrateOut : false;
+ }
+
+ unsigned int totalOutput(bool);
+ unsigned int totalInput(bool);
+
+ static ThreadInfo serverThread,idleThread;
+
+
+ Servent *servents;
+ WLock lock;
+
+ ServHost hostCache[MAX_HOSTCACHE];
+
+ char password[64];
+
+ bool allowGnutella;
+
+ unsigned int maxBitrateOut,maxControl,maxRelays,maxDirect;
+ unsigned int minGnuIncoming,maxGnuIncoming;
+ unsigned int maxServIn;
+
+ bool isDisabled;
+ bool isRoot;
+ int totalStreams;
+
+ Host serverHost;
+ String rootHost;
+ String rootHost2;
+
+ char downloadURL[128];
+ String rootMsg;
+ String forceIP;
+ char connectHost[128];
+ GnuID networkID;
+ unsigned int firewallTimeout;
+ int showLog;
+ int shutdownTimer;
+ bool pauseLog;
+ bool forceNormal;
+ bool useFlowControl;
+ unsigned int lastIncoming;
+
+ bool restartServer;
+ bool allowDirect;
+ bool autoConnect,autoServe,forceLookup;
+ int queryTTL;
+
+ unsigned int allowServer1,allowServer2;
+ unsigned int startTime;
+ unsigned int tryoutDelay;
+ unsigned int refreshHTML;
+ unsigned int relayBroadcast;
+
+ unsigned int notifyMask;
+
+ BCID *validBCID;
+ GnuID sessionID;
+
+ ServFilter filters[MAX_FILTERS];
+ int numFilters;
+
+
+ CookieList cookieList;
+ AUTH_TYPE authType;
+
+ char htmlPath[128];
+ unsigned int clientVersions[MAX_VERSIONS],clientCounts[MAX_VERSIONS];
+ int numVersions;
+
+ int serventNum;
+ String chanLog;
+
+ char modulePath[256]; //JP-EX
+ int enableGetName; //JP-EX
+ int allowConnectPCST; //JP-EX
+ int autoRelayKeep; //JP-EX
+ unsigned int autoMaxRelaySetting; //JP-EX
+ unsigned int autoBumpSkipCount;//JP-EX
+ unsigned int kickPushStartRelays; //JP-EX
+ unsigned int kickPushInterval; //JP-EX
+ unsigned int kickPushTime;
+ bool isCheckPushStream(); //JP-EX
+ void banFirewalledHost(); //JP-EX
+
+ bool getModulePath; //JP-EX
+ bool clearPLS; //JP-EX
+ bool writeLogFile; //JP-EX
+
+ bool autoPort0Kick;
+ bool allowOnlyVP;
+ unsigned int kickKeepTime;
+ bool vpDebug;
+ bool saveIniChannel;
+ bool saveGuiPos;
+ bool keepDownstreams;
+
+ int maxRelaysIndexTxt; // for PCRaw (relay)
+
+private:
+ FW_STATE firewalled;
+};
+
+// ----------------------------------
+extern ServMgr *servMgr;
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : socket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// ClientSocket is a generic socket interface, Non OS/HW dependant.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include <stdio.h>
+#include <string.h>
+#include "socket.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
--- /dev/null
+// ------------------------------------------------
+// File : socket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+
+#include "common.h"
+#include "stream.h"
+
+//#define DISABLE_NAGLE 1
+
+class SocketBuffer {
+
+public:
+ SocketBuffer(const void *p, int l){
+ buf = ::new char[l];
+ len = l;
+ pos = 0;
+ next = NULL;
+ ctime = sys->getTime();
+ memcpy((void*)buf, p, l);
+ }
+
+ ~SocketBuffer(){
+ if (buf){
+ ::delete [] buf;
+ }
+ }
+ char *buf;
+ int len;
+ int pos;
+ unsigned int ctime;
+ SocketBuffer *next;
+};
+
+class SocketBufferList {
+
+public:
+ SocketBufferList(){
+ top = NULL;
+ last = NULL;
+ skipCount = 0;
+ lastSkipTime = 0;
+ }
+
+ bool isNull(){ return (top == NULL); }
+ void add(const void *p, int l){
+ SocketBuffer *tmp = new SocketBuffer(p,l);
+
+ if (!last){
+ top = tmp;
+ last = tmp;
+ } else {
+ last->next = tmp;
+ last = tmp;
+ }
+
+// LOG_DEBUG("tmp = %d, top = %d, last = %d", tmp, top, last);
+ }
+
+ SocketBuffer *getTop(){
+ unsigned int ctime = sys->getTime();
+
+ while(top){
+ if (top && (top->ctime + 10 >= ctime)){
+ break;
+ } else {
+// LOG_DEBUG("over 10sec(data skip)");
+ skipCount++;
+ lastSkipTime = sys->getTime();
+ deleteTop();
+ }
+ }
+ return top;
+ }
+
+ void deleteTop(){
+// LOG_DEBUG("oldtop = %d", top);
+ SocketBuffer *tmp = top;
+ top = tmp->next;
+ delete tmp;
+ if (!top){
+ last = NULL;
+ }
+
+// LOG_DEBUG("newtop = %d",top);
+ }
+
+ void clear(){
+ while(top){
+ SocketBuffer *tmp = top;
+ top = tmp->next;
+ delete tmp;
+ }
+ top = NULL;
+ last = NULL;
+ }
+
+ SocketBuffer *top;
+ SocketBuffer *last;
+ unsigned int skipCount;
+ unsigned int lastSkipTime;
+
+};
+
+// --------------------------------------------------
+class ClientSocket : public Stream
+{
+public:
+
+ ClientSocket()
+ {
+ readTimeout = 30000;
+ writeTimeout = 30000;
+#ifdef WIN32
+ skipCount = 0;
+ lastSkipTime = 0;
+#endif
+ }
+
+ ~ClientSocket(){
+#ifdef WIN32
+ bufList.clear();
+#endif
+ }
+
+ // required interface
+ virtual void open(Host &) = 0;
+ virtual void bind(Host &) = 0;
+ virtual void connect() = 0;
+ virtual bool active() = 0;
+ virtual ClientSocket *accept() = 0;
+ virtual Host getLocalHost() = 0;
+
+ virtual void setReadTimeout(unsigned int t)
+ {
+ readTimeout = t;
+ }
+ virtual void setWriteTimeout(unsigned int t)
+ {
+ writeTimeout = t;
+ }
+ virtual void setBlocking(bool) {}
+
+
+ static unsigned int getIP(char *);
+ static bool getHostname(char *,unsigned int);
+
+ virtual bool eof()
+ {
+ return active()==false;
+ }
+
+ Host host;
+
+#ifdef WIN32
+ SocketBufferList bufList;
+ virtual void bufferingWrite(const void *, int) = 0;
+ unsigned int skipCount;
+ unsigned int lastSkipTime;
+#endif
+
+ unsigned int readTimeout,writeTimeout;
+
+};
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : stats.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Statistic logging
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stats.h"
+#include "common.h"
+#include "sys.h"
+#include "stream.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+Stats stats;
+// ------------------------------------
+void Stats::clear()
+{
+ for(int i=0; i<Stats::MAX; i++)
+ {
+ current[i] = 0;
+ last[i] = 0;
+ perSec[i] = 0;
+ }
+ lastUpdate = 0;
+}
+// ------------------------------------
+void Stats::update()
+{
+ unsigned int ctime = sys->getTime();
+
+ unsigned int diff = ctime - lastUpdate;
+ if (diff >= /* 5 */ 1)
+ {
+
+ for(int i=0; i<Stats::MAX; i++)
+ {
+ perSec[i] = (current[i]-last[i])/diff;
+ last[i] = current[i];
+ }
+
+ lastUpdate = ctime;
+ }
+
+}
+// ------------------------------------
+bool Stats::writeVariable(Stream &out,const String &var)
+{
+ char buf[1024];
+
+ if (var == "totalInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)));
+ else if (var == "totalOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)));
+ else if (var == "totalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)+getPerSecond(Stats::BYTESOUT)));
+ else if (var == "wanInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN)));
+ else if (var == "wanOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT)));
+ else if (var == "wanTotalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS((getPerSecond(Stats::BYTESIN)-getPerSecond(Stats::LOCALBYTESIN))+(getPerSecond(Stats::BYTESOUT)-getPerSecond(Stats::LOCALBYTESOUT))));
+ else if (var == "netInPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAIN)));
+ else if (var == "netOutPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)));
+ else if (var == "netTotalPerSec")
+ sprintf(buf,"%.1f",BYTES_TO_KBPS(getPerSecond(Stats::PACKETDATAOUT)+getPerSecond(Stats::PACKETDATAIN)));
+ else if (var == "packInPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSIN));
+ else if (var == "packOutPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT));
+ else if (var == "packTotalPerSec")
+ sprintf(buf,"%.1f",getPerSecond(Stats::NUMPACKETSOUT)+getPerSecond(Stats::NUMPACKETSIN));
+
+ else
+ return false;
+
+ out.writeString(buf);
+
+ return true;
+}
+
+
+
--- /dev/null
+// ------------------------------------------------
+// File : stats.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STATS_H
+#define _STATS_H
+
+// ------------------------------------------------------
+class Stats
+{
+public:
+
+ void clear();
+ void update();
+
+ enum STAT
+ {
+ NONE,
+
+ PACKETSSTART,
+ NUMQUERYIN,NUMQUERYOUT,
+ NUMPINGIN,NUMPINGOUT,
+ NUMPONGIN,NUMPONGOUT,
+ NUMPUSHIN,NUMPUSHOUT,
+ NUMHITIN,NUMHITOUT,
+ NUMOTHERIN,NUMOTHEROUT,
+ NUMDROPPED,
+ NUMDUP,
+ NUMACCEPTED,
+ NUMOLD,
+ NUMBAD,
+ NUMHOPS1,NUMHOPS2,NUMHOPS3,NUMHOPS4,NUMHOPS5,NUMHOPS6,NUMHOPS7,NUMHOPS8,NUMHOPS9,NUMHOPS10,
+ NUMPACKETSIN,
+ NUMPACKETSOUT,
+ NUMROUTED,
+ NUMBROADCASTED,
+ NUMDISCARDED,
+ NUMDEAD,
+ PACKETDATAIN,
+ PACKETDATAOUT,
+ PACKETSEND,
+
+
+ BYTESIN,
+ BYTESOUT,
+ LOCALBYTESIN,
+ LOCALBYTESOUT,
+
+ MAX
+ };
+
+ bool writeVariable(class Stream &,const class String &);
+
+ void clearRange(STAT s, STAT e)
+ {
+ for(int i=s; i<=e; i++)
+ current[i] = 0;
+ }
+ void clear(STAT s) {current[s]=0;}
+ void add(STAT s,int n=1) {current[s]+=n;}
+ unsigned int getPerSecond(STAT s) {return perSec[s];}
+ unsigned int getCurrent(STAT s) {return current[s];}
+
+ unsigned int current[Stats::MAX],last[Stats::MAX],perSec[Stats::MAX];
+ unsigned int lastUpdate;
+};
+
+extern Stats stats;
+
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : stream.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Basic stream handling functions.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+#include "stream.h"
+#include "common.h"
+#include "sys.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void MemoryStream::convertFromBase64()
+{
+ char *out = buf;
+ char *in = buf;
+
+ int rl=len;
+ while(rl >= 4)
+ {
+ out += String::base64WordToChars(out,in);
+ in += 4;
+ rl -= 4;
+ }
+ *out = 0;
+ len = out-buf;
+}
+// -------------------------------------
+void FileStream::openReadOnly(const char *fn)
+{
+ file = fopen(fn,"rb");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteReplace(const char *fn)
+{
+ file = fopen(fn,"wb");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+// -------------------------------------
+void FileStream::openWriteAppend(const char *fn)
+{
+ file = fopen(fn,"ab");
+
+ if (!file)
+ throw StreamException("Unable to open file");
+}
+
+// -------------------------------------
+void FileStream::close()
+{
+ if (file)
+ {
+ fclose(file);
+ file = NULL;
+ }
+}
+// -------------------------------------
+void FileStream::rewind()
+{
+ if (file)
+ fseek(file,0,SEEK_SET);
+}
+// -------------------------------------
+int FileStream::length()
+{
+ int len = 0;
+ if (file)
+ {
+ int old = ftell(file);
+ fseek(file,0,SEEK_END);
+ len = ftell(file);
+ fseek(file,old,SEEK_SET);
+
+ }
+ return len;
+}
+
+// -------------------------------------
+bool FileStream::eof()
+{
+ if (file)
+ return (feof(file)!=0);
+ else
+ return true;
+}
+// -------------------------------------
+int FileStream::read(void *ptr, int len)
+{
+ if (!file)
+ return 0;
+ if (feof(file))
+ throw StreamException("End of file");
+
+ int r = (int)fread(ptr,1,len,file);
+
+ updateTotals(r, 0);
+ return r;
+}
+
+// -------------------------------------
+void FileStream::write(const void *ptr, int len)
+{
+ if (!file)
+ return;
+ fwrite(ptr,1,len,file);
+ updateTotals(0, len);
+
+}
+// -------------------------------------
+void FileStream::flush()
+{
+ if (!file)
+ return;
+ fflush(file);
+}
+// -------------------------------------
+int FileStream::pos()
+{
+ if (!file)
+ return 0;
+ return ftell(file);
+}
+
+// -------------------------------------
+void FileStream::seekTo(int pos)
+{
+ if (!file)
+ return;
+ fseek(file,pos,SEEK_SET);
+}
+
+// -------------------------------------
+void Stream::writeTo(Stream &out, int len)
+{
+ char tmp[4096];
+ while (len)
+ {
+ int rlen = sizeof(tmp);
+ if (rlen > len)
+ rlen = len;
+
+ read(tmp,rlen);
+ out.write(tmp,rlen);
+
+ len-=rlen;
+ }
+}
+// -------------------------------------
+int Stream::writeUTF8(unsigned int code)
+{
+ if (code < 0x80)
+ {
+ writeChar(code);
+ return 1;
+ }else
+ if (code < 0x0800)
+ {
+ writeChar(code>>6 | 0xC0);
+ writeChar(code & 0x3F | 0x80);
+ return 2;
+ }else if (code < 0x10000)
+ {
+ writeChar(code>>12 | 0xE0);
+ writeChar(code>>6 & 0x3F | 0x80);
+ writeChar(code & 0x3F | 0x80);
+ return 3;
+ }else
+ {
+ writeChar(code>>18 | 0xF0);
+ writeChar(code>>12 & 0x3F | 0x80);
+ writeChar(code>>6 & 0x3F | 0x80);
+ writeChar(code & 0x3F | 0x80);
+ return 4;
+ }
+
+}
+
+// -------------------------------------
+void Stream::skip(int len)
+{
+ char tmp[4096];
+ while (len)
+ {
+ int rlen = sizeof(tmp);
+ if (rlen > len)
+ rlen = len;
+ read(tmp,rlen);
+ len-=rlen;
+ }
+
+}
+
+
+// -------------------------------------
+void Stream::updateTotals(unsigned int in, unsigned int out)
+{
+ totalBytesIn += in;
+ totalBytesOut += out;
+
+ unsigned int tdiff = sys->getTime()-lastUpdate;
+ if (tdiff >= 5)
+ {
+ bytesInPerSec = (totalBytesIn-lastBytesIn)/tdiff;
+ bytesOutPerSec = (totalBytesOut-lastBytesOut)/tdiff;
+ lastBytesIn = totalBytesIn;
+ lastBytesOut = totalBytesOut;
+ lastUpdate = sys->getTime();
+ }
+}
+// -------------------------------------
+int Stream::readLine(char *in, int max)
+{
+ int i=0;
+ max -= 2;
+
+ while(max--)
+ {
+ char c;
+ read(&c,1);
+ if (c == '\n')
+ break;
+ if (c == '\r')
+ continue;
+ in[i++] = c;
+ }
+ in[i] = 0;
+ return i;
+}
+// -------------------------------------
+void Stream::write(const char *fmt,va_list ap)
+{
+ char tmp[4096];
+ vsprintf(tmp,fmt,ap);
+ write(tmp,strlen(tmp));
+}
+// -------------------------------------
+void Stream::writeStringF(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ write(fmt,ap);
+ va_end(ap);
+}
+// -------------------------------------
+void Stream::writeString(const char *str)
+{
+ write(str,strlen(str));
+}
+// -------------------------------------
+void Stream::writeLineF(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ write(fmt,ap);
+
+ if (writeCRLF)
+ write("\r\n",2);
+ else
+ write("\n",1);
+
+ va_end(ap);
+}
+
+// -------------------------------------
+void Stream::writeLine(const char *str)
+{
+ writeString(str);
+
+ if (writeCRLF)
+ write("\r\n",2);
+ else
+ write("\n",1);
+}
+
+// -------------------------------------
+int Stream::readWord(char *in, int max)
+{
+ int i=0;
+ while (!eof())
+ {
+ char c = readChar();
+
+ if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
+ {
+ if (i)
+ break; // stop reading
+ else
+ continue; // skip whitespace
+ }
+
+ if (i >= (max-1))
+ break;
+
+ in[i++] = c;
+ }
+
+ in[i]=0;
+ return i;
+}
+
+
+// --------------------------------------------------
+int Stream::readBase64(char *p, int max)
+{
+ char vals[4];
+
+ int cnt=0;
+ while (cnt < (max-4))
+ {
+ read(vals,4);
+ int rl = String::base64WordToChars(p,vals);
+ if (!rl)
+ break;
+
+ p+=rl;
+ cnt+=rl;
+ }
+ *p = 0;
+ return cnt;
+}
+
+
+// -------------------------------------
+int Stream::readBits(int cnt)
+{
+ int v = 0;
+
+ while (cnt)
+ {
+ if (!bitsPos)
+ bitsBuffer = readChar();
+
+ cnt--;
+
+ v |= (bitsBuffer&(1<<(7-bitsPos)))?(1<<cnt):0;
+
+ bitsPos = (bitsPos+1)&7;
+ }
+
+ return v;
+}
--- /dev/null
+// ------------------------------------------------
+// File : stream.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _STREAM_H
+#define _STREAM_H
+
+// -------------------------------------
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "common.h"
+#include "sys.h"
+#include "id.h"
+
+// -------------------------------------
+class Stream
+{
+public:
+ Stream()
+ :writeCRLF(true)
+ ,totalBytesIn(0)
+ ,totalBytesOut(0)
+ ,lastBytesIn(0)
+ ,lastBytesOut(0)
+ ,bytesInPerSec(0)
+ ,bytesOutPerSec(0)
+ ,lastUpdate(0)
+ ,bitsBuffer(0)
+ ,bitsPos(0)
+ {
+ }
+ virtual ~Stream() {}
+
+ virtual int readUpto(void *,int) {return 0;}
+ virtual int read(void *,int)=0;
+ virtual void write(const void *,int) = 0;
+ virtual bool eof()
+ {
+ throw StreamException("Stream can`t eof");
+ return false;
+ }
+
+ virtual void rewind()
+ {
+ throw StreamException("Stream can`t rewind");
+ }
+
+ virtual void seekTo(int)
+ {
+ throw StreamException("Stream can`t seek");
+ }
+
+ void writeTo(Stream &out, int len);
+ virtual void skip(int i);
+
+ virtual void close()
+ {
+ }
+
+ virtual void setReadTimeout(unsigned int )
+ {
+ }
+ virtual void setWriteTimeout(unsigned int )
+ {
+ }
+ virtual void setPollRead(bool)
+ {
+ }
+
+ virtual int getPosition() {return 0;}
+
+
+ // binary
+ char readChar()
+ {
+ char v;
+ read(&v,1);
+ return v;
+ }
+ short readShort()
+ {
+ short v;
+ read(&v,2);
+ CHECK_ENDIAN2(v);
+ return v;
+ }
+ long readLong()
+ {
+ long v;
+ read(&v,4);
+ CHECK_ENDIAN4(v);
+ return v;
+ }
+ int readInt()
+ {
+ return readLong();
+ }
+ ID4 readID4()
+ {
+ ID4 id;
+ read(id.getData(),4);
+ return id;
+ }
+ int readInt24()
+ {
+ int v=0;
+ read(&v,3);
+ CHECK_ENDIAN3(v);
+ }
+
+
+
+ long readTag()
+ {
+ long v = readLong();
+ return SWAP4(v);
+ }
+
+ int readString(char *s, int max)
+ {
+ int cnt=0;
+ while (max)
+ {
+ char c = readChar();
+ *s++ = c;
+ cnt++;
+ max--;
+ if (!c)
+ break;
+ }
+ return cnt;
+ }
+
+ virtual bool readReady() {return true;}
+ virtual int numPending() {return 0;}
+
+
+ void writeID4(ID4 id)
+ {
+ write(id.getData(),4);
+ }
+
+ void writeChar(char v)
+ {
+ write(&v,1);
+ }
+ void writeShort(short v)
+ {
+ CHECK_ENDIAN2(v);
+ write(&v,2);
+ }
+ void writeLong(long v)
+ {
+ CHECK_ENDIAN4(v);
+ write(&v,4);
+ }
+ void writeInt(int v) {writeLong(v);}
+
+ void writeTag(long v)
+ {
+ //CHECK_ENDIAN4(v);
+ writeLong(SWAP4(v));
+ }
+
+ void writeTag(char id[4])
+ {
+ write(id,4);
+ }
+
+ int writeUTF8(unsigned int);
+
+ // text
+ int readLine(char *in, int max);
+
+ int readWord(char *, int);
+ int readBase64(char *, int);
+
+ void write(const char *,va_list);
+ void writeLine(const char *);
+ void writeLineF(const char *,...);
+ void writeString(const char *);
+ void writeStringF(const char *,...);
+
+ bool writeCRLF;
+
+ int readBits(int);
+
+ void updateTotals(unsigned int,unsigned int);
+
+
+ unsigned char bitsBuffer;
+ unsigned int bitsPos;
+
+ unsigned int totalBytesIn,totalBytesOut;
+ unsigned int lastBytesIn,lastBytesOut;
+ unsigned int bytesInPerSec,bytesOutPerSec;
+ unsigned int lastUpdate;
+
+};
+
+
+// -------------------------------------
+class FileStream : public Stream
+{
+public:
+ FileStream() {file=NULL;}
+
+ void openReadOnly(const char *);
+ void openWriteReplace(const char *);
+ void openWriteAppend(const char *);
+ bool isOpen(){return file!=NULL;}
+ int length();
+ int pos();
+
+ virtual void seekTo(int);
+ virtual int getPosition() {return pos();}
+ virtual void flush();
+ virtual int read(void *,int);
+ virtual void write(const void *,int);
+ virtual bool eof();
+ virtual void rewind();
+ virtual void close();
+
+ FILE *file;
+};
+// -------------------------------------
+class MemoryStream : public Stream
+{
+public:
+ MemoryStream()
+ :buf(NULL)
+ ,len(0)
+ ,pos(0)
+ ,own(false)
+ {
+ }
+
+ MemoryStream(void *p, int l)
+ :buf((char *)p)
+ ,len(l)
+ ,pos(0)
+ ,own(false)
+ {
+ }
+
+ MemoryStream(int l)
+ :buf(new char[l])
+ ,len(l)
+ ,pos(0)
+ ,own(true)
+ {
+ }
+
+ ~MemoryStream() {free2();}
+
+ void readFromFile(FileStream &file)
+ {
+ len = file.length();
+ buf = new char[len];
+ own = true;
+ pos = 0;
+ file.read(buf,len);
+ }
+
+ void free2()
+ {
+ if (own && buf)
+ {
+ delete buf;
+ buf = NULL;
+ own = false;
+ }
+
+ }
+
+ virtual int read(void *p,int l)
+ {
+ if (pos+l <= len)
+ {
+ memcpy(p,&buf[pos],l);
+ pos += l;
+ return l;
+ }else
+ {
+ memset(p,0,l);
+ return 0;
+ }
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ if ((pos+l) > len)
+ throw StreamException("Stream - premature end of write()");
+ memcpy(&buf[pos],p,l);
+ pos += l;
+ }
+
+ virtual bool eof()
+ {
+ return pos >= len;
+ }
+
+ virtual void rewind()
+ {
+ pos = 0;
+ }
+
+ virtual void seekTo(int p)
+ {
+ pos = p;
+ }
+
+ virtual int getPosition()
+ {
+ return pos;
+ }
+
+ void convertFromBase64();
+
+
+ char *buf;
+ bool own;
+ int len,pos;
+};
+// --------------------------------------------------
+class IndirectStream : public Stream
+{
+public:
+
+ void init(Stream *s)
+ {
+ stream = s;
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return stream->read(p,l);
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ stream->write(p,l);
+ }
+
+ virtual bool eof()
+ {
+ return stream->eof();
+ }
+
+ virtual void close()
+ {
+ stream->close();
+ }
+
+ Stream *stream;
+};
+
+// -------------------------------------
+
+class SockBufStream : public Stream
+{
+public:
+ SockBufStream(Stream &sockStream, int bufsize=128*1024)
+ : sock(sockStream), mem(bufsize)
+ {
+ }
+
+ ~SockBufStream()
+ {
+ flush();
+ mem.free2();
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return sock.read(p, l);
+ }
+
+ virtual void write(const void *p, int len)
+ {
+ if ( mem.pos+len > mem.len )
+ flush();
+
+ mem.write(p, len);
+ }
+
+ void flush()
+ {
+ if ( mem.pos > 0 ) {
+ sock.write(mem.buf, mem.pos);
+ clearWriteBuffer();
+ }
+ }
+
+ void clearWriteBuffer()
+ {
+ mem.rewind();
+ }
+
+private:
+ Stream &sock;
+ MemoryStream mem;
+};
+
+// -------------------------------------
+class WriteBufferStream : public Stream
+{
+public:
+ WriteBufferStream(Stream *out_)
+ :buf(NULL)
+ ,own(false)
+ ,len(0)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ WriteBufferStream(void *p, int l, Stream *out_)
+ :buf((char *)p)
+ ,own(false)
+ ,len(l)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ WriteBufferStream(int l, Stream *out_)
+ :buf(new char[l])
+ ,own(true)
+ ,len(l)
+ ,pos(0)
+ ,out(out_)
+ {
+ }
+
+ virtual ~WriteBufferStream()
+ {
+ try {
+ flush();
+ } catch (StreamException &) {}
+ free();
+ }
+
+ void readFromFile(FileStream &file)
+ {
+ len = file.length();
+ buf = new char[len];
+ own = true;
+ pos = 0;
+ file.read(buf,len);
+ }
+
+ void flush()
+ {
+ if (!out || !buf) return;
+ out->write(buf, pos);
+ pos = 0;
+ }
+
+ void free()
+ {
+ if (own && buf)
+ {
+ delete buf;
+ buf = NULL;
+ own = false;
+ }
+
+ }
+
+ virtual int read(void *p,int l)
+ {
+ return 0;
+ }
+
+ virtual void write(const void *p,int l)
+ {
+ char *cp = (char *) p;
+ while ((pos + l) >= len) {
+ int n = len - pos;
+ memcpy(&buf[pos], cp, n);
+ l -= n;
+ cp += n;
+ pos = len;
+ flush();
+ if (pos != 0) return;
+ }
+ if (l > 0) {
+ memcpy(&buf[pos], cp, l);
+ pos += l;
+ }
+ }
+
+ virtual bool eof()
+ {
+ return true;
+ }
+
+ virtual void rewind()
+ {
+ pos = 0;
+ }
+
+ virtual void seekTo(int p)
+ {
+ pos = p;
+ }
+
+ virtual int getPosition()
+ {
+ return pos;
+ }
+
+ void convertFromBase64();
+
+
+ char *buf;
+ bool own;
+ int len,pos;
+ Stream *out;
+};
+
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : sys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Sys is a base class for all things systemy, like starting threads, creating sockets etc..
+// Lock is a very basic cross platform CriticalSection class
+// SJIS-UTF8 conversion by ????
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "common.h"
+#include "sys.h"
+#include "socket.h"
+#include "gnutella.h"
+#include "servmgr.h" //JP-EX
+#ifdef WIN32
+#include "utf8.h" //JP-Patch
+#endif
+#include <stdlib.h>
+#include <time.h>
+#include "jis.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// -----------------------------------
+#define isSJIS(a,b) ((a >= 0x81 && a <= 0x9f || a >= 0xe0 && a<=0xfc) && (b >= 0x40 && b <= 0x7e || b >= 0x80 && b<=0xfc))
+#define isEUC(a) (a >= 0xa1 && a <= 0xfe)
+#define isASCII(a) (a <= 0x7f)
+#define isPLAINASCII(a) (((a >= '0') && (a <= '9')) || ((a >= 'a') && (a <= 'z')) || ((a >= 'A') && (a <= 'Z')))
+#define isUTF8(a,b) ((a & 0xc0) == 0xc0 && (b & 0x80) == 0x80 )
+#define isESCAPE(a,b) ((a == '&') && (b == '#'))
+#define isHTMLSPECIAL(a) ((a == '&') || (a == '\"') || (a == '\'') || (a == '<') || (a == '>'))
+
+
+
+// -----------------------------------
+const char *LogBuffer::logTypes[]=
+{
+ "",
+ "DBUG",
+ "EROR",
+ "GNET",
+ "CHAN",
+};
+
+// -----------------------------------
+// base64 encode/decode taken from ices2 source..
+static char base64table[64] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+#if 0
+// -----------------------------------
+static char *util_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = malloc(len*4/3 + 4);
+ char *result = out;
+ int chunk;
+
+ while(len > 0) {
+ chunk = (len >3)?3:len;
+ *out++ = base64table[(*data & 0xFC)>>2];
+ *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+ switch(chunk) {
+ case 3:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+ *out++ = base64table[(*(data+2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+
+ return result;
+}
+#endif
+
+// -----------------------------------
+static int base64chartoval(char input)
+{
+ if(input >= 'A' && input <= 'Z')
+ return input - 'A';
+ else if(input >= 'a' && input <= 'z')
+ return input - 'a' + 26;
+ else if(input >= '0' && input <= '9')
+ return input - '0' + 52;
+ else if(input == '+')
+ return 62;
+ else if(input == '/')
+ return 63;
+ else if(input == '=')
+ return -1;
+ else
+ return -2;
+}
+
+// -----------------------------------
+static char *util_base64_decode(char *input)
+{
+ return NULL;
+}
+
+
+
+
+
+// ------------------------------------------
+Sys::Sys()
+{
+ idleSleepTime = 10;
+ logBuf = new LogBuffer(1000,100);
+ numThreads=0;
+}
+
+// ------------------------------------------
+void Sys::sleepIdle()
+{
+ sleep(idleSleepTime);
+}
+
+// ------------------------------------------
+bool Host::isLocalhost()
+{
+ return loopbackIP() || (ip == ClientSocket::getIP(NULL));
+}
+// ------------------------------------------
+void Host::fromStrName(const char *str, int p)
+{
+ if (!strlen(str))
+ {
+ port = 0;
+ ip = 0;
+ return;
+ }
+
+ char name[128];
+ strncpy(name,str,sizeof(name)-1);
+ name[127] = '\0';
+ port = p;
+ char *pp = strstr(name,":");
+ if (pp)
+ {
+ port = atoi(pp+1);
+ pp[0] = 0;
+ }
+
+ ip = ClientSocket::getIP(name);
+}
+// ------------------------------------------
+void Host::fromStrIP(const char *str, int p)
+{
+ unsigned int ipb[4];
+ unsigned int ipp;
+
+
+ if (strstr(str,":"))
+ {
+ if (sscanf(str,"%03d.%03d.%03d.%03d:%d",&ipb[0],&ipb[1],&ipb[2],&ipb[3],&ipp) == 5)
+ {
+ ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+ port = ipp;
+ }else
+ {
+ ip = 0;
+ port = 0;
+ }
+ }else{
+ port = p;
+ if (sscanf(str,"%03d.%03d.%03d.%03d",&ipb[0],&ipb[1],&ipb[2],&ipb[3]) == 4)
+ ip = ((ipb[0]&0xff) << 24) | ((ipb[1]&0xff) << 16) | ((ipb[2]&0xff) << 8) | ((ipb[3]&0xff));
+ else
+ ip = 0;
+ }
+}
+// -----------------------------------
+bool Host::isMemberOf(Host &h)
+{
+ if (h.ip==0)
+ return false;
+
+ if( h.ip0() != 255 && ip0() != h.ip0() )
+ return false;
+ if( h.ip1() != 255 && ip1() != h.ip1() )
+ return false;
+ if( h.ip2() != 255 && ip2() != h.ip2() )
+ return false;
+ if( h.ip3() != 255 && ip3() != h.ip3() )
+ return false;
+
+/* removed for endieness compatibility
+ for(int i=0; i<4; i++)
+ if (h.ipByte[i] != 255)
+ if (ipByte[i] != h.ipByte[i])
+ return false;
+*/
+ return true;
+}
+
+// -----------------------------------
+char *trimstr(char *s1)
+{
+ while (*s1)
+ {
+ if ((*s1 == ' ') || (*s1 == '\t'))
+ s1++;
+ else
+ break;
+
+ }
+
+ char *s = s1;
+
+ if(strlen(s1) > 0) {
+/* s1 = s1+strlen(s1);
+
+ while (*--s1)
+ if ((*s1 != ' ') && (*s1 != '\t'))
+ break;*/
+
+ s1 = s1+strlen(s1);
+
+// s1[1] = 0;
+
+ while (*--s1)
+ if ((*s1 != ' ') && (*s1 != '\t'))
+ break;
+
+ s1[1] = 0;
+ }
+ return s;
+}
+
+// -----------------------------------
+char *stristr(const char *s1, const char *s2)
+{
+ while (*s1)
+ {
+ if (TOUPPER(*s1) == TOUPPER(*s2))
+ {
+ const char *c1 = s1;
+ const char *c2 = s2;
+
+ while (*c1 && *c2)
+ {
+ if (TOUPPER(*c1) != TOUPPER(*c2))
+ break;
+ c1++;
+ c2++;
+ }
+ if (*c2==0)
+ return (char *)s1;
+ }
+
+ s1++;
+ }
+ return NULL;
+}
+// -----------------------------------
+bool String::isValidURL()
+{
+ return (strnicmp(data,"http://",7)==0) || (strnicmp(data,"mailto:",7)==0);
+}
+
+// -----------------------------------
+void String::setFromTime(unsigned int t)
+{
+// char *p = ctime((time_t*)&t);
+ time_t tmp = t;
+ char *p = ctime(&tmp);
+ if (p)
+ strcpy(data,p);
+ else
+ strcpy(data,"-");
+ type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromStopwatch(unsigned int t)
+{
+ unsigned int sec,min,hour,day;
+
+ sec = t%60;
+ min = (t/60)%60;
+ hour = (t/3600)%24;
+ day = (t/86400);
+
+ if (day)
+ sprintf(data,"%d day, %d hour",day,hour);
+ else if (hour)
+ sprintf(data,"%d hour, %d min",hour,min);
+ else if (min)
+ sprintf(data,"%d min, %d sec",min,sec);
+ else if (sec)
+ sprintf(data,"%d sec",sec);
+ else
+ sprintf(data,"-");
+
+ type = T_ASCII;
+}
+// -----------------------------------
+void String::setFromString(const char *str, TYPE t)
+{
+ int cnt=0;
+ bool quote=false;
+ while (*str)
+ {
+ bool add=true;
+ if (*str == '\"')
+ {
+ if (quote)
+ break;
+ else
+ quote = true;
+ add = false;
+ }else if (*str == ' ')
+ {
+ if (!quote)
+ {
+ if (cnt)
+ break;
+ else
+ add = false;
+ }
+ }
+
+ if (add)
+ {
+ data[cnt++] = *str++;
+ if (cnt >= (MAX_LEN-1))
+ break;
+ }else
+ str++;
+ }
+ data[cnt] = 0;
+ type = t;
+}
+
+// -----------------------------------
+int String::base64WordToChars(char *out,const char *input)
+{
+ char *start = out;
+ signed char vals[4];
+
+ vals[0] = base64chartoval(*input++);
+ vals[1] = base64chartoval(*input++);
+ vals[2] = base64chartoval(*input++);
+ vals[3] = base64chartoval(*input++);
+
+ if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1)
+ return 0;
+
+ *out++ = vals[0]<<2 | vals[1]>>4;
+ if(vals[2] >= 0)
+ *out++ = ((vals[1]&0x0F)<<4) | (vals[2]>>2);
+ else
+ *out++ = 0;
+
+ if(vals[3] >= 0)
+ *out++ = ((vals[2]&0x03)<<6) | (vals[3]);
+ else
+ *out++ = 0;
+
+ return out-start;
+}
+
+// -----------------------------------
+void String::BASE642ASCII(const char *input)
+{
+ char *out = data;
+ int len = strlen(input);
+
+ while(len >= 4)
+ {
+ out += base64WordToChars(out,input);
+ input += 4;
+ len -= 4;
+ }
+ *out = 0;
+}
+
+
+
+// -----------------------------------
+void String::UNKNOWN2UNICODE(const char *in,bool safe)
+{
+ MemoryStream utf8(data,MAX_LEN-1);
+
+ unsigned char c;
+ unsigned char d;
+
+ while (c = *in++)
+ {
+ d = *in;
+
+ if (isUTF8(c,d)) // utf8 encoded
+ {
+ int numChars=0;
+ int i;
+
+ for(i=0; i<6; i++)
+ {
+ if (c & (0x80>>i))
+ numChars++;
+ else
+ break;
+ }
+
+ utf8.writeChar(c);
+ for(i=0; i<numChars-1; i++)
+ utf8.writeChar(*in++);
+
+ }
+ else if(isSJIS(c,d)) // shift_jis
+ {
+ utf8.writeUTF8(JISConverter::sjisToUnicode((c<<8 | d)));
+ in++;
+
+ }
+ else if(isEUC(c) && isEUC(d)) // euc-jp
+ {
+ utf8.writeUTF8(JISConverter::eucToUnicode((c<<8 | d)));
+ in++;
+
+ }
+ else if (isESCAPE(c,d)) // html escape tags &#xx;
+ {
+ in++;
+ char code[16];
+ char *cp = code;
+ while (c=*in++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+
+ utf8.writeUTF8(strtoul(code,NULL,10));
+
+ }
+ else if (isPLAINASCII(c)) // plain ascii : a-z 0-9 etc..
+ {
+ utf8.writeUTF8(c);
+
+ }
+ else if (isHTMLSPECIAL(c) && safe)
+ {
+ const char *str = NULL;
+ if (c == '&') str = "&";
+ else if (c == '\"') str = """;
+ else if (c == '\'') str = "'";
+ else if (c == '<') str = "<";
+ else if (c == '>') str = ">";
+ else str = "?";
+
+ utf8.writeString(str);
+ }
+ else
+ {
+ utf8.writeUTF8(c);
+ }
+
+ if (utf8.pos >= (MAX_LEN-10))
+ break;
+
+
+ }
+
+ utf8.writeChar(0); // null terminate
+
+}
+
+// -----------------------------------
+void String::ASCII2HTML(const char *in)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ unsigned char c;
+ const char *p = in;
+ while (c = *p++)
+ {
+
+ if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+ {
+ *op++ = c;
+ }else
+ {
+ sprintf(op,"&#x%02X;",(int)c);
+ op+=6;
+ }
+ if (op >= oe)
+ break;
+ }
+ *op = 0;
+}
+// -----------------------------------
+void String::ASCII2ESC(const char *in, bool safe)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ unsigned char c;
+ while (c = *p++)
+ {
+ if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
+ *op++ = c;
+ else
+ {
+ *op++ = '%';
+ if (safe)
+ *op++ = '%';
+ *op=0;
+ sprintf(op,"%02X",(int)c);
+ op+=2;
+ }
+ if (op >= oe)
+ break;
+ }
+ *op=0;
+}
+// -----------------------------------
+void String::HTML2ASCII(const char *in)
+{
+ unsigned char c;
+ char *o = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ while (c = *p++)
+ {
+ if ((c == '&') && (p[0] == '#'))
+ {
+ p++;
+ char code[8];
+ char *cp = code;
+ char ec = *p++; // hex/dec
+ while (c=*p++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+ c = (unsigned char)strtoul(code,NULL,ec=='x'?16:10);
+ }
+ *o++ = c;
+ if (o >= oe)
+ break;
+ }
+
+ *o=0;
+}
+// -----------------------------------
+void String::HTML2UNICODE(const char *in)
+{
+ MemoryStream utf8(data,MAX_LEN-1);
+
+ unsigned char c;
+ while (c = *in++)
+ {
+ if ((c == '&') && (*in == '#'))
+ {
+ in++;
+ char code[16];
+ char *cp = code;
+ char ec = *in++; // hex/dec
+ while (c=*in++)
+ {
+ if (c!=';')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = 0;
+ utf8.writeUTF8(strtoul(code,NULL,ec=='x'?16:10));
+ }else
+ utf8.writeUTF8(c);
+
+ if (utf8.pos >= (MAX_LEN-10))
+ break;
+ }
+
+ utf8.writeUTF8(0);
+}
+
+// -----------------------------------
+void String::ESC2ASCII(const char *in)
+{
+ unsigned char c;
+ char *o = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ while (c = *p++)
+ {
+ if (c == '+')
+ c = ' ';
+ else if (c == '%')
+ {
+ if (p[0] == '%')
+ p++;
+
+ char hi = TOUPPER(p[0]);
+ char lo = TOUPPER(p[1]);
+ c = (TONIBBLE(hi)<<4) | TONIBBLE(lo);
+ p+=2;
+ }
+ *o++ = c;
+ if (o >= oe)
+ break;
+ }
+
+ *o=0;
+}
+// -----------------------------------
+void String::ASCII2META(const char *in, bool safe)
+{
+ char *op = data;
+ char *oe = data+MAX_LEN-10;
+ const char *p = in;
+ unsigned char c;
+ while (c = *p++)
+ {
+ switch (c)
+ {
+ case '%':
+ if (safe)
+ *op++='%';
+ break;
+ case ';':
+ c = ':';
+ break;
+ }
+
+ *op++=c;
+ if (op >= oe)
+ break;
+ }
+ *op=0;
+}
+#ifdef WIN32
+// -----------------------------------
+void String::ASCII2SJIS(const char *in) //JP-EX
+{
+ char *op = data;
+ char *p;
+ if (utf8_decode(in,&p)<0)
+ {
+ strcpy(op,in);
+ return;
+ }
+ strcpy(op,p);
+ free(p);
+}
+#endif
+// -----------------------------------
+void String::convertTo(TYPE t)
+{
+ if (t != type)
+ {
+ String tmp = *this;
+
+ // convert to ASCII
+ switch (type)
+ {
+ case T_UNKNOWN:
+ case T_ASCII:
+ break;
+ case T_HTML:
+ tmp.HTML2ASCII(data);
+ break;
+ case T_ESC:
+ case T_ESCSAFE:
+ tmp.ESC2ASCII(data);
+ break;
+ case T_META:
+ case T_METASAFE:
+ break;
+ case T_BASE64:
+ tmp.BASE642ASCII(data);
+ break;
+ }
+
+ // convert to new format
+ switch (t)
+ {
+ case T_UNKNOWN:
+ case T_ASCII:
+ strcpy(data,tmp.data);
+ break;
+ case T_UNICODE:
+ UNKNOWN2UNICODE(tmp.data,false);
+ break;
+ case T_UNICODESAFE:
+ UNKNOWN2UNICODE(tmp.data,true);
+ break;
+ case T_HTML:
+ ASCII2HTML(tmp.data);
+ break;
+ case T_ESC:
+ ASCII2ESC(tmp.data,false);
+ break;
+ case T_ESCSAFE:
+ ASCII2ESC(tmp.data,true);
+ break;
+ case T_META:
+ ASCII2META(tmp.data,false);
+ break;
+ case T_METASAFE:
+ ASCII2META(tmp.data,true);
+ break;
+#ifdef WIN32
+ case T_SJIS: //JP-EX
+ ASCII2SJIS(tmp.data);
+ break;
+#endif
+ }
+
+ type = t;
+ }
+}
+// -----------------------------------
+void LogBuffer::write(const char *str, TYPE t)
+{
+ lock.on();
+
+ unsigned int len = strlen(str);
+ int cnt=0;
+ while (len)
+ {
+ unsigned int rlen = len;
+ if (rlen > (lineLen-1))
+ rlen = lineLen-1;
+
+ int i = currLine % maxLines;
+ int bp = i*lineLen;
+ strncpy(&buf[bp],str,rlen);
+ buf[bp+rlen] = 0;
+ if (cnt==0)
+ {
+ times[i] = sys->getTime();
+ types[i] = t;
+ }else
+ {
+ times[i] = 0;
+ types[i] = T_NONE;
+ }
+ currLine++;
+
+ str += rlen;
+ len -= rlen;
+ cnt++;
+ }
+
+ lock.off();
+}
+
+// -----------------------------------
+char *getCGIarg(const char *str, const char *arg)
+{
+ if (!str)
+ return NULL;
+
+// char *s = strstr(str,arg);
+ char *s = (char*)strstr(str,arg);
+
+ if (!s)
+ return NULL;
+
+ s += strlen(arg);
+
+ return s;
+}
+
+// -----------------------------------
+bool cmpCGIarg(char *str, char *arg, char *value)
+{
+ if ((!str) || (!strlen(value)))
+ return false;
+
+ if (strnicmp(str,arg,strlen(arg)) == 0)
+ {
+
+ str += strlen(arg);
+
+ return strncmp(str,value,strlen(value))==0;
+ }else
+ return false;
+}
+// -----------------------------------
+bool hasCGIarg(char *str, char *arg)
+{
+ if (!str)
+ return false;
+
+ char *s = strstr(str,arg);
+
+ if (!s)
+ return false;
+
+ return true;
+}
+
+
+// ---------------------------
+void GnuID::encode(Host *h, const char *salt1, const char *salt2, unsigned char salt3)
+{
+ int s1=0,s2=0;
+ for(int i=0; i<16; i++)
+ {
+ unsigned char ipb = id[i];
+
+ // encode with IP address
+ if (h)
+ ipb ^= ((unsigned char *)&h->ip)[i&3];
+
+ // add a bit of salt
+ if (salt1)
+ {
+ if (salt1[s1])
+ ipb ^= salt1[s1++];
+ else
+ s1=0;
+ }
+
+ // and some more
+ if (salt2)
+ {
+ if (salt2[s2])
+ ipb ^= salt2[s2++];
+ else
+ s2=0;
+ }
+
+ // plus some pepper
+ ipb ^= salt3;
+
+ id[i] = ipb;
+ }
+
+}
+// ---------------------------
+void GnuID::toStr(char *str)
+{
+
+ str[0] = 0;
+ for(int i=0; i<16; i++)
+ {
+ char tmp[8];
+ unsigned char ipb = id[i];
+
+ sprintf(tmp,"%02X",ipb);
+ strcat(str,tmp);
+ }
+
+}
+// ---------------------------
+void GnuID::fromStr(const char *str)
+{
+ clear();
+
+ if (strlen(str) < 32)
+ return;
+
+ char buf[8];
+
+ buf[2] = 0;
+
+ for(int i=0; i<16; i++)
+ {
+ buf[0] = str[i*2];
+ buf[1] = str[i*2+1];
+ id[i] = (unsigned char)strtoul(buf,NULL,16);
+ }
+
+}
+
+// ---------------------------
+void GnuID::generate(unsigned char flags)
+{
+ clear();
+
+ for(int i=0; i<16; i++)
+ id[i] = sys->rnd();
+
+ id[0] = flags;
+}
+
+// ---------------------------
+unsigned char GnuID::getFlags()
+{
+ return id[0];
+}
+
+// ---------------------------
+GnuIDList::GnuIDList(int max)
+:ids(new GnuID[max])
+{
+ maxID = max;
+ for(int i=0; i<maxID; i++)
+ ids[i].clear();
+}
+// ---------------------------
+GnuIDList::~GnuIDList()
+{
+ delete [] ids;
+}
+// ---------------------------
+bool GnuIDList::contains(GnuID &id)
+{
+ for(int i=0; i<maxID; i++)
+ if (ids[i].isSame(id))
+ return true;
+ return false;
+}
+// ---------------------------
+int GnuIDList::numUsed()
+{
+ int cnt=0;
+ for(int i=0; i<maxID; i++)
+ if (ids[i].storeTime)
+ cnt++;
+ return cnt;
+}
+// ---------------------------
+unsigned int GnuIDList::getOldest()
+{
+ unsigned int t=(unsigned int)-1;
+ for(int i=0; i<maxID; i++)
+ if (ids[i].storeTime)
+ if (ids[i].storeTime < t)
+ t = ids[i].storeTime;
+ return t;
+}
+// ---------------------------
+void GnuIDList::add(GnuID &id)
+{
+ unsigned int minTime = (unsigned int) -1;
+ int minIndex = 0;
+
+ // find same or oldest
+ for(int i=0; i<maxID; i++)
+ {
+ if (ids[i].isSame(id))
+ {
+ ids[i].storeTime = sys->getTime();
+ return;
+ }
+ if (ids[i].storeTime <= minTime)
+ {
+ minTime = ids[i].storeTime;
+ minIndex = i;
+ }
+ }
+
+ ids[minIndex] = id;
+ ids[minIndex].storeTime = sys->getTime();
+}
+// ---------------------------
+void GnuIDList::clear()
+{
+ for(int i=0; i<maxID; i++)
+ ids[i].clear();
+}
+
+// ---------------------------
+void LogBuffer::dumpHTML(Stream &out)
+{
+ WLockBlock lb(&lock);
+ lb.on();
+
+ unsigned int nl = currLine;
+ unsigned int sp = 0;
+ if (nl > maxLines)
+ {
+ nl = maxLines-1;
+ sp = (currLine+1)%maxLines;
+ }
+
+ String tim,str;
+ if (nl)
+ {
+ for(unsigned int i=0; i<nl; i++)
+ {
+ unsigned int bp = sp*lineLen;
+
+ if (types[sp])
+ {
+ tim.setFromTime(times[sp]);
+
+ out.writeString(tim.cstr());
+ out.writeString(" <b>[");
+ out.writeString(getTypeStr(types[sp]));
+ out.writeString("]</b> ");
+ }
+ str.set(&buf[bp]);
+ str.convertTo(String::T_HTML);
+
+ out.writeString(str.cstr());
+ out.writeString("<br>");
+
+ sp++;
+ sp %= maxLines;
+ }
+ }
+
+ lb.off();
+
+}
+
+// ---------------------------
+void ThreadInfo::shutdown()
+{
+ active = false;
+ //sys->waitThread(this);
+}
--- /dev/null
+// ------------------------------------------------
+// File : sys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _SYS_H
+#define _SYS_H
+
+#include <string.h>
+#include "common.h"
+
+#define RAND(a,b) (((a = 36969 * (a & 65535) + (a >> 16)) << 16) + \
+ (b = 18000 * (b & 65535) + (b >> 16)) )
+extern char *stristr(const char *s1, const char *s2);
+extern char *trimstr(char *s);
+
+
+#define MAX_CGI_LEN 1024
+// ------------------------------------
+class String
+{
+public:
+ enum {
+ MAX_LEN = 256
+ };
+
+ enum TYPE
+ {
+ T_UNKNOWN,
+ T_ASCII,
+ T_HTML,
+ T_ESC,
+ T_ESCSAFE,
+ T_META,
+ T_METASAFE,
+ T_BASE64,
+ T_UNICODE,
+ T_UNICODESAFE,
+#ifdef WIN32
+ T_SJIS, //JP-EX
+#endif
+ };
+
+ String() {clear();}
+ String(const char *p, TYPE t=T_ASCII)
+ {
+ set(p,t);
+ }
+
+ // set from straight null terminated string
+ void set(const char *p, TYPE t=T_ASCII)
+ {
+ strncpy(data,p,MAX_LEN-1);
+ data[MAX_LEN-1] = 0;
+ type = t;
+ }
+
+ // set from quoted or unquoted null terminated string
+ void setFromString(const char *str, TYPE t=T_ASCII);
+
+ // set from stopwatch
+ void setFromStopwatch(unsigned int t);
+
+ // set from time
+ void setFromTime(unsigned int t);
+
+
+ // from single word (end at whitespace)
+ void setFromWord(const char *str)
+ {
+ int i;
+ for(i=0; i<MAX_LEN-1; i++)
+ {
+ data[i] = *str++;
+ if ((data[i]==0) || (data[i]==' '))
+ break;
+ }
+ data[i]=0;
+ }
+
+
+ // set from null terminated string, remove first/last chars
+ void setUnquote(const char *p, TYPE t=T_ASCII)
+ {
+ int slen = strlen(p);
+ if (slen > 2)
+ {
+ if (slen >= MAX_LEN) slen = MAX_LEN;
+ strncpy(data,p+1,slen-2);
+ data[slen-2]=0;
+ }else
+ clear();
+ type = t;
+ }
+
+ void clear()
+ {
+ data[0]=0;
+ type = T_UNKNOWN;
+ }
+ void ASCII2ESC(const char *,bool);
+ void ASCII2HTML(const char *);
+ void ASCII2META(const char *,bool);
+ void ESC2ASCII(const char *);
+ void HTML2ASCII(const char *);
+ void HTML2UNICODE(const char *);
+ void BASE642ASCII(const char *);
+ void UNKNOWN2UNICODE(const char *,bool);
+#ifdef WIN32
+ void ASCII2SJIS(const char *); //JP-EX
+#endif
+
+ static int base64WordToChars(char *,const char *);
+
+ static bool isSame(const char *s1, const char *s2) {return strcmp(s1,s2)==0;}
+
+ bool startsWith(const char *s) const {return strncmp(data,s,strlen(s))==0;}
+ bool isValidURL();
+ bool isEmpty() {return data[0]==0;}
+ bool isSame(::String &s) const {return strcmp(data,s.data)==0;}
+ bool isSame(const char *s) const {return strcmp(data,s)==0;}
+ bool contains(::String &s) {return stristr(data,s.data)!=NULL;}
+ bool contains(const char *s) {return stristr(data,s)!=NULL;}
+ void append(const char *s)
+ {
+ if ((strlen(s)+strlen(data) < (MAX_LEN-1)))
+ strcat(data,s);
+ }
+ void append(char c)
+ {
+ char tmp[2];
+ tmp[0]=c;
+ tmp[1]=0;
+ append(tmp);
+ }
+
+ void prepend(const char *s)
+ {
+ ::String tmp;
+ tmp.set(s);
+ tmp.append(data);
+ tmp.type = type;
+ *this = tmp;
+ }
+
+ bool operator == (const char *s) const {return isSame(s);}
+
+ operator const char *() const {return data;}
+
+ void convertTo(TYPE t);
+
+ char *cstr() {return data;}
+
+ static bool isWhitespace(char c) {return c==' ' || c=='\t';}
+
+ TYPE type;
+ char data[MAX_LEN];
+};
+
+// ------------------------------------
+namespace peercast {
+class Random {
+public:
+ Random(int s=0x14235465)
+ {
+ setSeed(s);
+ }
+
+ unsigned int next()
+ {
+ return RAND(a[0],a[1]);
+ }
+
+ void setSeed(int s)
+ {
+ a[0] = a[1] = s;
+ }
+
+ unsigned long a[2];
+};
+}
+// ------------------------------------
+class Sys
+{
+public:
+ Sys();
+
+
+
+ virtual class ClientSocket *createSocket() = 0;
+ virtual bool startThread(class ThreadInfo *) = 0;
+ virtual void sleep(int) = 0;
+ virtual void appMsg(long,long = 0) = 0;
+ virtual unsigned int getTime() = 0;
+ virtual double getDTime() = 0;
+ virtual unsigned int rnd() = 0;
+ virtual void getURL(const char *) = 0;
+ virtual void exit() = 0;
+ virtual bool hasGUI() = 0;
+ virtual void callLocalURL(const char *,int)=0;
+ virtual void executeFile(const char *) = 0;
+ virtual void endThread(ThreadInfo *) {}
+ virtual void waitThread(ThreadInfo *, int timeout = 30000) {}
+
+
+
+#ifdef __BIG_ENDIAN__
+ unsigned short convertEndian(unsigned short v) { return SWAP2(v); }
+ unsigned int convertEndian(unsigned int v) { return SWAP4(v); }
+#else
+ unsigned short convertEndian(unsigned short v) { return v; }
+ unsigned int convertEndian(unsigned int v) { return v; }
+#endif
+
+
+ void sleepIdle();
+
+ unsigned int idleSleepTime;
+ unsigned int rndSeed;
+ unsigned int numThreads;
+
+ class LogBuffer *logBuf;
+};
+
+
+#ifdef WIN32
+#include <windows.h>
+
+typedef __int64 int64_t;
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+ WEvent()
+ {
+ event = ::CreateEvent(NULL, // no security attributes
+ TRUE, // manual-reset
+ FALSE,// initially non-signaled
+ NULL);// anonymous
+ }
+
+ ~WEvent()
+ {
+ ::CloseHandle(event);
+ }
+
+ void signal()
+ {
+ ::SetEvent(event);
+ }
+
+ void wait(int timeout = 30000)
+ {
+ switch(::WaitForSingleObject(event, timeout))
+ {
+ case WAIT_TIMEOUT:
+ throw TimeoutException();
+ break;
+ //case WAIT_OBJECT_0:
+ //break;
+ }
+ }
+
+ void reset()
+ {
+ ::ResetEvent(event);
+ }
+
+
+
+ HANDLE event;
+};
+
+
+
+// ------------------------------------
+typedef int (WINAPI *THREAD_FUNC)(ThreadInfo *);
+typedef unsigned int THREAD_HANDLE;
+#define THREAD_PROC int WINAPI
+#define vsnprintf _vsnprintf
+
+// ------------------------------------
+class WLock
+{
+public:
+ WLock()
+ {
+ InitializeCriticalSection(&cs);
+ }
+
+
+ void on()
+ {
+ EnterCriticalSection(&cs);
+ }
+
+ void off()
+ {
+ LeaveCriticalSection(&cs);
+ }
+
+ CRITICAL_SECTION cs;
+};
+#endif
+
+
+#ifdef _UNIX
+// ------------------------------------
+#include <pthread.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#include <sched.h>
+#define _BIG_ENDIAN 1
+#endif
+
+typedef long long int64_t;
+
+typedef int (*THREAD_FUNC)(ThreadInfo *);
+#define THREAD_PROC int
+typedef pthread_t THREAD_HANDLE;
+
+// ------------------------------------
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+
+// ------------------------------------
+class WEvent
+{
+public:
+
+ WEvent()
+ {
+ }
+
+ void signal()
+ {
+ }
+
+ void wait(int timeout = 30000)
+ {
+ }
+
+ void reset()
+ {
+ }
+
+};
+
+// ------------------------------------
+class WLock
+{
+private:
+ pthread_mutex_t mutex;
+public:
+ WLock()
+ {
+ const pthread_mutexattr_t mattr =
+ {
+#ifdef __APPLE__
+ PTHREAD_MUTEX_RECURSIVE
+#else
+ PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+ };
+
+ pthread_mutex_init( &mutex, &mattr );
+ }
+
+ ~WLock()
+ {
+ pthread_mutex_destroy( &mutex );
+ }
+
+
+ void on()
+ {
+ pthread_mutex_lock(&mutex);
+ }
+
+ void off()
+ {
+ pthread_mutex_unlock(&mutex);
+ }
+
+};
+#endif
+
+class WLockBlock
+{
+private:
+ WLock *lock;
+ bool flg;
+public:
+ WLockBlock(WLock *l){
+ lock = l;
+ flg = false;
+ }
+ ~WLockBlock(){
+ if (flg){
+ lock->off();
+ LOG_DEBUG("LOCK OFF by destructor");
+ }
+ }
+ void on(){
+ flg = true;
+ lock->on();
+ }
+ void off(){
+ flg = false;
+ lock->off();
+ }
+};
+
+// ------------------------------------
+class ThreadInfo
+{
+public:
+ //typedef int (__stdcall *THREAD_FUNC)(ThreadInfo *);
+
+ ThreadInfo()
+ {
+ active = false;
+ finish = false;
+ id = 0;
+ func = NULL;
+ data = NULL;
+ }
+
+ void shutdown();
+
+ volatile bool active;
+ volatile bool finish;
+ int id;
+ THREAD_FUNC func;
+ THREAD_HANDLE handle;
+
+
+ void *data;
+};
+
+
+// ------------------------------------
+class LogBuffer
+{
+public:
+ enum TYPE
+ {
+ T_NONE,
+ T_DEBUG,
+ T_ERROR,
+ T_NETWORK,
+ T_CHANNEL,
+ };
+
+ LogBuffer(int i, int l)
+ {
+ lineLen = l;
+ maxLines = i;
+ currLine = 0;
+ buf = new char[lineLen*maxLines];
+ times = new unsigned int [maxLines];
+ types = new TYPE [maxLines];
+ }
+
+ void clear()
+ {
+ currLine = 0;
+ }
+ void write(const char *, TYPE);
+ static const char *getTypeStr(TYPE t) {return logTypes[t];}
+ void dumpHTML(class Stream &);
+
+ char *buf;
+ unsigned int *times;
+ unsigned int currLine,maxLines,lineLen;
+ TYPE *types;
+ WLock lock;
+ static const char *logTypes[];
+
+};
+
+#define RWLOCK_READ_MAX 32
+
+class LockBlock
+{
+public:
+ LockBlock(WLock &l){ flg = false; lock = l; }
+ ~LockBlock(){ if (flg) lock.off(); }
+ void lockon(){ flg = true; lock.on(); }
+ void lockoff(){ flg = false; lock.off(); }
+
+private:
+ WLock lock;
+ bool flg;
+};
+
+// ------------------------------------
+extern Sys *sys;
+
+// ------------------------------------
+
+
+#if _BIG_ENDIAN
+#define CHECK_ENDIAN2(v) v=SWAP2(v)
+#define CHECK_ENDIAN3(v) v=SWAP3(v)
+#define CHECK_ENDIAN4(v) v=SWAP4(v)
+#else
+#define CHECK_ENDIAN2
+#define CHECK_ENDIAN3
+#define CHECK_ENDIAN4
+#endif
+
+
+// ------------------------------------
+#endif
+
--- /dev/null
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "url.h"
+#include "socket.h"
+#include "http.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "version2.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ------------------------------------------------
+void URLSource::stream(Channel *ch)
+{
+
+ String url,tmpUrl;
+ while (ch->thread.active && !peercastInst->isQuitting)
+ {
+ tmpUrl = url;
+ if (url.isEmpty())
+ url = baseurl;
+
+ url = streamURL(ch,url.cstr());
+ if (url == tmpUrl){
+ sys->sleep(2000);
+ }
+ }
+
+}
+// ------------------------------------------------
+int URLSource::getSourceRate()
+{
+ if (inputStream)
+ return inputStream->bytesInPerSec;
+ else
+ return 0;
+}
+
+// ------------------------------------------------
+::String URLSource::streamURL(Channel *ch, const char *url)
+{
+ String nextURL;
+
+ if (peercastInst->isQuitting || !ch->thread.active)
+ return nextURL;
+
+
+ String urlTmp;
+ urlTmp.set(url);
+
+ char *fileName = urlTmp.cstr();
+
+ PlayList *pls=NULL;
+ ChannelStream *source=NULL;
+
+ LOG_CHANNEL("Fetch URL=%s",fileName);
+
+ try
+ {
+
+ // get the source protocol
+ if (strnicmp(fileName,"http://",7)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_HTTP;
+ fileName += 7;
+ }
+ else if (strnicmp(fileName,"mms://",6)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+ fileName += 6;
+ }
+ else if (strnicmp(fileName,"pcp://",6)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_PCP;
+ fileName += 6;
+ }
+ else if (strnicmp(fileName,"file://",7)==0)
+ {
+ ch->info.srcProtocol = ChanInfo::SP_FILE;
+ fileName += 7;
+ }
+ else
+ {
+ ch->info.srcProtocol = ChanInfo::SP_FILE;
+ }
+
+ // default to mp3 for shoutcast servers
+ if (ch->info.contentType == ChanInfo::T_PLS)
+ ch->info.contentType = ChanInfo::T_MP3;
+
+
+ ch->setStatus(Channel::S_CONNECTING);
+
+ if ((ch->info.srcProtocol == ChanInfo::SP_HTTP) || (ch->info.srcProtocol == ChanInfo::SP_PCP) || (ch->info.srcProtocol == ChanInfo::SP_MMS))
+ {
+
+ if ((ch->info.contentType == ChanInfo::T_WMA) || (ch->info.contentType == ChanInfo::T_WMV))
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+
+
+ LOG_CHANNEL("Channel source is HTTP");
+
+ ClientSocket *inputSocket = sys->createSocket();
+ if (!inputSocket)
+ throw StreamException("Channel cannot create socket");
+
+
+ inputStream = inputSocket;
+
+
+ char *dir = strstr(fileName,"/");
+ if (dir)
+ *dir++=0;
+
+
+ LOG_CHANNEL("Fetch Host=%s",fileName);
+ if (dir)
+ LOG_CHANNEL("Fetch Dir=%s",dir);
+
+
+ Host host;
+ host.fromStrName(fileName,80);
+
+ inputSocket->open(host);
+ inputSocket->connect();
+
+ HTTP http(*inputSocket);
+ http.writeLineF("GET /%s HTTP/1.0",dir?dir:"");
+
+ http.writeLineF("%s %s",HTTP_HS_HOST,fileName);
+ http.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
+ http.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
+
+ if (ch->info.srcProtocol == ChanInfo::SP_MMS)
+ {
+ http.writeLineF("%s %s",HTTP_HS_AGENT,"NSPlayer/4.1.0.3856");
+ http.writeLine("Pragma: no-cache,rate=1.000000,request-context=1");
+ //http.writeLine("Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=4294967295:4294967295,request-context=22605256,max-duration=0");
+ http.writeLine("Pragma: xPlayStrm=1");
+ http.writeLine("Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
+ http.writeLine("Pragma: stream-switch-count=2");
+ http.writeLine("Pragma: stream-switch-entry=ffff:1:0 ffff:2:0");
+ }else
+ {
+ http.writeLineF("%s %s",HTTP_HS_AGENT,PCX_AGENT);
+ http.writeLineF("%s %d",PCX_HS_PCP,1);
+ http.writeLine("Icy-MetaData:1"); // fix by ravon
+ }
+
+ http.writeLine("");
+
+ int res = http.readResponse();
+
+
+ String name = ch->info.name;
+
+ while (http.nextHeader())
+ {
+
+ LOG_CHANNEL("Fetch HTTP: %s",http.cmdLine);
+
+ ChanInfo tmpInfo = ch->info;
+ Servent::readICYHeader(http,ch->info,NULL);
+
+ if (!tmpInfo.name.isEmpty())
+ ch->info.name = tmpInfo.name;
+ if (!tmpInfo.genre.isEmpty())
+ ch->info.genre = tmpInfo.genre;
+ if (!tmpInfo.url.isEmpty())
+ ch->info.url = tmpInfo.url;
+
+ if (http.isHeader("icy-metaint"))
+ ch->icyMetaInterval = http.getArgInt();
+ else if (http.isHeader("Location:"))
+ nextURL.set(http.getArgStr());
+
+ char *arg = http.getArgStr();
+ if (arg)
+ {
+ if (http.isHeader("content-type"))
+ {
+ if (stristr(arg,MIME_XSCPLS))
+ pls = new PlayList(PlayList::T_SCPLS, 1000);
+ else if (stristr(arg,MIME_PLS))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_XPLS))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_M3U))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_TEXT))
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (stristr(arg,MIME_ASX))
+ pls = new PlayList(PlayList::T_ASX, 1000);
+ else if (stristr(arg,MIME_MMS))
+ ch->info.srcProtocol = ChanInfo::SP_MMS;
+ }
+ }
+
+ }
+
+ if ((!nextURL.isEmpty()) && (res==302))
+ {
+ LOG_CHANNEL("Channel redirect: %s",nextURL.cstr());
+ inputSocket->close();
+ delete inputSocket;
+ inputSocket = NULL;
+ return nextURL;
+ }
+
+ if (res!=200)
+ {
+ LOG_ERROR("HTTP response: %d",res);
+ throw StreamException("Bad HTTP connect");
+ }
+
+
+ }else if (ch->info.srcProtocol == ChanInfo::SP_FILE)
+ {
+
+ LOG_CHANNEL("Channel source is FILE");
+
+ FileStream *fs = new FileStream();
+ fs->openReadOnly(fileName);
+ inputStream = fs;
+
+ ChanInfo::TYPE fileType = ChanInfo::T_UNKNOWN;
+ // if filetype is unknown, try and figure it out from file extension.
+ //if ((info.srcType == ChanInfo::T_UNKNOWN) || (info.srcType == ChanInfo::T_PLAYLIST))
+ {
+ const char *ext = fileName+strlen(fileName);
+ while (*--ext)
+ if (*ext=='.')
+ {
+ ext++;
+ break;
+ }
+
+ fileType = ChanInfo::getTypeFromStr(ext);
+ }
+
+
+ if (ch->info.bitrate)
+ ch->readDelay = true;
+
+
+ if (fileType == ChanInfo::T_PLS)
+ pls = new PlayList(PlayList::T_PLS, 1000);
+ else if (fileType == ChanInfo::T_ASX)
+ pls = new PlayList(PlayList::T_ASX, 1000);
+ else
+ ch->info.contentType = fileType;
+
+ }else
+ {
+ throw StreamException("Unsupported URL");
+ }
+
+
+ if (pls)
+ {
+
+ LOG_CHANNEL("Channel is Playlist");
+
+ pls->read(*inputStream);
+
+ inputStream->close();
+ delete inputStream;
+ inputStream = NULL;
+
+ int urlNum=0;
+ String url;
+
+ LOG_CHANNEL("Playlist: %d URLs",pls->numURLs);
+ while ((ch->thread.active) && (pls->numURLs) && (!peercastInst->isQuitting))
+ {
+ if (url.isEmpty())
+ {
+ url = pls->urls[urlNum%pls->numURLs];
+ urlNum++;
+ }
+ try
+ {
+ url = streamURL(ch,url.cstr());
+ }catch(StreamException &)
+ {}
+ }
+
+ delete pls;
+
+ }else
+ {
+
+ // if we didn`t get a channel id from the source, then create our own (its an original broadcast)
+ if (!ch->info.id.isSet())
+ {
+ ch->info.id = chanMgr->broadcastID;
+ ch->info.id.encode(NULL,ch->info.name.cstr(),ch->info.genre,ch->info.bitrate);
+ }
+
+ if (ch->info.contentType == ChanInfo::T_ASX)
+ ch->info.contentType = ChanInfo::T_WMV;
+
+ ch->setStatus(Channel::S_BROADCASTING);
+
+ inputStream->setReadTimeout(60); // use longer read timeout
+
+ source = ch->createSource();
+
+ ch->readStream(*inputStream,source);
+
+ inputStream->close();
+ }
+
+ }catch(StreamException &e)
+ {
+ ch->setStatus(Channel::S_ERROR);
+ LOG_ERROR("Channel error: %s",e.msg);
+ sys->sleep(1000);
+ }
+
+
+ ch->setStatus(Channel::S_CLOSING);
+ if (inputStream)
+ {
+ delete inputStream;
+ inputStream = NULL;
+ }
+
+ if (source)
+ delete source;
+
+
+ return nextURL;
+
+}
--- /dev/null
+// ------------------------------------------------
+// File : url.h
+// Date: 20-feb-2004
+// Author: giles
+//
+// (c) 2002-4 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _URL_H
+#define _URL_H
+
+#include "channel.h"
+
+// ------------------------------------------------
+class URLSource : public ChannelSource
+{
+public:
+ URLSource(const char *url)
+ :inputStream(NULL)
+ {
+ baseurl.set(url);
+ }
+
+ ::String streamURL(Channel *, const char *);
+
+ virtual void stream(Channel *);
+
+ virtual int getSourceRate();
+
+
+ Stream *inputStream;
+ ::String baseurl;
+};
+
+
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+#include "identify_encoding.h"
+#ifdef _WIN32
+
+/* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+ int size = 0, index = 0, out_index = 0;
+ unsigned char *out;
+ unsigned short c;
+
+ /* first calculate the size of the target string */
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x0080)
+ {
+ size += 1;
+ }
+ else if (c < 0x0800)
+ {
+ size += 2;
+ }else{
+ size += 3;
+ }
+ c = unicode[index++];
+ }
+
+ out = (unsigned char *)malloc(size + 1);
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = unicode[index++];
+ while (c)
+ {
+ if (c < 0x080)
+ {
+ out[out_index++] = (unsigned char)c;
+ }else if (c < 0x800)
+ {
+ out[out_index++] = 0xc0 | (c >> 6);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }else{
+ out[out_index++] = 0xe0 | (c >> 12);
+ out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ c = unicode[index++];
+ }
+ out[out_index] = 0x00;
+
+ return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+ int size = 0, index = 0, out_index = 0;
+ wchar_t *out;
+ unsigned char c;
+
+ /* first calculate the size of the target string */
+ c = utf8[index++];
+ while (c)
+ {
+ if ((c & 0x80) == 0)
+ {
+ index += 0;
+ }else if((c & 0xe0) == 0xe0)
+ {
+ index += 2;
+ }else{
+ index += 1;
+ }
+ size += 1;
+ c = utf8[index++];
+ }
+
+ out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = utf8[index++];
+ while (c)
+ {
+ if ((c & 0x80) == 0)
+ {
+ out[out_index++] = c;
+ }else if ((c & 0xe0) == 0xe0)
+ {
+ out[out_index] = (c & 0x1F) << 12;
+ c = utf8[index++];
+ out[out_index] |= (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }else{
+ out[out_index] = (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ c = utf8[index++];
+ }
+ out[out_index] = 0;
+
+ return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int wchars, err;
+
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlen(from), NULL, 0);
+
+ if(wchars == 0)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
+ if(unicode == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string to UTF8\n");
+ return -1;
+ }
+
+ err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars);
+ if (err != wchars)
+ {
+ free(unicode);
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ /* On NT-based windows systems, we could use WideCharToMultiByte(), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ *to = (char *)make_utf8_string(unicode);
+
+ free(unicode);
+ return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int chars, err;
+
+ const char *cds;
+ identify_encoding_t *cdt;
+ enum identify_encoding_order order;
+ order = ieo_SJIS;
+ cdt = identify_encoding_open(order);
+ cds = identify_encoding(cdt,(char *)from);
+ if (strcmp(cds,"UTF-8")!=0)
+ {
+ identify_encoding_close(cdt);
+ return -1;
+ }
+ identify_encoding_close(cdt);
+
+
+ /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ unicode = (wchar_t *)make_unicode_string((const unsigned char *)from);
+ if (unicode == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return -1;
+ }
+
+ chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+
+ if (chars == 0)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ return -1;
+ }
+
+ *to = (char *)calloc(chars + 1, sizeof(unsigned char));
+ if (*to == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string to local charset\n");
+ free(unicode);
+ return -1;
+ }
+
+ err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+ if (err != chars)
+ {
+// fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ free(*to);
+ *to = NULL;
+ return -1;
+ }
+
+ free(unicode);
+ return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen);
+
+static char *current_charset = 0; /* means "US-ASCII" */
+
+void convert_set_charset(const char *charset)
+{
+
+ if (!charset)
+ charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+ if (!charset)
+ charset = nl_langinfo(CODESET);
+#endif
+
+ free(current_charset);
+ current_charset = 0;
+ if (charset && *charset)
+ current_charset = strdup(charset);
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = -1;
+
+#ifdef HAVE_ICONV
+ ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+ ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+ return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+ const char *from, char **to, char replace)
+{
+ int ret;
+ size_t fromlen;
+ char *s;
+
+ fromlen = strlen(from);
+ ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+ if (ret == -2)
+ return -1;
+ if (ret != -1)
+ return ret;
+
+ s = malloc(fromlen + 1);
+ if (!s)
+ return -1;
+ strcpy(s, from);
+ *to = s;
+ for (; *s; s++)
+ if (*s & ~0x7f)
+ *s = replace;
+ return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ char *charset;
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string(charset, "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ char *charset;
+
+ if (*from == 0)
+ {
+ *to = malloc(1);
+ **to = 0;
+ return 1;
+ }
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string("UTF-8", charset, from, to, '?');
+}
+
+#endif
--- /dev/null
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ * -1 : memory allocation failed
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ * 3 : unknown encoding (but still converted, using '?')
+ */
+
+#ifndef __UTF8_H
+#define __UTF8_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void convert_set_charset(const char *charset);
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTF8_H */
--- /dev/null
+// ------------------------------------------------
+// File : version2.h
+// Date: 17-june-2005
+// Author: giles
+//
+// (c) 2005 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _VERSION2_H
+#define _VERSION2_H
+
+// ------------------------------------------------
+#ifdef PRIVATE_BROADCASTER
+static const char PCP_BROADCAST_FLAGS = 0x01;
+static bool PCP_FORCE_YP = true;
+#else
+static const char PCP_BROADCAST_FLAGS = 0x00;
+static bool PCP_FORCE_YP = false;
+#endif
+// ------------------------------------------------
+static const int PCP_CLIENT_VERSION = 1217;
+static const int PCP_CLIENT_VERSION_VP = 23;
+static const int PCP_ROOT_VERSION = 1212;
+
+static const int PCP_CLIENT_MINVERSION = 1200;
+
+static const char *PCX_AGENT = "PeerCast/0.1217";
+static const char *PCX_AGENTJP = "PeerCast/0.1217-J";
+static const char *PCX_AGENTVP = "PeerCast/0.1217(VP0023)";
+static const char *PCX_VERSTRING = "v0.1217(VP0023)";
+
+#if 1 /* for VP extend version */
+#define VERSION_EX 1
+static const char *PCP_CLIENT_VERSION_EX_PREFIX = "IM"; // 2bytes only
+static const int PCP_CLIENT_VERSION_EX_NUMBER = 7651;
+static const char *PCX_AGENTEX = "PeerCast/0.1217(IM7651)";
+static const char *PCX_VERSTRING_EX = "v0.1217(IM7651)";
+#endif
+
+// ------------------------------------------------
+
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : xml.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Basic XML parsing/creation
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include "xml.h"
+#include "stream.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ----------------------------------
+void XML::Node::add(Node *n)
+{
+ if (!n)
+ return;
+
+ n->parent = this;
+
+ if (child)
+ {
+ // has children, add to last sibling
+ Node *s = child;
+ while (s->sibling)
+ s = s->sibling;
+ s->sibling = n;
+
+ }else{
+ // no children yet
+ child = n;
+ }
+}
+// ---------------------------------
+inline char nibsToByte(char n1, char n2)
+{
+ if (n1 >= 'A') n1 = n1-'A'+10;
+ else n1 = n1-'0';
+ if (n2 >= 'A') n2 = n2-'A'+10;
+ else n2 = n2-'0';
+
+ return ((n2&0xf)<<4)|(n1&0xf);
+}
+
+// ----------------------------------
+int XML::Node::getBinaryContent(void *ptr, int size)
+{
+ char *in = contData;
+ char *out = (char *)ptr;
+
+ int i=0;
+ while (*in)
+ {
+ if (isWhiteSpace(*in))
+ {
+ in++;
+ }else
+ {
+ if (i >= size)
+ throw StreamException("Too much binary data");
+ out[i++] = nibsToByte(in[0],in[1]);
+ in+=2;
+ }
+ }
+ return i;
+}
+// ----------------------------------
+void XML::Node::setBinaryContent(void *ptr, int size)
+{
+ const char hexTable[] = "0123456789ABCDEF";
+ const int lineWidth = 1023;
+
+ contData = new char[size*2+1+(size/lineWidth)];
+
+ char *bp = (char *)ptr;
+ register char *ap = contData;
+
+ for(register int i=0; i<size; i++)
+ {
+ register char c = bp[i];
+ *ap++ = hexTable[c&0xf];
+ *ap++ = hexTable[(c>>4)&0xf];
+ if ((i&lineWidth)==lineWidth)
+ *ap++ = '\n';
+ }
+ ap[0] = 0;
+}
+
+
+// ----------------------------------
+void XML::Node::setContent(const char *n)
+{
+ contData = strdup(n);
+}
+// ----------------------------------
+void XML::Node::setAttributes(const char *n)
+{
+ char c;
+
+ attrData = strdup(n);
+
+ // count maximum amount of attributes
+ int maxAttr = 1; // 1 for tag name
+ bool inQ = false;
+ int i=0;
+ while ((c=attrData[i++])!=0)
+ {
+ if (c=='\"')
+ inQ ^= true;
+
+ if (!inQ)
+ if (c=='=')
+ maxAttr++;
+ }
+
+
+ attr = new Attribute[maxAttr];
+
+ attr[0].namePos = 0;
+ attr[0].valuePos = 0;
+
+ numAttr=1;
+
+ i=0;
+
+ // skip until whitespace
+ while (c=attrData[i++])
+ if (isWhiteSpace(c))
+ break;
+
+ if (!c) return; // no values
+
+ attrData[i-1]=0;
+
+
+ while ((c=attrData[i])!=0)
+ {
+ if (!isWhiteSpace(c))
+ {
+ if (numAttr>=maxAttr)
+ throw StreamException("Too many attributes");
+
+ // get start of tag name
+ attr[numAttr].namePos = i;
+
+
+ // skip whitespaces until next '='
+ // terminate name on next whitespace or '='
+ while (attrData[i])
+ {
+ c = attrData[i++];
+
+ if ((c == '=') || isWhiteSpace(c))
+ {
+ attrData[i-1] = 0; // null term. name
+ if (c == '=')
+ break;
+ }
+ }
+
+ // skip whitespaces
+ while (attrData[i])
+ {
+ if (isWhiteSpace(attrData[i]))
+ i++;
+ else
+ break;
+ }
+
+ // check for valid start of attribute value - '"'
+ if (attrData[i++] != '\"')
+ throw StreamException("Bad tag value");
+
+ attr[numAttr++].valuePos = i;
+
+ // terminate attribute value at next '"'
+
+ while (attrData[i])
+ if (attrData[i++] == '\"')
+ break;
+
+ attrData[i-1] = 0; // null term. value
+
+
+ }else{
+ i++;
+ }
+ }
+}
+// ----------------------------------
+XML::Node::Node(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ char tmp[8192];
+ vsprintf(tmp,fmt,ap);
+ setAttributes(tmp);
+
+ va_end(ap);
+ init();
+}
+
+// ----------------------------------
+void XML::Node::init()
+{
+ parent = sibling = child = NULL;
+ contData = NULL;
+ userPtr = NULL;
+}
+// ----------------------------------
+int XML::Node::findAttrInt(const char *name)
+{
+ char *v = findAttr(name);
+ if (!v) return 0;
+ return atoi(v);
+}
+// ----------------------------------
+int XML::Node::findAttrID(const char *name)
+{
+ char *v = findAttr(name);
+ if (!v) return 0;
+ return strToID(v);
+}
+// ----------------------------------
+char *XML::Node::findAttr(const char *name)
+{
+ int nlen = strlen(name);
+ for(int i=1; i<numAttr; i++)
+ {
+ char *an = getAttrName(i);
+ if (strnicmp(an,name,nlen)==0)
+ return getAttrValue(i);
+ }
+ return NULL;
+}
+// ----------------------------------
+void XML::Node::write(Stream &out, int level)
+{
+ int i;
+#if 0
+ char tabs[64];
+
+ for(i=0; i<level; i++)
+ tabs[i] = ' ';
+ tabs[i] = '\0';
+
+
+ if (level)
+ out.write(tabs,i);
+#endif
+ char *name = getAttrValue(0);
+
+ out.write("<",1);
+ out.write(name,strlen(name));
+
+ for(i=1; i<numAttr; i++)
+ {
+ out.write(" ",1);
+ char *at = getAttrName(i);
+ out.write(at,strlen(at));
+
+ out.write("=\"",2);
+ char *av = getAttrValue(i);
+ out.write(av,strlen(av));
+ out.write("\"",1);
+ }
+
+ if ((!contData) && (!child))
+ {
+ out.write("/>\n",3);
+ }else
+ {
+ out.write(">\n",2);
+
+ if (contData)
+ out.write(contData,strlen(contData));
+
+ if (child)
+ child->write(out,level+1);
+#if 0
+ if (level)
+ out.write(tabs,strlen(tabs));
+#endif
+ out.write("</",2);
+ out.write(name,strlen(name));
+ out.write(">\n",2);
+ }
+
+ if (sibling)
+ sibling->write(out,level);
+}
+// ----------------------------------
+XML::Node::~Node()
+{
+// LOG("delete %s",getName());
+
+ if (contData)
+ delete [] contData;
+ if (attrData)
+ delete [] attrData;
+ if (attr)
+ delete [] attr;
+
+ Node *n = child;
+ while (n)
+ {
+ Node *nn = n->sibling;
+ delete n;
+ n = nn;
+ }
+}
+
+
+// ----------------------------------
+XML::~XML()
+{
+ if (root)
+ delete root;
+}
+
+// ----------------------------------
+void XML::write(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ out.writeLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
+ root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeCompact(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ out.writeLine("<?xml ?>");
+ root->write(out,1);
+
+}
+// ----------------------------------
+void XML::writeHTML(Stream &out)
+{
+ if (!root)
+ throw StreamException("No XML root");
+
+ root->write(out,1);
+}
+
+// ----------------------------------
+void XML::setRoot(Node *n)
+{
+ root=n;
+}
+
+
+// ----------------------------------
+XML::Node *XML::findNode(const char *n)
+{
+ if (root)
+ return root->findNode(n);
+ else
+ return NULL;
+}
+
+
+// ----------------------------------
+XML::Node *XML::Node::findNode(const char *name)
+{
+ if (stricmp(getName(),name)==0)
+ return this;
+
+ XML::Node *c = child;
+
+ while (c)
+ {
+ XML::Node *fn = c->findNode(name);
+ if (fn)
+ return fn;
+ c=c->sibling;
+ }
+
+ return NULL;
+}
+
+// ----------------------------------
+void XML::read(Stream &in)
+{
+ const int BUFFER_LEN = 100*1024;
+ static char buf[BUFFER_LEN];
+
+ Node *currNode=NULL;
+ int tp=0;
+
+ while (!in.eof())
+ {
+ char c = in.readChar();
+
+ if (c == '<')
+ {
+ if (tp && currNode) // check for content
+ {
+ buf[tp] = 0;
+ currNode->setContent(buf);
+ }
+ tp = 0;
+
+ // read to next '>'
+ while (!in.eof())
+ {
+ c = in.readChar();
+ if (c == '>')
+ break;
+
+ if (tp >= BUFFER_LEN)
+ throw StreamException("Tag too long");
+
+ buf[tp++] = c;
+ }
+ buf[tp]=0;
+
+ if (buf[0] == '!') // comment
+ {
+ // do nothing
+ }else if (buf[0] == '?') // doc type
+ {
+ if (strnicmp(&buf[1],"xml ",4))
+ throw StreamException("Not XML document");
+ }else if (buf[0] == '/') // end tag
+ {
+ if (!currNode)
+ throw StreamException("Unexpected end tag");
+ currNode = currNode->parent;
+ }else // new tag
+ {
+ //LOG("tag: %s",buf);
+
+ bool singleTag = false;
+
+ if (buf[tp-1] == '/') // check for single tag
+ {
+ singleTag = true;
+ buf[tp-1] = 0;
+ }
+
+ // only add valid tags
+ if (strlen(buf))
+ {
+ Node *n = new Node(buf);
+
+ if (currNode)
+ currNode->add(n);
+ else
+ setRoot(n);
+
+ if (!singleTag)
+ currNode = n;
+ }
+ }
+
+ tp = 0;
+ } else {
+
+ if (tp >= BUFFER_LEN)
+ throw StreamException("Content too big");
+
+ buf[tp++] = c;
+
+ }
+ }
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : xml.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _XML_H
+#define _XML_H
+
+//-----------------------
+#include "common.h"
+#include <stdarg.h>
+
+//-----------------------
+class Stream;
+
+//-----------------------
+class XML
+{
+public:
+ class Node
+ {
+ public:
+ class Attribute
+ {
+ public:
+ int namePos,valuePos;
+ };
+
+ Node(const char *,...);
+
+ void init();
+
+ ~Node();
+
+ void add(Node *);
+ void write(Stream &,int); // output, level
+ char *getName() {return getAttrName(0);}
+
+ char *getAttrValue(int i) {return &attrData[attr[i].valuePos];}
+ char *getAttrName(int i) {return &attrData[attr[i].namePos];}
+ char *getContent() {return contData; }
+ int getBinaryContent(void *, int);
+
+ void setAttributes(const char *);
+ void setContent(const char *);
+ void setBinaryContent(void *, int);
+
+ Node *findNode(const char *);
+ char *findAttr(const char *);
+ int findAttrInt(const char *);
+ int findAttrID(const char *);
+
+ char *contData,*attrData;
+
+ Attribute *attr;
+ int numAttr;
+
+ Node *child,*parent,*sibling;
+ void *userPtr;
+ };
+
+ XML()
+ {
+ root = NULL;
+ }
+
+ ~XML();
+
+ void setRoot(Node *n);
+ void write(Stream &);
+ void writeCompact(Stream &);
+ void writeHTML(Stream &);
+ void read(Stream &);
+ Node *findNode(const char *n);
+
+ Node *root;
+};
+#endif
--- /dev/null
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="corelib"
+ ProjectGUID="{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+ RootNamespace="corelib"
+ SccProjectName=""$/PeerCast.root/PeerCast", JCAAAAAA"
+ SccLocalPath="..\..\.."
+ SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Private Release|Win32"
+ OutputDirectory=".\corelib___Win32_Private_Release"
+ IntermediateDirectory=".\corelib___Win32_Private_Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PRIVATE_BROADCASTER"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\corelib___Win32_Private_Release/corelib.pch"
+ AssemblerListingLocation=".\corelib___Win32_Private_Release/"
+ ObjectFile=".\corelib___Win32_Private_Release/"
+ ProgramDataBaseFileName=".\corelib___Win32_Private_Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\corelib___Win32_Private_Release\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\corelib___Win32_Private_Release/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../,../../common,../../../ui/win32/simple"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Debug/corelib.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Debug\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/corelib.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Release\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Private Debug|Win32"
+ OutputDirectory=".\corelib___Win32_Private_Debug"
+ IntermediateDirectory=".\corelib___Win32_Private_Debug"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../,../../common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PRIVATE_BROADCASTER"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\corelib___Win32_Private_Debug/corelib.pch"
+ AssemblerListingLocation=".\corelib___Win32_Private_Debug/"
+ ObjectFile=".\corelib___Win32_Private_Debug/"
+ ProgramDataBaseFileName=".\corelib___Win32_Private_Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\corelib___Win32_Private_Debug\corelib.lib"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\corelib___Win32_Private_Debug/corelib.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Core Source"
+ >
+ <File
+ RelativePath="..\..\common\channel.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\gnutella.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\html.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\http.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\icy.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\inifile.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\jis.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\mms.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\mp3.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\nsv.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\ogg.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\pcp.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\peercast.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\rtsp.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servent.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servhs.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\servmgr.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\socket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\stats.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\stream.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\sys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\url.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\xml.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Core Includes"
+ >
+ <File
+ RelativePath="..\..\common\asf.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\atom.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\channel.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\common.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\cstream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\gnutella.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\html-xml.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\html.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\http.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\icy.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\id.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\inifile.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\jis.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\mms.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\mp3.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\nsv.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\ogg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\pcp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\peercast.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\rtsp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\servent.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\servmgr.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\socket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\stats.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\stream.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\sys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\url.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\version2.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\xml.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Win32 Source"
+ >
+ <File
+ RelativePath="..\wsocket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\wsys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Win32 Includes"
+ >
+ <File
+ RelativePath="..\wsocket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\wsys.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Unix Source"
+ >
+ <File
+ RelativePath="..\..\unix\usocket.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\unix\usys.cpp"
+ >
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Unix Includes"
+ >
+ <File
+ RelativePath="..\..\unix\usocket.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\unix\usys.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:core\\win32\\lib"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// ------------------------------------------------
+// File : wsocket.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Windows version of ClientSocket. Handles the nitty gritty of actually
+// reading and writing TCP
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+// TODO: fix socket closing
+
+
+//#include "stdafx.h"
+//#include "winsock2.h"
+#include <windows.h>
+#include <stdio.h>
+#include "wsocket.h"
+#include "stats.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+
+// --------------------------------------------------
+void WSAClientSocket::init()
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 2, 0 );
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 )
+ throw SockException("Unable to init sockets");
+
+ //LOG4("WSAStartup: OK");
+
+}
+// --------------------------------------------------
+bool ClientSocket::getHostname(char *str,unsigned int ip)
+{
+ HOSTENT *he;
+
+ ip = htonl(ip);
+
+ he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+ if (he)
+ {
+ strcpy(str,he->h_name);
+ return true;
+ }else
+ return false;
+}
+
+unsigned int cache_ip = 0;
+unsigned int cache_time = 0;
+
+// --------------------------------------------------
+unsigned int ClientSocket::getIP(char *name)
+{
+ unsigned int ctime = sys->getTime();
+ bool null_flg = (name == NULL);
+
+ if (null_flg){
+ if ((cache_time != 0) && (cache_time + 60 > ctime)){
+ return cache_ip;
+ } else {
+ cache_time = 0;
+ cache_ip = 0;
+ }
+ }
+
+ char szHostName[256];
+
+ if (!name)
+ {
+ if (gethostname(szHostName, sizeof(szHostName))==0)
+ name = szHostName;
+ else
+ return 0;
+ }
+
+ HOSTENT *he = WSAClientSocket::resolveHost(name);
+
+ if (!he)
+ return 0;
+
+
+ LPSTR lpAddr = he->h_addr_list[0];
+ if (lpAddr)
+ {
+ unsigned int ret;
+ struct in_addr inAddr;
+ memmove (&inAddr, lpAddr, 4);
+
+ ret = inAddr.S_un.S_un_b.s_b1<<24 |
+ inAddr.S_un.S_un_b.s_b2<<16 |
+ inAddr.S_un.S_un_b.s_b3<<8 |
+ inAddr.S_un.S_un_b.s_b4;
+
+ if (null_flg){
+ cache_ip = ret;
+ cache_time = ctime;
+ }
+ return ret;
+ }
+ return 0;
+}
+// --------------------------------------------------
+void WSAClientSocket::setLinger(int sec)
+{
+ linger linger;
+ linger.l_onoff = (sec>0)?1:0;
+ linger.l_linger = sec;
+
+ if (setsockopt(sockNum, SOL_SOCKET, SO_LINGER, (const char *)&linger, sizeof (linger)) == -1)
+ throw SockException("Unable to set LINGER");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBlocking(bool yes)
+{
+ unsigned long op = yes ? 0 : 1;
+ if (ioctlsocket(sockNum, FIONBIO, &op) == SOCKET_ERROR)
+ throw SockException("Can`t set blocking");
+}
+// --------------------------------------------------
+void WSAClientSocket::setNagle(bool on)
+{
+ int nodelay = (on==false);
+ if (setsockopt(sockNum, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay, sizeof nodelay) == -1)
+ throw SockException("Unable to set NODELAY");
+
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setReuse(bool yes)
+{
+ unsigned long op = yes ? 1 : 0;
+ if (setsockopt(sockNum,SOL_SOCKET,SO_REUSEADDR,(char *)&op,sizeof(unsigned long)) == -1)
+ throw SockException("Unable to set REUSE");
+}
+
+// --------------------------------------------------
+void WSAClientSocket::setBufSize(int size)
+{
+ int oldop;
+ int op = size;
+ int len = sizeof(op);
+ if (getsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&oldop,&len) == -1) {
+ LOG_DEBUG("Unable to get RCVBUF");
+ } else if (oldop < size) {
+ if (setsockopt(sockNum,SOL_SOCKET,SO_RCVBUF,(char *)&op,len) == -1)
+ LOG_DEBUG("Unable to set RCVBUF");
+ //else
+ // LOG_DEBUG("*** recvbufsize:%d -> %d", oldop, op);
+ }
+
+ if (getsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&oldop,&len) == -1) {
+ LOG_DEBUG("Unable to get SNDBUF");
+ } else if (oldop < size) {
+ if (setsockopt(sockNum,SOL_SOCKET,SO_SNDBUF,(char *)&op,len) == -1)
+ LOG_DEBUG("Unable to set SNDBUF");
+ //else
+ // LOG_DEBUG("*** sendbufsize: %d -> %d", oldop, op);
+ }
+}
+
+// --------------------------------------------------
+HOSTENT *WSAClientSocket::resolveHost(const char *hostName)
+{
+ HOSTENT *he;
+
+ if ((he = gethostbyname(hostName)) == NULL)
+ {
+ // if failed, try using gethostbyaddr instead
+
+ unsigned long ip = inet_addr(hostName);
+
+ if (ip == INADDR_NONE)
+ return NULL;
+
+ if ((he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET)) == NULL)
+ return NULL;
+ }
+ return he;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::open(Host &rh)
+{
+ sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sockNum == INVALID_SOCKET)
+ throw SockException("Can`t open socket");
+
+ setBlocking(false);
+#ifdef DISABLE_NAGLE
+ setNagle(false);
+#endif
+ setBufSize(65535);
+
+ host = rh;
+
+ memset(&remoteAddr,0,sizeof(remoteAddr));
+
+ remoteAddr.sin_family = AF_INET;
+ remoteAddr.sin_port = htons(host.port);
+ remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip);
+
+}
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout(bool r, bool w)
+{
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK)
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+
+ }else{
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkTimeout2(bool r, bool w)
+{
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+ }
+}
+
+// --------------------------------------------------
+Host WSAClientSocket::getLocalHost()
+{
+ struct sockaddr_in localAddr;
+
+ int len = sizeof(localAddr);
+ if (getsockname(sockNum, (sockaddr *)&localAddr, &len) == 0)
+ return Host(SWAP4(localAddr.sin_addr.s_addr),0);
+ else
+ return Host(0,0);
+}
+
+// --------------------------------------------------
+void WSAClientSocket::connect()
+{
+ if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR)
+ checkTimeout(false,true);
+
+}
+// --------------------------------------------------
+int WSAClientSocket::read(void *p, int l)
+{
+ int bytesRead=0;
+
+ while (l)
+ {
+ if (rbDataSize >= l) {
+ memcpy(p, &apReadBuf[rbPos], l);
+ rbPos += l;
+ rbDataSize -= l;
+ return l;
+ } else if (rbDataSize > 0) {
+ memcpy(p, &apReadBuf[rbPos], rbDataSize);
+ p = (char *) p + rbDataSize;
+ l -= rbDataSize;
+ bytesRead += rbDataSize;
+ }
+
+ rbPos = 0;
+ rbDataSize = 0;
+ //int r = recv(sockNum, (char *)p, l, 0);
+ int r = recv(sockNum, apReadBuf, RBSIZE, 0);
+ if (r == SOCKET_ERROR)
+ {
+ // non-blocking sockets always fall through to here
+ checkTimeout(true,false);
+
+ }else if (r == 0)
+ {
+ throw EOFException("Closed on read");
+
+ }else
+ {
+ stats.add(Stats::BYTESIN,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESIN,r);
+ updateTotals(r,0);
+ //bytesRead += r;
+ //l -= r;
+ //p = (char *)p+r;
+
+ rbDataSize += r;
+ }
+ }
+ return bytesRead;
+}
+// --------------------------------------------------
+int WSAClientSocket::readUpto(void *p, int l)
+{
+ int bytesRead=0;
+ while (l)
+ {
+ int r = recv(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR)
+ {
+ // non-blocking sockets always fall through to here
+ //checkTimeout(true,false);
+ return r;
+
+ }else if (r == 0)
+ {
+ break;
+ }else
+ {
+ stats.add(Stats::BYTESIN,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESIN,r);
+ updateTotals(r,0);
+ bytesRead += r;
+ l -= r;
+ p = (char *)p+r;
+ }
+ if (bytesRead) break;
+ }
+ return bytesRead;
+}
+
+
+// --------------------------------------------------
+void WSAClientSocket::write(const void *p, int l)
+{
+ while (l)
+ {
+ int r = send(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR)
+ {
+ checkTimeout(false,true);
+ }
+ else if (r == 0)
+ {
+ throw SockException("Closed on write");
+ }
+ else
+ if (r > 0)
+ {
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+ l -= r;
+ p = (char *)p+r;
+ }
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bufferingWrite(const void *p, int l)
+{
+ if (bufList.isNull() && p != NULL){
+ while(l){
+ int r = send(sockNum, (char *)p, l, 0);
+ if (r == SOCKET_ERROR){
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK){
+ bufList.add(p, l);
+// LOG_DEBUG("normal add");
+ break;
+ } else {
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+ } else if (r == 0) {
+ throw SockException("Closed on write");
+ } else if (r > 0){
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+ l -= r;
+ p = (char *)p+r;
+ }
+ }
+ } else {
+// LOG_DEBUG("***************BufferingWrite");
+ if (p)
+ bufList.add(p,l);
+
+ bool flg = true;
+
+ while(flg){
+ SocketBuffer *tmp;
+ tmp = bufList.getTop();
+
+ if (tmp){
+// LOG_DEBUG("tmp->pos = %d, tmp->len = %d, %d", tmp->pos, tmp->len, tmp);
+ while(tmp->pos < tmp->len){
+ int r = send(sockNum, (char*)(tmp->buf + tmp->pos), tmp->len - tmp->pos, 0);
+// LOG_DEBUG("send = %d", r);
+ if (r == SOCKET_ERROR){
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK){
+ flg = false;
+ break;
+ } else {
+ bufList.clear();
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+ } else if (r == 0){
+ bufList.clear();
+ throw SockException("Closed on write");
+ } else if (r > 0){
+ stats.add(Stats::BYTESOUT,r);
+ if (host.localIP())
+ stats.add(Stats::LOCALBYTESOUT,r);
+
+ updateTotals(0,r);
+
+ tmp->pos += r;
+ if (tmp->pos >= tmp->len){
+// LOG_DEBUG("deleteTop");
+ bufList.deleteTop();
+ break;
+ }
+ }
+ }
+ } else {
+ flg = false;
+ }
+ }
+// LOG_DEBUG("bufferingWrite end");
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::checkBuffering(bool r, bool w)
+{
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK)
+ {
+
+ timeval timeout;
+ fd_set read_fds;
+ fd_set write_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&write_fds);
+ if (w)
+ {
+ timeout.tv_sec = (int)this->writeTimeout/1000;
+ FD_SET (sockNum, &write_fds);
+ }
+
+ FD_ZERO (&read_fds);
+ if (r)
+ {
+ timeout.tv_sec = (int)this->readTimeout/1000;
+ FD_SET (sockNum, &read_fds);
+ }
+
+ timeval *tp;
+ if (timeout.tv_sec)
+ tp = &timeout;
+ else
+ tp = NULL;
+
+
+ int r=select (NULL, &read_fds, &write_fds, NULL, tp);
+
+ if (r == 0)
+ throw TimeoutException();
+ else if (r == SOCKET_ERROR)
+ throw SockException("select failed.");
+
+ }else{
+ char str[32];
+ sprintf(str,"%d",err);
+ throw SockException(str);
+ }
+}
+
+// --------------------------------------------------
+void WSAClientSocket::bind(Host &h)
+{
+ struct sockaddr_in localAddr;
+
+ if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ throw SockException("Can`t open socket");
+
+ setBlocking(false);
+ setReuse(true);
+
+ memset(&localAddr,0,sizeof(localAddr));
+ localAddr.sin_family = AF_INET;
+ localAddr.sin_port = htons(h.port);
+ localAddr.sin_addr.s_addr = INADDR_ANY;
+
+ if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1)
+ throw SockException("Can`t bind socket");
+
+ if (::listen(sockNum,SOMAXCONN))
+ throw SockException("Can`t listen",WSAGetLastError());
+
+ host = h;
+}
+// --------------------------------------------------
+ClientSocket *WSAClientSocket::accept()
+{
+
+ int fromSize = sizeof(sockaddr_in);
+ sockaddr_in from;
+
+ int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize);
+
+
+ if (conSock == INVALID_SOCKET)
+ return NULL;
+
+
+ WSAClientSocket *cs = new WSAClientSocket();
+ cs->sockNum = conSock;
+
+ cs->host.port = from.sin_port;
+ cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |
+ from.sin_addr.S_un.S_un_b.s_b2<<16 |
+ from.sin_addr.S_un.S_un_b.s_b3<<8 |
+ from.sin_addr.S_un.S_un_b.s_b4;
+
+
+ cs->setBlocking(false);
+#ifdef DISABLE_NAGLE
+ cs->setNagle(false);
+#endif
+ cs->setBufSize(65535);
+
+ return cs;
+}
+
+// --------------------------------------------------
+void WSAClientSocket::close()
+{
+ sockLock.on();
+ if (sockNum)
+ {
+// shutdown(sockNum,SD_SEND);
+
+ setReadTimeout(2000);
+ unsigned int stime = sys->getTime();
+ try
+ {
+ char c[1024];
+ while (readUpto(&c,1024) > 0)
+ if (sys->getTime() - stime > 5) break;
+ //readUpto(&c,1);
+ }catch(StreamException &) {}
+
+ if (closesocket (sockNum))
+ LOG_ERROR("closesocket() error");
+
+
+ sockNum=0;
+ }
+ sockLock.off();
+}
+
+// --------------------------------------------------
+bool WSAClientSocket::readReady()
+{
+ if (rbDataSize) return true;
+
+ timeval timeout;
+ fd_set read_fds;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ FD_ZERO (&read_fds);
+ FD_SET (sockNum, &read_fds);
+
+ return select (sockNum+1, &read_fds, NULL, NULL, &timeout) == 1;
+}
+
--- /dev/null
+// ------------------------------------------------
+// File : wsocket.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// see .cpp for details
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _WSOCKET_H
+#define _WSOCKET_H
+
+#include <windows.h>
+#include "socket.h"
+//#include "winsock2.h"
+
+
+// --------------------------------------------------
+class WSAClientSocket : public ClientSocket
+{
+public:
+ static void init();
+
+ WSAClientSocket()
+ :sockNum(0)
+ ,writeCnt(0)
+ ,rbPos(0)
+ ,rbDataSize(0)
+ {
+ }
+
+ ~WSAClientSocket(){
+ bufList.clear();
+ }
+
+ virtual void open(Host &);
+ virtual int read(void *, int);
+ virtual int readUpto(void *, int);
+ virtual void write(const void *, int);
+ virtual void bind(Host &);
+ virtual void connect();
+ virtual void close();
+ virtual ClientSocket * accept();
+ virtual bool active() {return sockNum != 0;}
+ virtual bool readReady();
+ virtual Host getLocalHost();
+ virtual void setBlocking(bool);
+ void setReuse(bool);
+ void setNagle(bool);
+ void setLinger(int);
+ void setBufSize(int size);
+
+// static HOSTENT *resolveHost(const char *);
+ static hostent *resolveHost(const char *);
+
+ void checkTimeout(bool,bool);
+ void checkTimeout2(bool,bool);
+
+ virtual void bufferingWrite(const void*, int);
+ void checkBuffering(bool, bool);
+
+ unsigned int writeCnt;
+ unsigned int sockNum;
+ struct sockaddr_in remoteAddr;
+
+ enum {RBSIZE = 8192};
+ char apReadBuf[RBSIZE];
+ int rbPos;
+ int rbDataSize;
+
+ WLock sockLock;
+};
+
+#endif
+
\ No newline at end of file
--- /dev/null
+// ------------------------------------------------
+// File : wsys.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+//#include "stdafx.h"
+#include <process.h>
+#include <windows.h>
+#include <time.h>
+#include "win32/wsys.h"
+#include "win32/wsocket.h"
+#include "stats.h"
+#include "peercast.h"
+#include <sys/timeb.h>
+#include <time.h>
+#include "shellapi.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+// ---------------------------------
+WSys::WSys(HWND w)
+{
+ stats.clear();
+
+ rndGen.setSeed(getTime());
+
+ mainWindow = w;
+ WSAClientSocket::init();
+
+ rndSeed = rnd();
+}
+// ---------------------------------
+double WSys::getDTime()
+{
+ struct _timeb timebuffer;
+
+ _ftime( &timebuffer );
+
+ return (double)timebuffer.time+(((double)timebuffer.millitm)/1000);
+}
+// ---------------------------------
+unsigned int WSys::getTime()
+{
+ time_t ltime;
+ time( <ime );
+ return ltime;
+}
+
+// ---------------------------------
+ClientSocket *WSys::createSocket()
+{
+ return new WSAClientSocket();
+}
+// ---------------------------------
+void WSys::endThread(ThreadInfo *info)
+{
+}
+// ---------------------------------
+void WSys::waitThread(ThreadInfo *info, int timeout)
+{
+ switch(WaitForSingleObject((void *)info->handle, timeout))
+ {
+ case WAIT_TIMEOUT:
+ throw TimeoutException();
+ break;
+ }
+}
+
+
+// ---------------------------------
+bool WSys::startThread(ThreadInfo *info)
+{
+ info->active = true;
+
+/* typedef unsigned ( __stdcall *start_address )( void * );
+
+ unsigned int threadID;
+ info->handle = (unsigned int)_beginthreadex( NULL, 0, (start_address)info->func, info, 0, &threadID );
+
+ if(info->handle == 0)
+ return false;*/
+
+ typedef void (__cdecl *start_address)( void * );
+ info->handle = _beginthread((start_address)info->func, 0,info);
+
+ if(info->handle == -1)
+ return false;
+
+ return true;
+
+}
+// ---------------------------------
+void WSys::sleep(int ms)
+{
+ Sleep(ms);
+}
+
+// ---------------------------------
+void WSys::appMsg(long msg, long arg)
+{
+ //SendMessage(mainWindow,WM_USER,(WPARAM)msg,(LPARAM)arg);
+}
+
+// --------------------------------------------------
+void WSys::callLocalURL(const char *str,int port)
+{
+ char cmd[512];
+ sprintf(cmd,"http://localhost:%d/%s",port,str);
+ ShellExecute(mainWindow, NULL, cmd, NULL, NULL, SW_SHOWNORMAL);
+}
+
+// ---------------------------------
+void WSys::getURL(const char *url)
+{
+ if (mainWindow)
+ if (strnicmp(url,"http://",7) || strnicmp(url,"mailto:",7))
+ ShellExecute(mainWindow, NULL, url, NULL, NULL, SW_SHOWNORMAL);
+}
+// ---------------------------------
+void WSys::exit()
+{
+ if (mainWindow)
+ PostMessage(mainWindow,WM_CLOSE,0,0);
+ else
+ ::exit(0);
+}
+// --------------------------------------------------
+void WSys::executeFile(const char *file)
+{
+ ShellExecute(NULL,"open",file,NULL,NULL,SW_SHOWNORMAL);
+}
--- /dev/null
+// ------------------------------------------------
+// File : wsys.h
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// WSys derives from Sys to provide basic win32 functions such as starting threads.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+
+
+#ifndef _WSYS_H
+#define _WSYS_H
+// ------------------------------------
+#include <windows.h>
+#include "socket.h"
+#include "sys.h"
+
+// ------------------------------------
+class WSys : public Sys
+{
+public:
+ WSys(HWND);
+
+ virtual ClientSocket *createSocket();
+ virtual bool startThread(ThreadInfo *);
+ virtual void sleep(int );
+ virtual void appMsg(long,long);
+ virtual unsigned int getTime();
+ virtual double getDTime();
+ virtual unsigned int rnd() {return rndGen.next();}
+ virtual void getURL(const char *);
+ virtual void exit();
+ virtual bool hasGUI() {return mainWindow!=NULL;}
+ virtual void callLocalURL(const char *str,int port);
+ virtual void executeFile(const char *);
+ virtual void endThread(ThreadInfo *);
+ virtual void waitThread(ThreadInfo *, int timeout = 30000);
+
+
+ HWND mainWindow;
+ peercast::Random rndGen;
+};
+
+
+// ------------------------------------
+#endif
+
+
+
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "corelib", "..\..\core\win32\lib\corelib.vcproj", "{7BCFE65B-8757-45F3-8DFB-1E7D683950D1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple", "simple\Simple.vcproj", "{7D4833CE-1286-4587-9470-52E098B29C12}"
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 3
+ SccProjectName0 = \u0022$/PeerCast.root/PeerCast\u0022,\u0020JCAAAAAA
+ SccLocalPath0 = ..\\..
+ SccProvider0 = MSSCCI:Microsoft\u0020Visual\u0020SourceSafe
+ SccProjectFilePathRelativizedFromConnection0 = ui\\win32\\
+ SccProjectUniqueName1 = ..\\..\\core\\win32\\lib\\corelib.vcproj
+ SccLocalPath1 = ..\\..
+ SccProjectFilePathRelativizedFromConnection1 = core\\win32\\lib\\
+ SccProjectUniqueName2 = simple\\Simple.vcproj
+ SccLocalPath2 = ..\\..
+ SccProjectFilePathRelativizedFromConnection2 = ui\\win32\\simple\\
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Private Debug|Win32 = Private Debug|Win32
+ Private Release|Win32 = Private Release|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Debug|Win32.Build.0 = Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Debug|Win32.Build.0 = Private Debug|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.ActiveCfg = Private Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Private Release|Win32.Build.0 = Private Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.ActiveCfg = Release|Win32
+ {7BCFE65B-8757-45F3-8DFB-1E7D683950D1}.Release|Win32.Build.0 = Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Debug|Win32.Build.0 = Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.ActiveCfg = Private Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Debug|Win32.Build.0 = Private Debug|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.ActiveCfg = Private Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Private Release|Win32.Build.0 = Private Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.ActiveCfg = Release|Win32
+ {7D4833CE-1286-4587-9470-52E098B29C12}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// ------------------------------------------------
+// File : simple.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Simple tray icon interface to PeerCast, mostly win32 related stuff.
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#include <windows.h>
+#include <direct.h>
+#include "stdafx.h"
+#include "resource.h"
+#include "gui.h"
+#include "channel.h"
+#include "servent.h"
+#include "servmgr.h"
+#include "win32/wsys.h"
+#include "peercast.h"
+#include "simple.h"
+#include "version2.h"
+#include "gdiplus.h"
+#include "time.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+#define MAX_LOADSTRING 100
+
+#define PLAY_CMD 7000
+#define RELAY_CMD 8000
+#define INFO_CMD 9000
+#define URL_CMD 10000
+
+#define MAX_CHANNELS 999
+
+
+extern "C"
+{
+ void loadIcons(HINSTANCE hInstance, HWND hWnd);
+};
+
+UINT g_iTaskbarCreated = ~0; // for PCRaw (tray icon)
+
+// PeerCast globals
+
+static int currNotify=0;
+String iniFileName;
+HWND guiWnd;
+HWND mainWnd;
+static HMENU trayMenu = NULL,ltrayMenu = NULL; // for PCRaw (tray icon)
+bool showGUI=true;
+bool allowMulti=false;
+bool killMe=false;
+bool allowTrayMenu=true;
+static bool winDistinctionNT=false;
+int seenNewVersionTime=0;
+HICON icon1,icon2;
+ChanInfo chanInfo;
+bool chanInfoIsRelayed;
+//GnuID lastPlayID;
+String exePath;
+ULONG_PTR gdiplusToken;
+
+// ---------------------------------
+Sys * APICALL MyPeercastInst::createSys()
+{
+ return new WSys(mainWnd);
+}
+// ---------------------------------
+const char * APICALL MyPeercastApp ::getIniFilename()
+{
+ return iniFileName.cstr();
+}
+
+// ---------------------------------
+const char *APICALL MyPeercastApp ::getClientTypeOS()
+{
+ return PCX_OS_WIN32;
+}
+
+// ---------------------------------
+const char * APICALL MyPeercastApp::getPath()
+{
+ return exePath.cstr();
+}
+
+// --------------------------------- JP-EX
+void APICALL MyPeercastApp ::openLogFile()
+{
+ logFile.openWriteReplace("log.txt");
+}
+// --------------------------------- JP-EX
+void APICALL MyPeercastApp ::getDirectory()
+{
+ char path_buffer[256],drive[32],dir[128];
+ GetModuleFileName(NULL,path_buffer,255);
+ _splitpath(path_buffer,drive,dir,NULL,NULL);
+ sprintf(servMgr->modulePath,"%s%s",drive,dir);
+}
+// --------------------------------- JP-EX
+bool APICALL MyPeercastApp ::clearTemp()
+{
+ if (servMgr->clearPLS)
+ return true;
+
+ return false;
+}
+
+
+class NOTIFYICONDATA2
+{
+public:
+ DWORD cbSize; // DWORD
+ HWND hWnd; // HWND
+ UINT uID; // UINT
+ UINT uFlags; // UINT
+ UINT uCallbackMessage; // UINT
+ HICON hIcon; // HICON
+ char szTip[128]; // char[128]
+ DWORD dwState; // DWORD
+ DWORD dwStateMask; // DWORD
+ char szInfo[256]; // char[256]
+ UINT uTimeoutOrVersion; // UINT
+ char szInfoTitle[64]; // char[64]
+ DWORD dwInfoFlags; // DWORD
+ //GUID guidItem; > IE 6
+};
+
+NOTIFYICONDATA2 trayIcon;
+
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass2[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass3[MAX_LOADSTRING]; // The title bar text
+
+// Foward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+ATOM MyRegisterClass2(HINSTANCE hInstance);
+ATOM MyRegisterClass3(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK ChanInfoProc(HWND, UINT, WPARAM, LPARAM);
+
+void setTrayIcon(int type, const char *,const char *,bool);
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt);
+
+
+HWND chWnd=NULL;
+
+bool gbGetFile = FALSE;
+bool gbStart = FALSE;
+time_t gtGetFile;
+time_t gtStartTime;
+// --------------------------------------------------
+void LOG2(const char *fmt,...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char str[4096];
+ vsprintf(str,fmt,ap);
+ OutputDebugString(str);
+ va_end(ap);
+}
+
+
+
+// ---------------------------------------
+int APIENTRY WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+#ifdef _DEBUG
+ // memory leak check
+ ::_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ char tmpURL[8192];
+ tmpURL[0]=0;
+ char *chanURL=NULL;
+
+ hInst = hInstance;
+
+ iniFileName.set(".\\peercast.ini");
+
+ WIN32_FIND_DATA fd; //JP-EX
+ HANDLE hFind; //JP-EX
+
+ OSVERSIONINFO osInfo; //JP-EX
+ osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //JP-EX
+ GetVersionEx(&osInfo);
+ if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ winDistinctionNT = true;
+ else
+ winDistinctionNT = false;
+
+ // off by default now
+ showGUI = false;
+
+ if (strlen(lpCmdLine) > 0)
+ {
+ char *p;
+ if ((p = strstr(lpCmdLine,"-inifile"))!=NULL)
+ iniFileName.setFromString(p+8);
+
+ if (strstr(lpCmdLine,"-zen"))
+ showGUI = false;
+
+ if (strstr(lpCmdLine,"-multi"))
+ allowMulti = true;
+
+ if (strstr(lpCmdLine,"-kill"))
+ killMe = true;
+
+ if ((p = strstr(lpCmdLine,"-url"))!=NULL)
+ {
+ p+=4;
+ while (*p)
+ {
+ if (*p=='"')
+ {
+ p++;
+ break;
+ }
+ if (*p != ' ')
+ break;
+ p++;
+ }
+ if (*p)
+ strncpy(tmpURL,p,sizeof(tmpURL)-1);
+ }
+ }
+
+ // get current path
+ {
+ exePath = iniFileName;
+ char *s = exePath.cstr();
+ char *end = NULL;
+ while (*s)
+ {
+ if (*s++ == '\\')
+ end = s;
+ }
+ if (end)
+ *end = 0;
+ }
+
+
+ if (strnicmp(tmpURL,"peercast://",11)==0)
+ {
+ if (strnicmp(tmpURL+11,"pls/",4)==0)
+ chanURL = tmpURL+11+4;
+ else
+ chanURL = tmpURL+11;
+ showGUI = false;
+ }
+
+
+ MSG msg;
+ HACCEL hAccelTable;
+
+ // Initialize global strings
+ //LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ //LoadString(hInstance, IDC_APP_TITLE, szWindowClass, MAX_LOADSTRING);
+
+ strcpy(szTitle,"PeerCast");
+ strcpy(szWindowClass,"PeerCast");
+ strcpy(szWindowClass2,"Main");
+ strcpy(szWindowClass3,"Start");
+
+
+
+ if (!allowMulti)
+ {
+ HANDLE mutex = CreateMutex(NULL,TRUE,szWindowClass);
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ HWND oldWin = FindWindow(szWindowClass,NULL);
+ if (oldWin)
+ {
+ SendMessage(oldWin,WM_SHOWGUI,0,0);
+ if (killMe)
+ {
+ SendMessage(oldWin,WM_DESTROY,0,0);
+ return 0;
+ }
+
+ if (chanURL)
+ {
+ COPYDATASTRUCT copy;
+ copy.dwData = WM_PLAYCHANNEL;
+ copy.cbData = strlen(chanURL)+1; // plus null term
+ copy.lpData = chanURL;
+ SendMessage(oldWin,WM_COPYDATA,NULL,(LPARAM)©);
+ }else{
+ if (showGUI)
+ SendMessage(oldWin,WM_SHOWGUI,0,0);
+ }
+ }
+ return 0;
+ }
+ }
+
+ if (killMe)
+ return 0;
+
+ MyRegisterClass(hInstance);
+ MyRegisterClass2(hInstance);
+ MyRegisterClass3(hInstance);
+
+ // Perform application initialization:
+ if (!InitInstance (hInstance, nCmdShow))
+ return FALSE;
+
+ peercastInst = new MyPeercastInst();
+ peercastApp = new MyPeercastApp();
+
+ peercastInst->init();
+
+ LOG_DEBUG("Set OS Type: %s",winDistinctionNT?"WinNT":"Win9x");
+
+ if (peercastApp->clearTemp()) //JP-EX
+ {
+ DeleteFile("play.pls");
+ hFind = FindFirstFile("*.asx",&fd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ DeleteFile((char *)&fd.cFileName);
+ }
+ while (FindNextFile(hFind,&fd));
+
+ FindClose(hFind);
+ }
+ }
+
+ if (chanURL)
+ {
+ ChanInfo info;
+ servMgr->procConnectArgs(chanURL,info);
+ chanMgr->findAndPlayChannel(info,false);
+ }
+
+ struct tm t;
+ memset(&t,0,sizeof(t));
+ t.tm_year = 2007 - 1900;
+ t.tm_mon = 4 - 1;
+ t.tm_mday = 7;
+ t.tm_hour = 21;
+ t.tm_min = 0;
+ t.tm_sec = 0;
+ gtStartTime = ::mktime(&t);
+ t.tm_hour = 20;
+ t.tm_min = 50;
+ gtGetFile = ::mktime(&t);
+
+ if (gtStartTime > sys->getTime()){
+ gbGetFile = TRUE;
+ gbStart = TRUE;
+ }
+
+ hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SIMPLE);
+
+ // setup menu notifes
+ int mask = peercastInst->getNotifyMask();
+ if (mask & ServMgr::NT_PEERCAST)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_PEERCAST,MF_CHECKED|MF_BYCOMMAND);
+ if (mask & ServMgr::NT_BROADCASTERS)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_BROADCASTERS,MF_CHECKED|MF_BYCOMMAND);
+ if (mask & ServMgr::NT_TRACKINFO)
+ CheckMenuItem(trayMenu,ID_POPUP_SHOWMESSAGES_TRACKINFO,MF_CHECKED|MF_BYCOMMAND);
+
+ // Main message loop:
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ Shell_NotifyIcon(NIM_DELETE, (NOTIFYICONDATA*)&trayIcon);
+
+ peercastInst->saveSettings();
+ peercastInst->quit();
+
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+
+ return msg.wParam;
+}
+
+
+
+//
+// FUNCTION: MyRegisterClass()
+//
+// PURPOSE: Registers the window class.
+//
+// COMMENTS:
+//
+// This function and its usage is only necessary if you want this code
+// to be compatible with Win32 systems prior to the 'RegisterClassEx'
+// function that was added to Windows 95. It is important to call this function
+// so that the application will get 'well formed' small icons associated
+// with it.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass2(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
+ wcex.lpfnWndProc = (WNDPROC)GUIProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass2;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+ATOM MyRegisterClass3(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = (WNDPROC)StartProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_SIMPLE);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+// wcex.lpszMenuName = (LPCSTR)IDC_SIMPLE;
+ wcex.lpszMenuName = NULL;
+ wcex.lpszClassName = szWindowClass3;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+ return RegisterClassEx(&wcex);
+}
+
+//-----------------------------
+void loadIcons(HINSTANCE hInstance, HWND hWnd)
+{
+ icon1 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL);
+ icon2 = LoadIcon(hInstance, (LPCTSTR)IDI_SMALL2);
+
+ trayIcon.cbSize = sizeof(trayIcon);
+ trayIcon.hWnd = hWnd;
+ trayIcon.uID = 100;
+ trayIcon.uFlags = NIF_MESSAGE + NIF_ICON + NIF_TIP;
+ trayIcon.uCallbackMessage = WM_TRAYICON;
+ trayIcon.hIcon = icon1;
+ strcpy(trayIcon.szTip, "PeerCast");
+
+ Shell_NotifyIcon(NIM_ADD, (NOTIFYICONDATA*)&trayIcon);
+
+ //ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ if(!trayMenu) // for PCRaw (tray icon)
+ trayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_TRAYMENU));
+ if(!ltrayMenu) // for PCRaw (tray icon)
+ ltrayMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDR_LTRAYMENU));
+
+
+}
+
+//-----------------------------
+//
+// FUNCTION: InitInstance(HANDLE, int)
+//
+// PURPOSE: Saves instance handle and creates main window
+//
+// COMMENTS:
+//
+// In this function, we save the instance handle in a global variable and
+// create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ HWND hWnd;
+
+ hInst = hInstance; // Store instance handle in our global variable
+
+ hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+ if (!hWnd)
+ {
+ return FALSE;
+ }
+
+ mainWnd = hWnd;
+
+ g_iTaskbarCreated = RegisterWindowMessage("TaskbarCreated"); // for PCRaw (tray icon)
+
+ loadIcons(hInstance,hWnd);
+
+ using namespace Gdiplus;
+ GdiplusStartupInput gdiplusStartupInput;
+ GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+ return TRUE;
+}
+//-----------------------------
+//static String trackTitle;
+//static String channelComment;
+
+//-----------------------------
+void channelPopup(const char *title, const char *msg, bool isPopup = true)
+{
+ String both;
+
+ if (*title == '\0') return;
+ both.append(msg);
+ both.append(" (");
+ both.append(title);
+ both.append(")");
+
+ trayIcon.uFlags = NIF_ICON|NIF_TIP;
+ strncpy(trayIcon.szTip, both.cstr(),sizeof(trayIcon.szTip)-1);
+ trayIcon.szTip[sizeof(trayIcon.szTip)-1]=0;
+
+ if (isPopup) trayIcon.uFlags |= 16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+//-----------------------------
+void clearChannelPopup()
+{
+ trayIcon.uFlags = NIF_ICON|16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,"",sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,"",sizeof(trayIcon.szInfoTitle)-1);
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+}
+
+//-----------------------------
+// PopupEntry
+struct PopupEntry {
+ GnuID id;
+ String name;
+ String track;
+ String comment;
+ PopupEntry *next;
+};
+static PopupEntry *PEList = NULL;
+static WLock PELock;
+
+static void putPopupEntry(PopupEntry *pe)
+{
+ PELock.on();
+ pe->next = PEList;
+ PEList = pe;
+ PELock.off();
+}
+
+static PopupEntry *getPopupEntry(GnuID id)
+{
+ PELock.on();
+ PopupEntry *pe = PEList;
+ PopupEntry *prev = NULL;
+ while (pe) {
+ if (id.isSame(pe->id)) {
+ if (prev) prev->next = pe->next;
+ else PEList = pe->next;
+ PELock.off();
+ pe->next = NULL;
+ return pe;
+ }
+ prev = pe;
+ pe = pe->next;
+ }
+ PELock.off();
+ return NULL;
+}
+
+static PopupEntry *getTopPopupEntry()
+{
+ PopupEntry *p = NULL;
+ PELock.on();
+ if (PEList) {
+ p = PEList;
+ PEList = PEList->next;
+ }
+ PELock.off();
+ return p;
+}
+
+//-----------------------------
+void APICALL MyPeercastApp::channelStart(ChanInfo *info)
+{
+
+// lastPlayID = info->id;
+//
+// if(!isIndexTxt(info)) // for PCRaw (popup)
+// clearChannelPopup();
+
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (!pe) {
+ pe = new PopupEntry;
+ pe->id = info->id;
+ }
+ if (!isIndexTxt(info))
+ putPopupEntry(pe);
+ else
+ delete pe;
+}
+//-----------------------------
+void APICALL MyPeercastApp::channelStop(ChanInfo *info)
+{
+// if (info->id.isSame(lastPlayID))
+// {
+// lastPlayID.clear();
+//
+// if(!isIndexTxt(info)) // for PCRaw (popup)
+// clearChannelPopup();
+// }
+
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (pe) delete pe;
+
+ pe = getTopPopupEntry();
+ if (!pe) {
+ clearChannelPopup();
+ } else {
+ if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+ {
+ String name,track; //JP-Patch
+ name = pe->name; //JP-Patch
+ track = pe->track; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ track.convertTo(String::T_SJIS); //JP-Patch
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),trackTitle.cstr());
+ channelPopup(name.cstr(),track.cstr(), false); //JP-Patch
+ }
+ putPopupEntry(pe);
+ }
+}
+//-----------------------------
+void APICALL MyPeercastApp::channelUpdate(ChanInfo *info)
+{
+ if (info)
+ {
+ PopupEntry *pe = getPopupEntry(info->id);
+ if (!pe) return;
+
+ String tmp;
+ tmp.append(info->track.artist);
+ tmp.append(" ");
+ tmp.append(info->track.title);
+
+
+ if (!tmp.isSame(pe->track))
+ {
+ pe->name = info->name;
+ pe->track = tmp;
+ if (ServMgr::NT_TRACKINFO & peercastInst->getNotifyMask())
+ {
+ //trackTitle=tmp;
+ String name,track; //JP-Patch
+ name = info->name; //JP-Patch
+ track = tmp; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ track.convertTo(String::T_SJIS); //JP-Patch
+ if(!isIndexTxt(info)) // for PCRaw (popup)
+ {
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),trackTitle.cstr());
+ channelPopup(name.cstr(),track.cstr()); //JP-Patch
+ }
+ }
+ } else if (!info->comment.isSame(pe->comment))
+ {
+ pe->name = info->name;
+ pe->comment = info->comment;
+ if (ServMgr::NT_BROADCASTERS & peercastInst->getNotifyMask())
+ {
+ //channelComment = info->comment;
+ String name,comment; //JP-Patch
+ name = info->name; //JP-Patch
+ comment = info->comment; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patch
+ comment.convertTo(String::T_SJIS); //JP-Patch
+ if(!isIndexTxt(info)) // for PCRaw (popup)
+ {
+ clearChannelPopup();
+ // channelPopup(info->name.cstr(),channelComment.cstr());
+ channelPopup(name.cstr(),comment.cstr());
+ }
+ }
+ }
+
+ if (!isIndexTxt(info))
+ putPopupEntry(pe);
+ else
+ delete pe;
+ }
+}
+//-----------------------------
+void APICALL MyPeercastApp::notifyMessage(ServMgr::NOTIFY_TYPE type, const char *msg)
+{
+ currNotify = type;
+
+ if (type == ServMgr::NT_UPGRADE)
+ {
+ trayIcon.uFlags = NIF_ICON;
+ trayIcon.hIcon = icon2;
+ }else{
+ trayIcon.uFlags = NIF_ICON;
+ trayIcon.hIcon = icon1;
+ }
+
+ const char *title="";
+
+ switch(type)
+ {
+ case ServMgr::NT_UPGRADE:
+ title = "Upgrade alert";
+ break;
+ case ServMgr::NT_PEERCAST:
+ title = "Message from PeerCast:";
+ break;
+
+ }
+
+ if (type & peercastInst->getNotifyMask())
+ {
+ trayIcon.uFlags |= 16;
+ trayIcon.uTimeoutOrVersion = 10000;
+ strncpy(trayIcon.szInfo,msg,sizeof(trayIcon.szInfo)-1);
+ strncpy(trayIcon.szInfoTitle,title,sizeof(trayIcon.szInfoTitle)-1);
+ Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA*)&trayIcon);
+ }
+}
+//-----------------------------
+
+// createGUI()
+//
+void createGUI(HWND hWnd)
+{
+ if (!guiWnd){
+ guiWnd = ::CreateWindow(szWindowClass2,
+ "Peercast-IM@S",
+ WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX) /*| WS_VSCROLL | WS_HSCROLL*/,
+ 0,
+ 0,
+ 800,
+ 600,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+ }
+ ShowWindow(guiWnd,SW_SHOWNORMAL);
+}
+
+
+//
+// addRelayedChannelsMenu(HMENU m)
+//
+//
+void addRelayedChannelsMenu(HMENU cm)
+{
+ int cnt = GetMenuItemCount(cm);
+ for(int i=0; i<cnt-3; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);
+
+ Channel *c = chanMgr->channel;
+ while(c)
+ {
+ if (c->isActive())
+ {
+ char str[128],name[64];
+ strncpy(name,c->info.name,32);
+ name[32]=0;
+ if (strlen(c->info.name) > 32)
+ strcat(name,"...");
+
+
+ sprintf(str,"%s (%d kb/s %s)",name,c->info.bitrate,ChanInfo::getTypeStr(c->info.contentType));
+ //InsertMenu(cm,0,MF_BYPOSITION,RELAY_CMD+i,str);
+ }
+ c=c->next;
+ }
+}
+
+typedef int (*COMPARE_FUNC)(const void *,const void *);
+
+static int compareHitLists(ChanHitList **c2, ChanHitList **c1)
+{
+ return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+static int compareChannels(Channel **c2, Channel **c1)
+{
+ return stricmp(c1[0]->info.name.cstr(),c2[0]->info.name.cstr());
+}
+
+//
+// addAllChannelsMenu(HMENU m)
+//
+//
+void addAllChannelsMenu(HMENU cm)
+{
+ int cnt = GetMenuItemCount(cm);
+/* for(int i=0; i<cnt-2; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);*/
+
+ for(int i=0; i<cnt; i++)
+ DeleteMenu(cm,0,MF_BYPOSITION);
+
+ HMENU yMenu = CreatePopupMenu();
+ if (!servMgr->rootHost2.isEmpty()){
+ InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES2,servMgr->rootHost2);
+ }
+ if (!servMgr->rootHost.isEmpty()){
+ InsertMenu(yMenu,0,MF_BYPOSITION,ID_POPUP_YELLOWPAGES1,servMgr->rootHost);
+ }
+
+ InsertMenu(cm,0,MF_BYPOSITION|MF_POPUP,(UINT)yMenu,"\83C\83G\83\8d\81[\83y\81[\83W");
+ InsertMenu(cm,0,MF_BYPOSITION|MF_SEPARATOR,NULL,NULL);
+ // add channels to menu
+ int numActive=0;
+ Channel *ch = chanMgr->channel;
+ while(ch)
+ {
+ char str[128],name[64];
+ String sjis; //JP-Patch
+ sjis = ch->info.name; //JP-Patch
+ sjis.convertTo(String::T_SJIS); //JP-Patch
+ strncpy(name,sjis.cstr(),32);
+ //strncpy(name,ch->info.name,32);
+ name[32]=0;
+ //if (strlen(ch->info.name) > 32)
+ if (strlen(sjis.cstr()) > 32) //JP-Patch
+ strcat(name,"...");
+
+ sprintf(str,"%s (%d kb/s %s)",name,ch->info.bitrate,ChanInfo::getTypeStr(ch->info.contentType));
+
+ HMENU opMenu = CreatePopupMenu();
+ InsertMenu(opMenu,0,MF_BYPOSITION,INFO_CMD+numActive,"Info");
+ if (ch->info.url.isValidURL())
+ InsertMenu(opMenu,0,MF_BYPOSITION,URL_CMD+numActive,"URL");
+ InsertMenu(opMenu,0,MF_BYPOSITION,PLAY_CMD+numActive,"Play");
+
+ UINT fl = MF_BYPOSITION|MF_POPUP;
+ if (ch)
+ fl |= (ch->isPlaying()?MF_CHECKED:0);
+
+ InsertMenu(cm,0,fl,(UINT)opMenu,str);
+
+ numActive++;
+
+ ch=ch->next;
+ }
+
+
+ //if (!numActive)
+ // InsertMenu(cm,0,MF_BYPOSITION,0,"<No channels>");
+
+
+
+
+}
+
+
+//
+// flipNotifyPopup(id, flag)
+void flipNotifyPopup(int id, ServMgr::NOTIFY_TYPE nt)
+{
+ int mask = peercastInst->getNotifyMask();
+
+ mask ^= nt;
+ if (mask & nt)
+ CheckMenuItem(trayMenu,id,MF_CHECKED|MF_BYCOMMAND);
+ else
+ CheckMenuItem(trayMenu,id,MF_UNCHECKED|MF_BYCOMMAND);
+
+ peercastInst->setNotifyMask(mask);
+ peercastInst->saveSettings();
+}
+
+
+static void showHTML(const char *file)
+{
+ char url[256];
+ sprintf(url,"%s/%s",servMgr->htmlPath,file);
+
+// sys->callLocalURL(url,servMgr->serverHost.port);
+ sys->callLocalURL(url, // for PCRaw (url)
+ (servMgr->allowServer1&Servent::ALLOW_HTML)?(servMgr->serverHost.port):(servMgr->serverHost.port+1));
+}
+
+static ChanInfo getChannelInfo(int index)
+{
+ Channel *c = chanMgr->findChannelByIndex(index);
+ if (c)
+ return c->info;
+
+ ChanInfo info;
+ return info;
+}
+
+//
+// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+// PURPOSE: Processes messages for the main window.
+//
+// WM_COMMAND - process the application menu
+// WM_PAINT - Paint the main window
+// WM_DESTROY - post a quit message and return
+//
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ POINT point;
+ char buf[1024];
+
+ if(message == g_iTaskbarCreated) // for PCRaw (tray icon)
+ loadIcons(hInst, hWnd);
+
+ switch (message)
+ {
+ case WM_SHOWGUI:
+ createGUI(hWnd);
+ break;
+
+
+ case WM_TRAYICON:
+ switch((UINT)lParam)
+ {
+ case WM_LBUTTONDOWN:
+ if (allowTrayMenu)
+ SendMessage(hWnd,WM_SHOWMENU,2,0);
+ SetForegroundWindow(hWnd);
+ break;
+ case WM_RBUTTONDOWN:
+ if (allowTrayMenu)
+ SendMessage(hWnd,WM_SHOWMENU,1,0);
+ SetForegroundWindow(hWnd);
+ break;
+ case WM_LBUTTONDBLCLK:
+ createGUI(hWnd);
+ break;
+ }
+ break;
+
+ case WM_COPYDATA:
+ {
+ COPYDATASTRUCT *pc = (COPYDATASTRUCT *)lParam;
+ LOG_DEBUG("URL request: %s",pc->lpData);
+ if (pc->dwData == WM_PLAYCHANNEL)
+ {
+ ChanInfo info;
+ servMgr->procConnectArgs((char *)pc->lpData,info);
+ chanMgr->findAndPlayChannel(info,false);
+ }
+ //sys->callLocalURL((const char *)pc->lpData,servMgr->serverHost.port);
+ }
+ break;
+ case WM_GETPORTNUMBER:
+ {
+ int port;
+ port=servMgr->serverHost.port;
+ ReplyMessage(port);
+ }
+ break;
+
+ case WM_SHOWMENU:
+ {
+ if (servMgr->saveGuiPos){
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+ } else {
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+ }
+
+ SetForegroundWindow(hWnd);
+ bool skipMenu=false;
+
+ allowTrayMenu = false;
+
+ // check for notifications
+ if (currNotify & ServMgr::NT_UPGRADE)
+ {
+ if (servMgr->downloadURL[0])
+ {
+ if ((sys->getTime()-seenNewVersionTime) > (60*60)) // notify every hour
+ {
+ if (MessageBox(hWnd,"A newer version of PeerCast is available, press OK to upgrade.","PeerCast",MB_OKCANCEL|MB_APPLMODAL|MB_ICONEXCLAMATION) == IDOK)
+ sys->getURL(servMgr->downloadURL);
+
+ seenNewVersionTime=sys->getTime();
+ skipMenu=true;
+ }
+ }
+ }
+
+
+ if (!skipMenu)
+ {
+ RECT rcWnd;
+ HMENU menu;
+ UINT flg = 0;
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWnd, 0);
+ GetCursorPos(&point);
+
+ if (point.x < rcWnd.left){
+ point.x = rcWnd.left;
+ flg |= TPM_LEFTALIGN;
+ }
+ if (point.x > rcWnd.right){
+ point.x = rcWnd.right;
+ flg |= TPM_RIGHTALIGN;
+ }
+ if (point.y < rcWnd.top){
+ point.y = rcWnd.top;
+ flg |= TPM_TOPALIGN;
+ }
+ if (point.y > rcWnd.bottom){
+ point.y = rcWnd.bottom;
+ flg |= TPM_BOTTOMALIGN;
+ }
+ if (flg == 0){
+ flg = TPM_RIGHTALIGN;
+ }
+
+ switch (wParam)
+ {
+ case 1:
+ menu = GetSubMenu(trayMenu,0);
+ addAllChannelsMenu(GetSubMenu(menu,0));
+ addRelayedChannelsMenu(GetSubMenu(menu,1));
+ break;
+ case 2:
+ menu = GetSubMenu(ltrayMenu,0);
+ addAllChannelsMenu(menu);
+ break;
+ }
+ if (!TrackPopupMenu(menu,flg,point.x,point.y,0,hWnd,NULL))
+ {
+ LOG_ERROR("Can`t track popup menu: %d",GetLastError());
+ }
+ PostMessage(hWnd,WM_NULL,0,0);
+
+ }
+ allowTrayMenu = true;
+ }
+ break;
+
+ case WM_CREATE:
+ if (showGUI)
+ createGUI(hWnd);
+ break;
+
+ case WM_COMMAND:
+ wmId = LOWORD(wParam);
+ wmEvent = HIWORD(wParam);
+
+ if ((wmId >= INFO_CMD) && (wmId < INFO_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - INFO_CMD;
+ chanInfo = getChannelInfo(c);
+ chanInfoIsRelayed = false;
+ if (winDistinctionNT)
+ DialogBox(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc);
+ else
+ {
+ HWND WKDLG; //JP-Patch
+ WKDLG = CreateDialog(hInst, (LPCTSTR)IDD_CHANINFO, hWnd, (DLGPROC)ChanInfoProc); //JP-Patch
+ ShowWindow(WKDLG,SW_SHOWNORMAL); //JP-Patch
+ }
+ return 0;
+ }
+ if ((wmId >= URL_CMD) && (wmId < URL_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - URL_CMD;
+ chanInfo = getChannelInfo(c);
+ if (chanInfo.url.isValidURL())
+ sys->getURL(chanInfo.url);
+ return 0;
+ }
+ if ((wmId >= PLAY_CMD) && (wmId < PLAY_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - PLAY_CMD;
+ chanInfo = getChannelInfo(c);
+ chanMgr->findAndPlayChannel(chanInfo,false);
+ return 0;
+ }
+ if ((wmId >= RELAY_CMD) && (wmId < RELAY_CMD+MAX_CHANNELS))
+ {
+ int c = wmId - RELAY_CMD;
+ chanInfo = getChannelInfo(c);
+ chanMgr->findAndPlayChannel(chanInfo,true);
+ return 0;
+ }
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case ID_POPUP_SHOWMESSAGES_PEERCAST:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_PEERCAST,ServMgr::NT_PEERCAST);
+ break;
+ case ID_POPUP_SHOWMESSAGES_BROADCASTERS:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_BROADCASTERS,ServMgr::NT_BROADCASTERS);
+ break;
+ case ID_POPUP_SHOWMESSAGES_TRACKINFO:
+ flipNotifyPopup(ID_POPUP_SHOWMESSAGES_TRACKINFO,ServMgr::NT_TRACKINFO);
+ break;
+
+ case ID_POPUP_ABOUT:
+ case IDM_ABOUT:
+ DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+ break;
+ case ID_POPUP_SHOWGUI:
+ case IDM_SETTINGS_GUI:
+ case ID_POPUP_ADVANCED_SHOWGUI:
+ {
+ createGUI(hWnd);
+ break;
+ }
+ case ID_POPUP_YELLOWPAGES:
+ sys->getURL("http://yp.peercast.org/");
+ break;
+ case ID_POPUP_YELLOWPAGES1:
+ sprintf(buf, "http://%s",servMgr->rootHost.cstr());
+ sys->getURL(buf);
+ break;
+ case ID_POPUP_YELLOWPAGES2:
+ sprintf(buf, "http://%s",servMgr->rootHost2.cstr());
+ sys->getURL(buf);
+ break;
+
+ case ID_POPUP_ADVANCED_VIEWLOG:
+ showHTML("viewlog.html");
+ break;
+ case ID_POPUP_ADVANCED_SAVESETTINGS:
+ servMgr->saveSettings(iniFileName.cstr());
+ break;
+ case ID_POPUP_ADVANCED_INFORMATION:
+ showHTML("index.html");
+ break;
+ case ID_FIND_CHANNELS:
+ case ID_POPUP_ADVANCED_ALLCHANNELS:
+ case ID_POPUP_UPGRADE:
+ sys->callLocalURL("admin?cmd=upgrade",servMgr->serverHost.port);
+ break;
+ case ID_POPUP_ADVANCED_RELAYEDCHANNELS:
+ case ID_POPUP_FAVORITES_EDIT:
+ showHTML("relays.html");
+ break;
+ case ID_POPUP_ADVANCED_BROADCAST:
+ showHTML("broadcast.html");
+ break;
+ case ID_POPUP_SETTINGS:
+ showHTML("settings.html");
+ break;
+ case ID_POPUP_CONNECTIONS:
+ showHTML("connections.html");
+ break;
+ case ID_POPUP_HELP:
+ sys->getURL("http://www.peercast.org/help.php");
+ break;
+
+ case ID_POPUP_SAVE_GUI_POS:
+ if (servMgr->saveGuiPos){
+ servMgr->saveGuiPos = false;
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_UNCHECKED|MF_BYCOMMAND);
+ } else {
+ servMgr->saveGuiPos = true;
+ CheckMenuItem(trayMenu, ID_POPUP_SAVE_GUI_POS, MF_CHECKED|MF_BYCOMMAND);
+ }
+ peercastInst->saveSettings();
+ break;
+
+ case ID_POPUP_KEEP_DOWNSTREAMS:
+ if (servMgr->keepDownstreams){
+ servMgr->keepDownstreams = false;
+ CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_UNCHECKED|MF_BYCOMMAND);
+ } else {
+ servMgr->keepDownstreams = true;
+ CheckMenuItem(trayMenu, ID_POPUP_KEEP_DOWNSTREAMS, MF_CHECKED|MF_BYCOMMAND);
+ }
+ //peercastInst->saveSettings();
+ break;
+
+ case ID_POPUP_EXIT_CONFIRM:
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+// Mesage handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ //SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENT);
+// SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTJP);
+#ifdef VERSION_EX
+ SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTEX);
+#else
+ SendDlgItemMessage(hDlg,IDC_ABOUTVER,WM_SETTEXT,0,(LONG)PCX_AGENTVP);
+#endif
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+ case IDC_BUTTON1:
+ sys->getURL("http://www.peercast.org");
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+
+ }
+ break;
+ case WM_DESTROY:
+ break;
+ }
+ return FALSE;
+}
+
+// Mesage handler for chaninfo box
+LRESULT CALLBACK ChanInfoProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ char str[1024];
+ //strcpy(str,chanInfo.track.artist.cstr());
+ strcpy(str,chanInfo.track.artist); //JP-Patch
+ strcat(str," - ");
+ //strcat(str,chanInfo.track.title.cstr());
+ strcat(str,chanInfo.track.title);
+ String name,track,comment,desc,genre; //JP-Patch
+ name = chanInfo.name; //JP-Patch
+ track = str; //JP-Patch
+ comment = chanInfo.comment; //JP-Patch
+ desc = chanInfo.desc; //JP-Patc
+ genre = chanInfo.genre; //JP-Patch
+ name.convertTo(String::T_SJIS); //JP-Patc
+ track.convertTo(String::T_SJIS); //JP-Patch
+ comment.convertTo(String::T_SJIS); //JP-Patch
+ desc.convertTo(String::T_SJIS); //JP-Patch
+ genre.convertTo(String::T_SJIS); //JP-Patch
+
+ //SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)chanInfo.name.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_NAME,WM_SETTEXT,0,(LONG)name.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)str);
+ SendDlgItemMessage(hDlg,IDC_EDIT_PLAYING,WM_SETTEXT,0,(LONG)track.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)chanInfo.comment.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_MESSAGE,WM_SETTEXT,0,(LONG)comment.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)chanInfo.desc.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_DESC,WM_SETTEXT,0,(LONG)desc.cstr()); //JP-Patch
+ //SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)chanInfo.genre.cstr());
+ SendDlgItemMessage(hDlg,IDC_EDIT_GENRE,WM_SETTEXT,0,(LONG)genre.cstr()); //JP-Patch
+
+ sprintf(str,"%d kb/s %s",chanInfo.bitrate,ChanInfo::getTypeStr(chanInfo.contentType));
+ SendDlgItemMessage(hDlg,IDC_FORMAT,WM_SETTEXT,0,(LONG)str);
+
+
+ if (!chanInfo.url.isValidURL())
+ EnableWindow(GetDlgItem(hDlg,IDC_CONTACT),false);
+
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ {
+ SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)ch->getStatusStr());
+ SendDlgItemMessage(hDlg, IDC_KEEP,BM_SETCHECK, ch->stayConnected, 0);
+ }else
+ {
+ SendDlgItemMessage(hDlg,IDC_EDIT_STATUS,WM_SETTEXT,0,(LONG)"OK");
+ EnableWindow(GetDlgItem(hDlg,IDC_KEEP),false);
+ }
+
+
+
+ POINT point;
+ RECT rect,drect;
+ HWND hDsk = GetDesktopWindow();
+ GetWindowRect(hDsk,&drect);
+ GetWindowRect(hDlg,&rect);
+ GetCursorPos(&point);
+
+ POINT pos,size;
+ size.x = rect.right-rect.left;
+ size.y = rect.bottom-rect.top;
+
+ if (point.x-drect.left < size.x)
+ pos.x = point.x;
+ else
+ pos.x = point.x-size.x;
+
+ if (point.y-drect.top < size.y)
+ pos.y = point.y;
+ else
+ pos.y = point.y-size.y;
+
+ SetWindowPos(hDlg,HWND_TOPMOST,pos.x,pos.y,size.x,size.y,0);
+ chWnd = hDlg;
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ {
+ char str[1024],idstr[64];
+ chanInfo.id.toStr(idstr);
+
+ switch (LOWORD(wParam))
+ {
+ case IDC_CONTACT:
+ {
+ sys->getURL(chanInfo.url);
+ return TRUE;
+ }
+ case IDC_DETAILS:
+ {
+ sprintf(str,"admin?page=chaninfo&id=%s&relay=%d",idstr,chanInfoIsRelayed);
+ sys->callLocalURL(str,servMgr->serverHost.port);
+ return TRUE;
+ }
+ case IDC_KEEP:
+ {
+ Channel *ch = chanMgr->findChannelByID(chanInfo.id);
+ if (ch)
+ ch->stayConnected = SendDlgItemMessage(hDlg, IDC_KEEP,BM_GETCHECK, 0, 0) == BST_CHECKED;;
+ return TRUE;
+ }
+
+
+ case IDC_PLAY:
+ {
+ chanMgr->findAndPlayChannel(chanInfo,false);
+ return TRUE;
+ }
+
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ if (winDistinctionNT)
+ EndDialog(hDlg, 0);
+ else
+ DestroyWindow(hDlg); //JP-Patch
+ break;
+
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) == WA_INACTIVE)
+ if (winDistinctionNT)
+ EndDialog(hDlg, 0);
+ else
+ DestroyWindow(hDlg); //JP-Patch
+ break;
+ case WM_DESTROY:
+ chWnd = NULL;
+ break;
+
+
+ }
+ return FALSE;
+}
--- /dev/null
+
+// ------------------------------------------------
+// File : simple.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#if !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
+#define AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+// ---------------------------------
+class MyPeercastInst : public PeercastInstance
+{
+public:
+ virtual Sys * APICALL createSys();
+};
+// ---------------------------------
+class MyPeercastApp : public PeercastApplication
+{
+public:
+ MyPeercastApp ()
+ {
+ //logFile.openWriteReplace("log.txt");
+ }
+
+ virtual const char * APICALL getPath();
+
+ virtual const char * APICALL getIniFilename();
+ virtual const char *APICALL getClientTypeOS();
+ virtual void APICALL openLogFile(); //JP-EX
+ virtual void APICALL getDirectory(); //JP-EX
+ virtual bool APICALL clearTemp(); //JP-EX
+ virtual void APICALL printLog(LogBuffer::TYPE t, const char *str);
+
+ virtual void APICALL updateSettings();
+ virtual void APICALL notifyMessage(ServMgr::NOTIFY_TYPE, const char *);
+
+ virtual void APICALL channelStart(ChanInfo *);
+ virtual void APICALL channelStop(ChanInfo *);
+ virtual void APICALL channelUpdate(ChanInfo *);
+
+ FileStream logFile;
+
+};
+
+
+#endif // !defined(AFX_SIMPLE_H__F2E64B1B_62DE_473C_A6B6_E7826D41E0FA__INCLUDED_)
--- /dev/null
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+// Generated Help ID header file
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.hm"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
+#pragma code_page(932)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAYMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM "\8fî\95ñ", ID_POPUP_ABOUT
+ MENUITEM "\83w\83\8b\83v", ID_POPUP_HELP
+ MENUITEM SEPARATOR
+ POPUP "\83|\83b\83v\83A\83b\83v\83\81\83b\83Z\81[\83W"
+ BEGIN
+ MENUITEM "PeerCast", ID_POPUP_SHOWMESSAGES_PEERCAST
+
+ MENUITEM "\94z\90M\8eÒ", ID_POPUP_SHOWMESSAGES_BROADCASTERS
+
+ MENUITEM "\83g\83\89\83b\83N\8fî\95ñ", ID_POPUP_SHOWMESSAGES_TRACKINFO
+
+ MENUITEM "\83A\83b\83v\83f\81[\83g\8fî\95ñ", ID_POPUP_POPUPMESSAGES_UPGRADEALERTS
+ , CHECKED, GRAYED
+ END
+ POPUP "\8d\82\93x"
+ BEGIN
+ MENUITEM "\8fî\95ñ", ID_POPUP_ADVANCED_INFORMATION
+
+ MENUITEM "\83\8a\83\8c\81[\83`\83\83\83\93\83l\83\8b", ID_POPUP_ADVANCED_RELAYEDCHANNELS
+
+ MENUITEM "\94z\90M", ID_POPUP_ADVANCED_BROADCAST
+
+ MENUITEM "\83R\83l\83N\83V\83\87\83\93", ID_POPUP_CONNECTIONS
+ MENUITEM "\83\8d\83O", ID_POPUP_ADVANCED_VIEWLOG
+
+ MENUITEM "\90Ý\92è", ID_POPUP_SETTINGS
+ MENUITEM "GUI\82ð\8aJ\82", ID_POPUP_ADVANCED_SHOWGUI
+
+ END
+ POPUP "\92Ç\89Á\90Ý\92è"
+ BEGIN
+ MENUITEM "\8fI\97¹\8e\9e\81A\95\\8e¦\88Ê\92u\82ð\95Û\91¶", ID_POPUP_SAVE_GUI_POS
+ , CHECKED
+ MENUITEM "\8dÄ\90Ú\91±\8e\9e\89º\97¬\88Û\8e\9d", ID_POPUP_KEEP_DOWNSTREAMS
+ , CHECKED
+ END
+ MENUITEM SEPARATOR
+ POPUP "\8fI\97¹"
+ BEGIN
+ MENUITEM "\82Í\82¢", ID_POPUP_EXIT_CONFIRM
+ MENUITEM "\82¢\82¢\82¦", ID_POPUP_EXIT_NO
+ END
+ END
+END
+
+IDR_LTRAYMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "\83C\83G\83\8d\81[\83y\81[\83W", ID_POPUP_YELLOWPAGES
+ POPUP "\83C\83G\83\8d\81[\83y\81[\83W"
+ BEGIN
+ MENUITEM "AAA", ID_POPUP_YELLOWPAGES1
+ MENUITEM "BBB", ID_POPUP_YELLOWPAGES2
+ END
+ END
+END
+
+IDR_GUIMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "\90§\8cä", ID_POPUP_YELLOWPAGES
+ POPUP "\90§\8cä"
+ BEGIN
+ MENUITEM "AAA", ID_POPUP_YELLOWPAGES1
+ MENUITEM "BBB", ID_POPUP_YELLOWPAGES2
+ END
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINWINDOW DIALOGEX 0, 0, 298, 341
+STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU |
+ WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "PeerCast"
+FONT 9, "MS UI Gothic", 0, 0, 0x1
+BEGIN
+ LISTBOX IDC_LIST1,3,291,291,43,LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "\97L\8cø",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,9,29,60,20,WS_EX_TRANSPARENT
+ EDITTEXT IDC_EDIT1,127,18,47,12,ES_AUTOHSCROLL
+ RTEXT "\83|\81[\83g :",IDC_STATIC,107,20,18,8
+ LISTBOX IDC_LIST2,3,206,291,71,LBS_OWNERDRAWFIXED |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "\83\8d\83O",IDC_STATIC_LOG,3,282,13,8
+ LTEXT "\83R\83l\83N\83V\83\87\83\93",IDC_STATIC_CONNECTION,3,184,40,8
+ GROUPBOX "",IDC_STATIC,3,4,291,49
+ PUSHBUTTON "\83N\83\8a\83A",IDC_BUTTON1,35,279,25,11
+ LISTBOX IDC_LIST3,3,81,291,67,LBS_OWNERDRAWFIXED |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "\90Ø\92f",IDC_BUTTON5,67,65,43,13
+ GROUPBOX "\83\8a\83\8c\81[",IDC_GROUPBOX_RELAY,3,54,291,96
+ EDITTEXT IDC_EDIT3,127,34,47,12,ES_PASSWORD | ES_AUTOHSCROLL
+ RTEXT "\83p\83X\83\8f\81[\83h :",IDC_STATIC,89,36,36,8
+ CONTROL "\83f\83o\83b\83O",IDC_LOGDEBUG,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,127,279,32,11
+ CONTROL "\83l\83b\83g\83\8f\81[\83N",IDC_LOGNETWORK,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,185,279,35,11
+ CONTROL "\83G\83\89\81[",IDC_LOGERRORS,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,159,279,25,11
+ CONTROL "\92â\8e~",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,60,279,30,11
+ PUSHBUTTON "\8dÄ\90¶",IDC_BUTTON8,10,65,22,13
+ CONTROL "\83`\83\83\83\93\83l\83\8b",IDC_LOGCHANNELS,"Button",BS_AUTOCHECKBOX |
+ BS_PUSHLIKE | WS_TABSTOP,221,279,35,11
+ PUSHBUTTON "\8dÄ\90Ú\91±",IDC_BUTTON3,41,65,24,13
+ EDITTEXT IDC_EDIT9,33,159,261,14,ES_AUTOHSCROLL
+ CONTROL "DJ",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE |
+ WS_TABSTOP,5,160,23,12
+ RTEXT "\8dÅ\91å\83\8a\83\8c\81[\90\94 :",IDC_STATIC,203,20,40,8
+ EDITTEXT IDC_MAXRELAYS,248,18,40,14,ES_AUTOHSCROLL | ES_NUMBER
+ PUSHBUTTON "\83L\81[\83v",IDC_BUTTON9,112,65,24,13
+ PUSHBUTTON "\90Ø\92f",IDC_BUTTON6,47,179,43,13
+ LTEXT "Peercast-VP",IDC_STATIC,21,14,39,8
+END
+
+IDD_CHANINFO DIALOGEX 0, 0, 184, 207
+STYLE DS_SETFONT | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Channel Information"
+FONT 9, "MS UI Gothic", 400, 0, 0x80
+BEGIN
+ LTEXT "\96¼\91O:",IDC_STATIC,7,8,24,9
+ EDITTEXT IDC_EDIT_NAME,7,18,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ LTEXT "\93à\97e:",IDC_STATIC,7,79,93,9
+ EDITTEXT IDC_EDIT_PLAYING,8,90,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ LTEXT "DJ \83\81\83b\83Z\81[\83W:",IDC_STATIC,7,117,41,9
+ EDITTEXT IDC_EDIT_MESSAGE,8,128,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ PUSHBUTTON "URL",IDC_CONTACT,7,185,34,15,0,0,HIDC_CONTACT
+ LTEXT "\8fÚ\8d×:",IDC_STATIC,7,43,67,8
+ EDITTEXT IDC_EDIT_DESC,8,53,170,21,ES_MULTILINE | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ RTEXT "\8c`\8e®",IDC_FORMAT,69,80,107,8
+ LTEXT "\83W\83\83\83\93\83\8b:",IDC_STATIC,63,5,22,8
+ EDITTEXT IDC_EDIT_GENRE,87,3,90,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE
+ CONTROL "\83L\81[\83v",IDC_KEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 144,188,33,10
+ LTEXT "\83X\83e\81[\83^\83X:",IDC_STATIC,7,153,41,9
+ EDITTEXT IDC_EDIT_STATUS,8,163,82,12,ES_READONLY | NOT WS_BORDER |
+ NOT WS_TABSTOP,WS_EX_STATICEDGE
+ PUSHBUTTON "\8dÄ\90¶",IDC_PLAY,56,185,34,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MAINWINDOW, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 294
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 336
+ END
+
+ IDD_CHANINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 177
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // \83j\83\85\81[\83g\83\89\83\8b (\83V\83X\83e\83\80\95W\8f\80) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// \89p\8cê (\95Ä\8d\91) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_SIMPLE MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About ...", IDM_ABOUT
+ END
+ POPUP "Settings"
+ BEGIN
+ MENUITEM "GUI", IDM_SETTINGS_GUI
+ END
+END
+
+IDR_VERMENU MENU
+BEGIN
+ POPUP "popup"
+ BEGIN
+ MENUITEM "Please upgrade PeerCast. Click here to download.",
+ ID_POPUP_UPGRADE
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG 22, 17, 163, 59
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+ ICON IDI_SIMPLE,IDC_MYICON,14,9,20,20
+ LTEXT "PeerCast",IDC_ABOUTVER,43,9,103,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 2005",IDC_STATIC,43,22,119,8
+ PUSHBUTTON "OK",IDOK,134,40,24,12,WS_GROUP
+ PUSHBUTTON "www.peercast.org",IDC_BUTTON1,42,40,66,12
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 58
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SIMPLE ICON "Simple.ICO"
+IDI_SMALL2 ICON "small1.ico"
+IDI_SMALL ICON "small3.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_SIMPLE ACCELERATORS
+BEGIN
+ "?", IDM_ABOUT, ASCII, ALT
+ "/", IDM_ABOUT, ASCII, ALT
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""resource.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_APP_TITLE "PeerCast"
+END
+
+#endif // \89p\8cê (\95Ä\8d\91) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
--- /dev/null
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="Simple"
+ ProjectGUID="{7D4833CE-1286-4587-9470-52E098B29C12}"
+ RootNamespace="Simple"
+ SccProjectName=""$/PeerCast.root/PeerCast", JCAAAAAA"
+ SccLocalPath="..\..\.."
+ SccProvider="MSSCCI:Microsoft Visual SourceSafe"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Private Debug|Win32"
+ OutputDirectory=".\Simple___Win32_Private_Debug"
+ IntermediateDirectory=".\Simple___Win32_Private_Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Simple___Win32_Private_Debug/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Simple___Win32_Private_Debug/Simple.pch"
+ AssemblerListingLocation=".\Simple___Win32_Private_Debug/"
+ ObjectFile=".\Simple___Win32_Private_Debug/"
+ ProgramDataBaseFileName=".\Simple___Win32_Private_Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile="Debug/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Simple___Win32_Private_Debug/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Simple___Win32_Private_Debug/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to program files"
+ CommandLine="copy debug\peercast.exe "c:\program files\peercast""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/Simple.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+ OutputFile="Release/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=""C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Release""
+ ProgramDatabaseFile=".\Release/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to pimp & program files"
+ CommandLine="copy release\peercast.exe "c:\program files\peercast"
copy release\peercast.exe ..\pimp\
"
+ />
+ </Configuration>
+ <Configuration
+ Name="Private Release|Win32"
+ OutputDirectory=".\Simple___Win32_Private_Release"
+ IntermediateDirectory=".\Simple___Win32_Private_Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Simple___Win32_Private_Release/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;PRIVATE_BROADCASTER"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Simple___Win32_Private_Release/Simple.pch"
+ AssemblerListingLocation=".\Simple___Win32_Private_Release/"
+ ObjectFile=".\Simple___Win32_Private_Release/"
+ ProgramDataBaseFileName=".\Simple___Win32_Private_Release/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile="PrivRelease/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\Simple___Win32_Private_Release/PeerCast.pdb"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Simple___Win32_Private_Release/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to pimp & program files"
+ CommandLine="copy release\peercast.exe "c:\program files\peercast"
copy release\peercast.exe ..\pimp\
"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/Simple.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../core,../../../core/common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ PrecompiledHeaderFile=".\Debug/Simple.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib gdiplus.lib comsuppw.lib Wininet.lib corelib.lib"
+ OutputFile="Debug/PeerCast.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalLibraryDirectories=""C:\Visual Studio Projects\PeCa-IMAS7651\core\win32\lib\Debug""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/PeerCast.pdb"
+ SubSystem="2"
+ HeapReserveSize="4194304"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/Simple.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ Description="Copy exe to program files"
+ CommandLine="copy debug\peercast.exe "c:\program files\peercast""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="chkMemoryLeak.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="gui.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\identify_encoding.c"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Simple.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="Simple.rc"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="StdAfx.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="stdafx.h"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\utf8.c"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="chkMemoryLeak.h"
+ >
+ </File>
+ <File
+ RelativePath="gui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\identify_encoding.h"
+ >
+ </File>
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ <File
+ RelativePath="Simple.h"
+ >
+ </File>
+ <File
+ RelativePath="StdAfx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\core\common\utf8.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="Simple.ico"
+ >
+ </File>
+ <File
+ RelativePath="small.ico"
+ >
+ </File>
+ <File
+ RelativePath="small1.ico"
+ >
+ </File>
+ <File
+ RelativePath="small3.ico"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Linux"
+ >
+ <File
+ RelativePath="..\..\linux\main.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\linux\makefile"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="OSX"
+ >
+ <File
+ RelativePath="..\..\osx\main.cpp"
+ >
+ <FileConfiguration
+ Name="Private Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Private Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\osx\makefile"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = "relative:ui\\win32\\simple"
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
+}
--- /dev/null
+// stdafx.cpp : source file that includes just the standard includes
+// Simple.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
+
--- /dev/null
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
+#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+// Local Header Files
+
+// TODO: reference additional headers your program requires here
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_)
--- /dev/null
+#ifdef _DEBUG
+//#include "stdafx.h"
+#include "chkMemoryLeak.h"
+
+#ifdef __AFXWIN_H__ // MFC\82Ì\83E\83B\83\93\83h\83E\82ð\8eg\82¤\8fê\8d\87\82É\8cÀ\92è\82µ\82Ä\82¢\82Ü\82·
+#else
+ #if defined(_DEBUG)
+ #define __chkMemoryLeak_H__
+ void* operator new(size_t size, const char *filename, int linenumber)
+ {
+ return _malloc_dbg(size, _NORMAL_BLOCK, filename, linenumber);
+ }
+ void operator delete(void * _P, const char *filename, int linenumber)
+ {
+ _free_dbg(_P, _NORMAL_BLOCK);
+ return;
+ }
+
+ #endif
+#endif
+#endif
--- /dev/null
+#ifndef _CHKMEMORYLEAK_H
+#define _CHKMEMORYLEAK_H
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef _DEBUG
+ #define _CRTDBG_MAP_ALLOC
+
+ #define SET_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+ #define CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+
+ void* operator new(size_t size, const char *filename, int linenumber);
+ void operator delete(void * _P, const char *filename, int linenumber);
+#else
+ #define SET_CRT_DEBUG_FIELD(a) ((void) 0)
+ #define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
+#endif
+
+#include <crtdbg.h>
+
+#include <malloc.h>
+
+#endif
--- /dev/null
+// ------------------------------------------------
+// File : gui.cpp
+// Date: 4-apr-2002
+// Author: giles
+// Desc:
+// Windows front end GUI, PeerCast core is not dependant on any of this.
+// Its very messy at the moment, but then again Windows UI always is.
+// I really don`t like programming win32 UI.. I want my borland back..
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#define _WIN32_WINNT 0x0500
+
+#include <windows.h>
+#include "stdio.h"
+#include "string.h"
+#include "stdarg.h"
+#include "resource.h"
+#include "socket.h"
+#include "win32/wsys.h"
+#include "servent.h"
+#include "win32/wsocket.h"
+#include "inifile.h"
+#include "gui.h"
+#include "servmgr.h"
+#include "peercast.h"
+#include "simple.h"
+#include "gdiplus.h"
+#include "commctrl.h"
+#include "locale.h"
+#include "stats.h"
+#include "socket.h"
+#include "wininet.h"
+#ifdef _DEBUG
+#include "chkMemoryLeak.h"
+#define DEBUG_NEW new(__FILE__, __LINE__)
+#define new DEBUG_NEW
+#endif
+
+ThreadInfo guiThread;
+bool shownChannels=false;
+WINDOWPLACEMENT winPlace;
+bool guiFlg = false;
+
+using namespace Gdiplus;
+
+#include <comdef.h>
+
+void APICALL MyPeercastApp ::printLog(LogBuffer::TYPE t, const char *str)
+{
+/* ADDLOG(str,logID,true,NULL,t);
+ if (logFile.isOpen())
+ {
+ logFile.writeLine(str);
+ logFile.flush();
+ }*/
+}
+
+void APICALL MyPeercastApp::updateSettings()
+{
+// setControls(true);
+}
+
+Gdiplus::Bitmap bmpBack(800,600,PixelFormat24bppRGB);
+UINT backWidth;
+UINT backHeight;
+
+Gdiplus::Image *backImage;
+Gdiplus::Bitmap *backBmp;
+Gdiplus::Graphics *backGra;
+
+Gdiplus::Image *img_idle;
+Gdiplus::Image *img_connect;
+Gdiplus::Image *img_conn_ok;
+Gdiplus::Image *img_conn_full;
+Gdiplus::Image *img_conn_over;
+Gdiplus::Image *img_conn_ok_skip;
+Gdiplus::Image *img_conn_full_skip;
+Gdiplus::Image *img_conn_over_skip;
+Gdiplus::Image *img_error;
+Gdiplus::Image *img_broad_ok;
+Gdiplus::Image *img_broad_full;
+
+UINT winWidth=0;
+UINT winHeight=0;
+
+static HWND hTree;
+extern HINSTANCE hInst;
+extern HWND guiWnd;
+extern Stats stats;
+
+WLock sd_lock;
+WLock ChannelDataLock;
+WLock MakeBackLock;
+ChannelData *channelDataTop = NULL;
+
+extern bool gbGetFile;
+extern bool gbStart;
+extern time_t gtGetFile;
+extern time_t gtStartTime;
+ThreadInfo gtiStart;
+ThreadInfo gtiGetFile;
+static char *data1URL = "http://www.idolmaster.jp/download/images/wallpaper/imas360p_800.jpg";
+static char *data2URL = "http://www.xbox.com/NR/rdonlyres/CAB05E2F-3051-409B-A4C8-830167C1C138/0/wpr0701idolmasterw120001.jpg";
+HWND ghStart;
+
+bool gbDispTop = false;
+bool gbAllOpen = false;
+
+THREAD_PROC FestivalStart(ThreadInfo *thread);
+
+THREAD_PROC GetHostName(ThreadInfo *thread){
+ IdData *id = (IdData*)(thread->data);
+
+ HOSTENT *he;
+ unsigned int ip;
+ bool flg = TRUE;
+
+ ChannelDataLock.on();
+ ip = htonl(id->getIpAddr());
+
+ for (int i=0; i<5 && flg; i++){
+ he = gethostbyaddr((char *)&ip,sizeof(ip),AF_INET);
+
+ ChannelData* cd = channelDataTop;
+ if (he)
+ {
+ while(cd){
+ if (cd->setName(id->getServentId(), he->h_name)){
+ flg = FALSE;
+ break;
+ }
+ cd = cd->getNextData();
+ }
+ }
+// ::delete id;
+ ChannelDataLock.off();
+ sys->sleep(1000);
+ }
+
+
+ return 0;
+}
+
+bool DownloadFile(LPCTSTR URL, LPCTSTR local){
+ char header[] = "Accept: */*\r\n\r\n";
+ char buf[4096];
+
+ FileStream f;
+ HINTERNET hInternet;
+ HINTERNET hConnect;
+
+ try{
+ f.openWriteReplace(local);
+ }catch(StreamException &e){
+ return false;
+ }
+
+ hInternet = ::InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
+ if (hInternet == NULL){
+ return false;
+ }
+
+ hConnect = ::InternetOpenUrl(hInternet, URL, header, strlen(header), INTERNET_FLAG_DONT_CACHE, 0);
+ if (hConnect == NULL){
+ ::InternetCloseHandle(hInternet);
+ return false;
+ }
+
+ while(1){
+ sys->sleep(0);
+ DWORD dwReadSize;
+ BOOL ret = ::InternetReadFile(hConnect, buf, 4096, &dwReadSize);
+ if (ret){
+ if (dwReadSize == 0){
+ break;
+ }
+ try{
+ f.write(buf, dwReadSize);
+ continue;
+ } catch(StreamException e){
+ }
+ f.close();
+ ::InternetCloseHandle(hConnect);
+ ::InternetCloseHandle(hInternet);
+ return false;
+ }
+ }
+
+ f.flush();
+ f.close();
+ ::InternetCloseHandle(hConnect);
+ ::InternetCloseHandle(hInternet);
+
+ return true;
+}
+
+THREAD_PROC GetInternetFile(ThreadInfo *thread){
+
+ DownloadFile(data1URL, "data1.jpg");
+ DownloadFile(data2URL, "data2.jpg");
+ return 0;
+}
+
+extern TCHAR szWindowClass3[]; // The title bar text
+
+
+int drawSpeed(Graphics *gra, int posX, int posY){
+
+ // \91¬\93x\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82\82·\82é
+ SolidBrush b(Color(180,255,255,255));
+ backGra->FillRectangle(&b, posX, posY, 200, 14);
+ // \83t\83H\83\93\83g\90Ý\92è
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",10);
+ // \95¶\8e\9a\90F
+ SolidBrush strBrush(Color::Black);
+ // \95¶\8e\9a\97ñ\8dì\90¬
+ char tmp[256];
+ sprintf(tmp, "R:%.1fkbps S:%.1fkbps",
+ BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)),
+ BYTES_TO_KBPS(stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT)));
+ _bstr_t bstr(tmp);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ StringFormat format;
+ format.SetAlignment(StringAlignmentCenter);
+ RectF r((REAL)posX, (REAL)posY, (REAL)200, (REAL)14);
+ // \95¶\8e\9a\95`\89æ
+ gra->DrawString(bstr, -1, &font, r, &format, &strBrush);
+
+
+
+ return posY + 15;
+}
+
+void MakeBack(HWND hwnd, UINT x, UINT y){
+ MakeBackLock.on();
+
+ winWidth = x;
+ winHeight = y;
+
+ if (backGra){
+ ::delete backBmp;
+ ::delete backGra;
+ }
+
+ backBmp = ::new Bitmap(x,y);
+ backGra = ::new Graphics(backBmp);
+
+ // \91S\82Ä\94\92\82Å\93h\82è\82Â\82Ô\82µ
+ SolidBrush b(Color(255,255,255,255));
+ backGra->FillRectangle(&b, 0, 0, x, y);
+
+ backWidth = backImage->GetWidth();
+ backHeight = backImage->GetHeight();
+
+ // \94w\8ci\89æ\91\9c\82ð\95`\89æ
+ for (UINT xx = 0; xx < x/backWidth + 1; xx++){
+ for (UINT yy = 0; yy < y/backHeight + 1; yy++){
+ UINT width,height;
+ if (backWidth*(xx+1) > x){
+ width = x % backWidth;
+ } else {
+ width = backWidth;
+ }
+ if (backHeight*(yy+1) > y){
+ height = y % backHeight;
+ } else {
+ height = backHeight;
+ }
+ Rect r((INT)backWidth*xx, (INT)backHeight*yy, width, height);
+ backGra->DrawImage(backImage, r, 0, 0, (INT)width, (INT)height, UnitPixel);
+ }
+ }
+
+ INT posX = 20;
+ INT posY = 20;
+
+ // \91¬\93x\95`\89æ
+ drawSpeed(backGra, winWidth-205, 5);
+
+ // \83`\83\83\83\93\83l\83\8b\8fî\95ñ\82ð\95`\89æ
+ ChannelDataLock.on();
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ posY = cd->drawChannel(backGra, 20, posY);
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ MakeBackLock.off();
+}
+
+void MakeBack(HWND hwnd){
+ MakeBack(hwnd, winWidth, winHeight);
+ ::InvalidateRect(guiWnd, NULL, FALSE);
+}
+
+void ChannelData::setData(Channel *c){
+ String sjis;
+ sjis = c->getName();
+ sjis.convertTo(String::T_SJIS);
+
+ strncpy(name, sjis, 256);
+ name[256] = '\0';
+ channel_id = c->channel_id;
+ bitRate = c->info.bitrate;
+ lastPlayStart = c->info.lastPlayStart;
+ status = c->status;
+ totalListeners = c->totalListeners();
+ totalRelays = c->totalRelays();
+ localListeners = c->localListeners();
+ localRelays = c->localRelays();
+ stayConnected = c->stayConnected;
+ chDisp = c->chDisp;
+ bTracker = c->sourceHost.tracker;
+ lastSkipTime = c->lastSkipTime;
+ skipCount = c->skipCount;
+}
+
+int gW = 0;
+int gWS = 0;
+
+int ChannelData::drawChannel(Graphics *g, int x, int y){
+ REAL xx = x * 1.0f;
+ REAL yy = y * 1.0f;
+ ServentData* sd;
+
+ // \88Ê\92u\82ð\95Û\91¶
+ posX = x;
+ posY = y;
+
+ int w,h;
+
+ if (getWidth() == 0){
+ if (gW){
+ w = gW;
+ } else {
+ w = 400;
+ }
+ } else {
+ w = getWidth();
+ gW = w;
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+ if (isSelected()){
+ // \91I\91ð\92\86
+ SolidBrush b(Color(160,49,106,197));
+ g->FillRectangle(&b, x, y, w, 14);
+ } else {
+ // \94ñ\91I\91ð
+ SolidBrush b(Color(160,255,255,255));
+ g->FillRectangle(&b, x, y, w, 14);
+ }
+
+ // \83X\83e\81[\83^\83X\95\\8e¦
+ Gdiplus::Image *img = NULL;
+ unsigned int nowTime = sys->getTime();
+ switch(this->getStatus()){
+ case Channel::S_IDLE:
+ img = img_idle;
+ break;
+ case Channel::S_SEARCHING:
+ case Channel::S_CONNECTING:
+ img = img_connect;
+ break;
+ case Channel::S_RECEIVING:
+ if ((skipCount > 2) && (lastSkipTime + 120 > nowTime)){
+ if (chDisp.relay){
+ img = img_conn_ok_skip;
+ } else {
+ if (chDisp.numRelays){
+ img = img_conn_full_skip;
+ } else {
+ img = img_conn_over_skip;
+ }
+ }
+ } else {
+ if (chDisp.relay){
+ img = img_conn_ok;
+ } else {
+ if (chDisp.numRelays){
+ img = img_conn_full;
+ } else {
+ img = img_conn_over;
+ }
+ }
+ }
+ break;
+ case Channel::S_BROADCASTING:
+ img = img_broad_ok;
+ break;
+ case Channel::S_ERROR:
+ img = img_error;
+ break;
+ default:
+ img = img_idle;
+ break;
+ }
+ // \95`\89æ\8aî\93_
+ PointF origin(xx, yy);
+ // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+ Rect img_rect((INT)origin.X, (INT)origin.Y + 1, img ? img->GetWidth() : 12, 12);
+ // \83X\83e\81[\83^\83X\95`\89æ
+ ImageAttributes att;
+// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+ g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += img_rect.Width;
+
+ // \83t\83H\83\93\83g\90Ý\92è
+ Gdiplus::Font font(L"\82l\82r \82o\83S\83V\83b\83N",10);
+ // \95¶\8e\9a\90F
+ SolidBrush *strBrush;
+ if (servMgr->getFirewall() == ServMgr::FW_ON){
+ strBrush = ::new SolidBrush(Color::Red);
+ } else if (isTracker() && (getStatus() == Channel::S_RECEIVING)){
+ strBrush = ::new SolidBrush(Color::Green);
+ } else {
+ if (isSelected()){
+ // \91I\91ð\92\86
+ strBrush = ::new SolidBrush(Color::White);
+ } else {
+ // \94ñ\91I\91ð
+ strBrush = ::new SolidBrush(Color::Black);
+ }
+ }
+ // \83`\83\83\83\93\83l\83\8b\96¼\95\\8e¦
+ g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ _bstr_t bstr1(getName());
+ // \95¶\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+ RectF r1(origin.X, origin.Y, 120.0f, 13.0f);
+ StringFormat format;
+ format.SetAlignment(StringAlignmentNear);
+ g->DrawString(bstr1, -1, &font, r1, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r1.Width;
+
+ // \83\8a\83X\83i\81[\90\94/\83\8a\83\8c\81[\90\94\95\\8e¦
+ char tmp[256];
+ sprintf(tmp, "%d/%d - [%d/%d]", getTotalListeners(), getTotalRelays(), getLocalListeners(), getLocalRelays());
+ _bstr_t bstr2(tmp);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ RectF r2(origin.X, origin.Y, 100.0f, 13.0f);
+ format.SetAlignment(StringAlignmentCenter);
+ g->DrawString(bstr2, -1, &font, r2, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r2.Width;
+
+ // bps\95\\8e¦
+ Font *f;
+ if (isStayConnected()){
+ f = ::new Font(L"Arial", 9.0f, FontStyleItalic|FontStyleBold, UnitPoint);
+ } else {
+ f = ::new Font(L"Arial", 9.0f);
+ }
+ sprintf(tmp, "%dkbps", getBitRate());
+ _bstr_t bstr3(tmp);
+ format.SetAlignment(StringAlignmentFar);
+ // \95¶\8e\9a\95\\8e¦\94Í\88Í\8ew\92è
+ RectF r3(origin.X, origin.Y, 80.0f, 13.0f);
+ g->DrawString(bstr3, -1, f, r3, &format, strBrush);
+ // \83t\83H\83\93\83g\8aJ\95ú
+ ::delete f;
+
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r3.Width;
+
+ // \83u\83\89\83V\8dí\8f\9c
+ ::delete strBrush;
+
+
+ // Servent\95\\8e¦
+ if (!openFlg){
+ int count = getServentCount();
+ // Servent\95\\8e¦\95\94\82Ì\94w\8ci\82ð\94\92\82É\82·\82é
+ SolidBrush b(Color(160,255,255,255));
+ g->FillRectangle(&b, (INT)origin.X, (INT)origin.Y, 14*count, 14);
+
+ sd = serventDataTop;
+ int index = 0;
+ while(sd){
+ SolidBrush *serventBrush;
+ if (sd->getInfoFlg()){
+ ChanHit *hit = sd->getChanHit();
+ if (hit->firewalled){
+ SolidBrush bb(Color(180,255,0,0));
+ g->FillRectangle(&bb, (INT)origin.X + 14*index, (INT)origin.Y, 14, 14);
+ }
+ if (hit->relay){
+ // \83\8a\83\8c\81[\82n\82j
+ serventBrush = ::new SolidBrush(Color::Green);
+ } else {
+ // \83\8a\83\8c\81[\95s\89Â
+ if (hit->numRelays){
+ // \83\8a\83\8c\81[\88ê\94t
+ serventBrush = ::new SolidBrush(Color::Blue);
+ } else {
+ // \83\8a\83\8c\81[\82È\82µ
+ serventBrush = ::new SolidBrush(Color::Purple);
+ }
+ }
+ } else {
+ // \8fî\95ñ\82È\82µ
+ serventBrush = ::new SolidBrush(Color::Black);
+ }
+ // \8el\8ap\95`\89æ
+ backGra->FillRectangle(serventBrush, (INT)origin.X + index*14 + 1, (INT)origin.Y + 1, 12, 12);
+
+ ::delete serventBrush;
+ sd = sd->getNextData();
+ index++;
+ }
+ }
+
+ // \8e\9f\82Ì\8aî\93_
+ origin.Y += 15;
+
+ // \83T\83C\83Y\82ð\95Û\91¶
+ setWidth((int)origin.X - posX);
+ setHeight((int)origin.Y - posY);
+
+ // ServentData\95\\8e¦
+ sd = serventDataTop;
+ while(sd){
+ if (openFlg || sd->getSelected()){
+ sd->drawServent(g, (INT)x+12, (INT)origin.Y);
+ // \8e\9f\82Ì\8aî\93_
+ origin.Y += 15;
+ }
+ sd = sd->getNextData();
+ }
+
+
+ return (int)(origin.Y);
+}
+
+bool ChannelData::checkDown(int x,int y){
+ // \94Í\88Í\93à\83`\83F\83b\83N
+ if (
+ (x > posX)
+ && (x < posX + getWidth())
+ && (y > posY)
+ && (y < posY + getHeight())
+ ){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+ServentData *ChannelData::findServentData(int servent_id){
+ ServentData *sv = serventDataTop;
+ while(sv){
+ if (sv->getServentId() == servent_id){
+ return sv;
+ }
+ sv = sv->getNextData();
+ }
+ return NULL;
+}
+
+void ChannelData::addServentData(ServentData *sd){
+ sd->setNextData(serventDataTop);
+ serventDataTop = sd;
+}
+
+void ChannelData::deleteDisableServents(){
+ ServentData *sd = serventDataTop;
+ ServentData *prev = NULL;
+
+ while(sd){
+ if (!(sd->getEnableFlg())){
+ ServentData *next = sd->getNextData();
+ if (prev){
+ prev->setNextData(next);
+ } else {
+ serventDataTop = next;
+ }
+ ::delete sd;
+ sd = next;
+ } else {
+ prev = sd;
+ sd = sd->getNextData();
+ }
+ }
+}
+
+int ChannelData::getServentCount(){
+ int ret = 0;
+
+ ServentData *sd = serventDataTop;
+ while(sd){
+ ret++;
+ sd = sd->getNextData();
+ }
+ return ret;
+}
+
+bool ChannelData::setName(int servent_id, String name){
+ ServentData *sd = serventDataTop;
+ while(sd){
+ if (sd->getServentId() == servent_id){
+ sd->setName(name);
+ return TRUE;
+ }
+ sd = sd->getNextData();
+ }
+ return FALSE;
+}
+
+void ServentData::setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool f){
+ servent_id = s->servent_id;
+ type = s->type;
+ status = s->status;
+ lastSkipTime = s->lastSkipTime;
+ host = s->getHost();
+
+ chanHit.numRelays = hit->numRelays;
+ chanHit.relay = hit->relay;
+ chanHit.firewalled = hit->firewalled;
+ chanHit.version = hit->version;
+ chanHit.version_vp = hit->version_vp;
+ chanHit.version_ex_number = hit->version_ex_number;
+ chanHit.version_ex_prefix[0] = hit->version_ex_prefix[0];
+ chanHit.version_ex_prefix[1] = hit->version_ex_prefix[1];
+
+ totalListeners = listeners;
+ totalRelays = relays;
+
+ infoFlg = f;
+}
+
+int ServentData::drawServent(Gdiplus::Graphics *g, int x, int y){
+ REAL xx = x * 1.0f;
+ REAL yy = y * 1.0f;
+ int w,h;
+
+ // \88Ê\92u\82ð\95Û\91¶
+ posX = x;
+ posY = y;
+
+ if (getWidth() == 0){
+ if (gWS){
+ w = gWS;
+ } else {
+ w = 400;
+ }
+ } else {
+ w = getWidth();
+ gWS = w;
+ }
+
+ // \95`\89æ\8aî\93_
+ PointF origin(xx, yy);
+
+ // \83t\83H\83\93\83g\90Ý\92è
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",9);
+ // \95¶\8e\9a\90F
+ SolidBrush *strBrush;
+ if (chanHit.firewalled){
+ strBrush = ::new SolidBrush(Color::Red);
+ } else {
+ if (getSelected()){
+ // \91I\91ð\92\86
+ strBrush = ::new SolidBrush(Color::White);
+ } else {
+ // \94ñ\91I\91ð
+ strBrush = ::new SolidBrush(Color::Black);
+ }
+ }
+ // ServantData\95\\8e¦
+ g->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ // \95¶\8e\9a\97ñ\8dì\90¬
+ char tmp[256];
+ char host1[256];
+ host.toStr(host1);
+
+ if (infoFlg){
+ if (chanHit.version_ex_number){
+ // \8ag\92£\83o\81[\83W\83\87\83\93
+ sprintf(tmp, "%c%c%04d - %d/%d - %s(%s)",
+ chanHit.version_ex_prefix[0],
+ chanHit.version_ex_prefix[1],
+ chanHit.version_ex_number,
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ } else if (chanHit.version_vp){
+ sprintf(tmp, "VP%04d - %d/%d - %s(%s)",
+ chanHit.version_vp,
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ } else {
+ sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ }
+ } else {
+ sprintf(tmp, "(-----) - %d/%d - %s(%s)",
+ totalListeners,
+ totalRelays,
+ host1,
+ hostname.cstr()
+ );
+ }
+ _bstr_t bstr1(tmp);
+
+ // \83X\83e\81[\83^\83X\95\\8e¦
+ Gdiplus::Image *img = NULL;
+ unsigned int nowTime = sys->getTime();
+ switch(getStatus()){
+ case Servent::S_CONNECTING:
+ img = img_connect;
+ break;
+ case Servent::S_CONNECTED:
+ if (lastSkipTime + 120 > nowTime){
+ if (chanHit.relay){
+ img = img_conn_ok_skip;
+ } else {
+ if (chanHit.numRelays){
+ img = img_conn_full_skip;
+ } else {
+ img = img_conn_over_skip;
+ }
+ }
+ } else {
+ if (chanHit.relay){
+ img = img_conn_ok;
+ } else {
+ if (chanHit.numRelays){
+ img = img_conn_full;
+ } else {
+ img = img_conn_over;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // \95¶\8e\9a\95`\89æ\94Í\88Í\8ew\92è
+ RectF r1(origin.X + img->GetWidth() + 2, origin.Y, 800.0f, 13.0f);
+ RectF r2;
+ StringFormat format;
+ format.SetAlignment(StringAlignmentNear);
+ g->MeasureString(bstr1, -1, &font, r1, &format, &r2);
+
+ w = (INT)r2.Width + img->GetWidth() + 2;
+ // ServentData\95\\8e¦\95\94\82Ì\94w\8ci\82ð\93h\82é
+ if (getSelected()){
+ // \91I\91ð\92\86
+ SolidBrush b(Color(160,49,106,197));
+ g->FillRectangle(&b, x, y, w, 13);
+ } else {
+ // \94ñ\91I\91ð
+ SolidBrush b(Color(160,200,200,200));
+ g->FillRectangle(&b, x, y, w, 13);
+ }
+
+ // \83X\83e\81[\83^\83X\95\\8e¦\88Ê\92u
+ Rect img_rect((INT)origin.X, (INT)origin.Y+1, img ? img->GetWidth() : 12, 12);
+ // \83X\83e\81[\83^\83X\95`\89æ
+ ImageAttributes att;
+// att.SetColorKey(Color::White, Color::White, ColorAdjustTypeBitmap);
+ g->DrawImage(img, img_rect, 0, 0, img_rect.Width, 12, UnitPixel, &att);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += 12;
+
+ g->DrawString(bstr1, -1, &font, r2, &format, strBrush);
+ // \8e\9f\82Ì\8aî\93_
+ origin.X += r2.Width;
+ origin.Y += 13;
+
+ setWidth((int)origin.X-posX);
+ setHeight((int)origin.Y - posY);
+
+ ::delete strBrush;
+ return 0;
+}
+
+bool ServentData::checkDown(int x, int y){
+ if (
+ (x > posX)
+ && (x < posX + getWidth())
+ && (y > posY)
+ && (y < posY + getHeight())
+ ){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+THREAD_PROC GUIDataUpdate(ThreadInfo *thread){
+ int i;
+
+ // set GUI thread status to running
+ thread->finish = false;
+
+ while(thread->active){
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83\8d\83b\83N
+ ChannelDataLock.on();
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82Ì\8dX\90V\83t\83\89\83O\82ð\91S\82ÄFALSE\82É\82·\82é
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ // Servent\82Ì\8dX\90V\83t\83\89\83O\82ðFALSE\82É\82·\82é
+ ServentData *sv = cd->getServentDataTop();
+ while(sv){
+ sv->setEnableFlg(FALSE);
+ sv = sv->getNextData();
+ }
+ cd->setEnableFlg(FALSE);
+ cd = cd->getNextData();
+ }
+
+ Channel *c = chanMgr->channel;
+ // \8c»\8dÝ\91¶\8dÝ\82·\82é\83`\83\83\83\93\83l\83\8b\95ª\83\8b\81[\83v
+ while(c){
+ // \8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\8e\9d\82Á\82Ä\82¢\82é\82©
+ cd = channelDataTop;
+ // \94\8c©\83t\83\89\83OFALSE
+ bool bFoundFlg = FALSE;
+ while(cd){
+ if (cd->getChannelId() == c->channel_id){
+ //\8aù\82É\83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ª\82 \82é\82Ì\82Å\81A\82»\82Ì\82Ü\82Ü\8dX\90V
+ cd->setData(c);
+ // \8dX\90V\83t\83\89\83OTRUE
+ cd->setEnableFlg(TRUE);
+ // \94\8c©\83t\83\89\83OTRUE
+ bFoundFlg = TRUE;
+ // \83\8b\81[\83v\97£\92E
+ break;
+ }
+ // \8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87\81A\8e\9f\82Ì\83f\81[\83^\82ð\83`\83F\83b\83N
+ cd = cd->getNextData();
+ }
+
+ // \90V\82µ\82¢\83`\83\83\83\93\83l\83\8b\82Ì\8fê\8d\87\81A\90V\8bK\83f\81[\83^\8dì\90¬
+ if (!bFoundFlg){
+ // \90V\8bK\83f\81[\83^\8dì\90¬
+ cd = ::new ChannelData();
+ // \83f\81[\83^\8dX\90V
+ cd->setData(c);
+ // \8dX\90V\83t\83\89\83OTRUE
+ cd->setEnableFlg(TRUE);
+
+ // \90V\8bK\83f\81[\83^\82ð\83\8a\83X\83g\82Ì\90æ\93ª\82É\93ü\82ê\82é
+ cd->setNextData(channelDataTop);
+ channelDataTop = cd;
+ }
+ // \8e\9f\82Ì\83`\83\83\83\93\83l\83\8b\82ð\8eæ\93¾
+ c = c->next;
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\82ª\82È\82\82È\82Á\82Ä\82¢\82é\8fê\8d\87\82Ì\8f\88\97\9d
+ cd = channelDataTop;
+ ChannelData *prev = NULL;
+ while(cd){
+ // \83f\81[\83^\82ð\8dX\90V\82µ\82È\82©\82Á\82½\82©
+ if (cd->getEnableFlg() == FALSE){
+ // \83`\83\83\83\93\83l\83\8b\82ª\82È\82\82È\82Á\82Ä\82¢\82é\82Ì\82Å\8dí\8f\9c
+ ChannelData *next;
+ next = cd->getNextData();
+ if (!prev){
+ // \90æ\93ª\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+ channelDataTop = next;
+ } else {
+ // \93r\92\86\82Ì\83f\81[\83^\82ð\8dí\8f\9c
+ prev->setNextData(next);
+ }
+ // \8e\9f\82Ì\83f\81[\83^\82Ö
+ cd = next;
+ } else {
+ // \83f\81[\83^\8dX\90V\8dÏ\81F\8e\9f\82Ì\83f\81[\83^\82Ö
+ prev = cd;
+ cd = cd->getNextData();
+ }
+ }
+
+ Servent *s = servMgr->servents;
+ while(s){
+ // \8f\89\8aú\89»
+ ChanHitList *chl;
+ bool infoFlg = false;
+ bool relay = true;
+ bool firewalled = false;
+ unsigned int numRelays = 0;
+ int vp_ver = 0;
+ char ver_ex_prefix[2] = {' ',' '};
+ int ver_ex_number = 0;
+ // \92¼\89º\83z\83X\83g\8fî\95ñ\83`\83F\83b\83N
+ unsigned int totalRelays = 0;
+ unsigned int totalListeners = 0;
+
+ ChanHit hitData;
+ // \8eó\90M\92\86\82©
+ if ((s->type == Servent::T_RELAY) && (s->status == Servent::S_CONNECTED)){
+ // \83z\83X\83g\8fî\95ñ\83\8d\83b\83N
+ chanMgr->hitlistlock.on();
+ // \92¼\89º\83z\83X\83g\82ª\8eó\90M\82µ\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\8eæ\93¾
+ chl = chanMgr->findHitListByID(s->chanID);
+ // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\82©
+ if (chl){
+ // \83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ª\82 \82é\8fê\8d\87
+ ChanHit *hit = chl->hit;
+ //\81@\83`\83\83\83\93\83l\83\8b\82Ì\83z\83X\83g\8fî\95ñ\82ð\91S\91\96\8d¸\82µ\82Ä
+ while(hit){
+ // ID\82ª\93¯\82¶\82à\82Ì\82Å\82 \82ê\82Î
+ if (hit->servent_id == s->servent_id){
+ // \83g\81[\83^\83\8b\83\8a\83\8c\81[\82Æ\83g\81[\83^\83\8b\83\8a\83X\83i\81[\82ð\89Á\8eZ
+ totalRelays += hit->numRelays;
+ totalListeners += hit->numListeners;
+ // \92¼\89º\82Å\82 \82ê\82Î
+ if (hit->numHops == 1){
+ // \8fî\95ñ\82ð\88ê\92U\95Û\91¶
+ infoFlg = true;
+ hitData.relay = hit->relay;
+ hitData.firewalled = hit->firewalled;
+ hitData.numRelays = hit->numRelays;
+ hitData.version_vp = hit->version_vp;
+ hitData.version_ex_prefix[0] = hit->version_ex_prefix[0];
+ hitData.version_ex_prefix[1] = hit->version_ex_prefix[1];
+ hitData.version_ex_number = hit->version_ex_number;
+ }
+ }
+ // \8e\9f\82ð\83`\83F\83b\83N
+ hit = hit->next;
+ }
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82©\82çServent\82ð\8c\9f\8dõ
+ bool bFoundFlg = FALSE;
+ cd = channelDataTop;
+ while(cd){
+ ServentData *sv = cd->findServentData(s->servent_id);
+ // ServentData\82ª\82 \82ê\82Î
+ if (sv){
+ // \83f\81[\83^\90Ý\92è
+ sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+ sv->setEnableFlg(TRUE);
+ bFoundFlg = TRUE;
+ break;
+ }
+ cd = cd->getNextData();
+ }
+ // ServentData\82ª\8c©\82Â\82©\82ç\82È\82©\82Á\82½\8fê\8d\87
+ if (!bFoundFlg){
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ð\92T\82·
+ cd = channelDataTop;
+ while(cd){
+ // \83`\83\83\83\93\83l\83\8bID\82ª\93¯\82¶\82©
+ if (cd->getChannelId() == s->channel_id){
+ // \83f\81[\83^\90Ý\92è
+ ServentData *sv = ::new ServentData();
+ sv->setData(s, &hitData, totalListeners, totalRelays, infoFlg);
+ sv->setEnableFlg(TRUE);
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\82ÉServentData\92Ç\89Á
+ cd->addServentData(sv);
+ // \83z\83X\83g\96¼\82ð\8eæ\93¾\82·\82é
+ IdData *id = ::new IdData(cd->getChannelId(), sv->getServentId(), sv->getHost().ip);
+ ThreadInfo t;
+ t.func = GetHostName;
+ t.data = (void*)id;
+ sys->startThread(&t);
+ // \83\8b\81[\83v\8fI\97¹
+ break;
+ }
+ // \8e\9f\82Ì\83f\81[\83^\82Ö
+ cd = cd->getNextData();
+ }
+ }
+ // \83z\83X\83g\8fî\95ñ\83A\83\93\83\8d\83b\83N
+ chanMgr->hitlistlock.off();
+ }
+ s = s->next;
+ }
+
+ // \8dX\90V\82µ\82Ä\82¢\82È\82¢ServentData\82ð\8dí\8f\9c
+ cd = channelDataTop;
+ while(cd){
+ cd->deleteDisableServents();
+ cd = cd->getNextData();
+ }
+
+ // \83`\83\83\83\93\83l\83\8b\83f\81[\83^\83A\83\93\83\8d\83b\83N
+ ChannelDataLock.off();
+
+ // \95`\89æ\8dX\90V
+ if (guiWnd){
+ MakeBack(guiWnd);
+ }
+
+ // 0.1\95b\81~10\82Å1\95b\91Ò\82¿
+ for(i=0; i<10; i++)
+ {
+ if (!thread->active)
+ break;
+ sys->sleep(100);
+ }
+
+ if (gbGetFile && (sys->getTime() > gtGetFile)){
+ gbGetFile = false;
+ gtiGetFile.func = GetInternetFile;
+ gtiGetFile.data = NULL;
+ sys->startThread(>iGetFile);
+ }
+ else if (gbStart && (sys->getTime() > gtStartTime)){
+ gbStart = false;
+ SendMessage(guiWnd, WM_START, 0, 0);
+ gtiStart.func = FestivalStart;
+ gtiStart.data = NULL;
+ sys->startThread(>iStart);
+ }
+ }
+
+ // set GUI thread status to terminated
+ thread->finish = true;
+
+ return 0;
+}
+
+ChannelData *findChannelData(int channel_id){
+ ChannelData *cd = channelDataTop;
+
+ while(cd){
+ if (cd->getChannelId() == channel_id){
+ return cd;
+ }
+ cd = cd->getNextData();
+ }
+
+ return NULL;
+}
+
+
+void PopupChannelMenu(int channel_id){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ ChannelData *cd = findChannelData(channel_id);
+
+ if (cd == NULL){
+ return;
+ }
+
+ info.wID = 1001;
+ info.dwTypeData = "\90Ø\92f";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ info.wID = 1000;
+ info.dwTypeData = "\8dÄ\90¶";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ info.wID = 1002;
+ info.dwTypeData = "\8dÄ\90Ú\91±";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ info.wID = 1003;
+ info.dwTypeData = "\83L\81[\83v";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!cd->getOpenFlg()){
+ info.wID = 1004;
+ info.dwTypeData = "\92¼\89º\95\\8e¦";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1005;
+ info.dwTypeData = "\92¼\89º\89B\95Á";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ cd = findChannelData(channel_id);
+
+ if (cd == NULL){
+ return;
+ }
+
+ Channel *c = chanMgr->findChannelByChannelID(channel_id);
+
+ if (c == NULL){
+ return;
+ }
+
+ switch(dwID){
+ case 1000: // \8dÄ\90¶
+ chanMgr->playChannel(c->info);
+ break;
+
+ case 1001: // \90Ø\92f
+ c->thread.active = false;
+ c->thread.finish = true;
+ break;
+
+ case 1002: // \8dÄ\90Ú\91±
+ c->bump = true;
+ break;
+
+ case 1003: // \83L\81[\83v
+ if (!c->stayConnected){
+ c->stayConnected = true;
+ } else {
+ c->stayConnected = false;
+ }
+ break;
+
+ case 1004: // \92¼\89º\95\\8e¦
+ cd->setOpenFlg(TRUE);
+ MakeBack(guiWnd);
+ break;
+
+ case 1005: // \92¼\89º\89B\95Á
+ cd->setOpenFlg(FALSE);
+ MakeBack(guiWnd);
+ break;
+ }
+}
+
+void PopupServentMenu(int servent_id){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ ServentData *sd = NULL;
+ ChannelData *cd = channelDataTop;
+ while(cd){
+ sd = cd->findServentData(servent_id);
+ if (sd){
+ break;
+ }
+ cd = cd->getNextData();
+ }
+
+ if (cd == NULL || sd == NULL){
+ return;
+ }
+
+ info.wID = 1001;
+ info.dwTypeData = "\90Ø\92f";
+ InsertMenuItem(hMenu, -1, true, &info);
+
+// InsertMenuItem(hMenu, -1, true, &separator);
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ cd = channelDataTop;
+ while(cd){
+ sd = cd->findServentData(servent_id);
+ if (sd){
+ break;
+ }
+ cd = cd->getNextData();
+ }
+
+ if (cd == NULL || sd == NULL){
+ return;
+ }
+
+ Servent *s = servMgr->findServentByServentID(servent_id);
+
+ if (s == NULL){
+ return;
+ }
+
+ switch(dwID){
+ case 1001: // \90Ø\92f
+ s->thread.active = false;
+ break;
+
+ }
+}
+
+void PopupOtherMenu(){
+ POINT pos;
+ MENUITEMINFO info, separator;
+ HMENU hMenu;
+ DWORD dwID;
+
+ hMenu = CreatePopupMenu();
+
+ memset(&separator, 0, sizeof(MENUITEMINFO));
+ separator.cbSize = sizeof(MENUITEMINFO);
+ separator.fMask = MIIM_ID | MIIM_TYPE;
+ separator.fType = MFT_SEPARATOR;
+ separator.wID = 8000;
+
+ memset(&info, 0, sizeof(MENUITEMINFO));
+ info.cbSize = sizeof(MENUITEMINFO);
+ info.fMask = MIIM_ID | MIIM_TYPE;
+ info.fType = MFT_STRING;
+
+ if (!gbDispTop){
+ info.wID = 1101;
+ info.dwTypeData = "\8dÅ\91O\96Ê\95\\8e¦";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1102;
+ info.dwTypeData = "\8dÅ\91O\96Ê\89ð\8f\9c";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!gbAllOpen){
+ info.wID = 1103;
+ info.dwTypeData = "\91S\92¼\89º\93W\8aJ";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1104;
+ info.dwTypeData = "\91S\92¼\89º\89B\95Á";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ InsertMenuItem(hMenu, -1, true, &separator);
+
+ if (!servMgr->autoServe){
+ info.wID = 1105;
+ info.dwTypeData = "\97L\8cø";
+ InsertMenuItem(hMenu, -1, true, &info);
+ } else {
+ info.wID = 1106;
+ info.dwTypeData = "\96³\8cø";
+ InsertMenuItem(hMenu, -1, true, &info);
+ }
+
+ GetCursorPos(&pos);
+ dwID = TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RETURNCMD, pos.x, pos.y, 0, guiWnd, NULL);
+
+ DestroyMenu(hMenu);
+
+ ChannelData *cd = channelDataTop;
+
+ switch(dwID){
+ case 1101: // \8dÅ\91O\96Ê\95\\8e¦
+ gbDispTop = true;
+ ::SetWindowPos(guiWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ break;
+
+ case 1102: // \8dÅ\91O\96Ê\89ð\8f\9c
+ gbDispTop = false;
+ ::SetWindowPos(guiWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ break;
+
+ case 1103: // \91S\92¼\89º\93W\8aJ
+ gbAllOpen = true;
+ while(cd){
+ cd->setOpenFlg(true);
+ cd = cd->getNextData();
+ }
+ break;
+
+ case 1104: // \91S\92¼\89º\89B\95Á
+ gbAllOpen = false;
+ while(cd){
+ cd->setOpenFlg(false);
+ cd = cd->getNextData();
+ }
+ break;
+
+ case 1105: // \97L\8cø
+ servMgr->autoServe = true;
+ break;
+
+ case 1106: // \96³\8cø
+ servMgr->autoServe = false;
+ break;
+
+ }
+}
+
+void WmCreateProc(HWND hwnd){
+ if (backImage){
+ ::delete backImage;
+ }
+ _bstr_t bstr("back.jpg");
+ backImage = ::new Image(bstr);
+
+ MakeBack(hwnd, 800, 600);
+
+ guiThread.func = GUIDataUpdate;
+ if (!sys->startThread(&guiThread)){
+ MessageBox(hwnd,"Unable to start GUI","PeerCast",MB_OK|MB_ICONERROR);
+ PostMessage(hwnd,WM_DESTROY,0,0);
+ }
+ if (guiFlg){
+ SetWindowPlacement(hwnd, &winPlace);
+ }
+
+ if (img_idle){
+ ::delete img_idle;
+ ::delete img_connect;
+ ::delete img_conn_ok;
+ ::delete img_conn_full;
+ ::delete img_conn_over;
+ ::delete img_conn_ok_skip;
+ ::delete img_conn_full_skip;
+ ::delete img_conn_over_skip;
+ ::delete img_error;
+ ::delete img_broad_ok;
+ ::delete img_broad_full;
+ }
+ bstr = L"ST_IDLE.bmp";
+ img_idle = ::new Image(bstr);
+ bstr = L"ST_CONNECT.bmp";
+ img_connect = ::new Image(bstr);
+ bstr = L"ST_CONN_OK.bmp";
+ img_conn_ok = ::new Image(bstr);
+ bstr = L"ST_CONN_FULL.bmp";
+ img_conn_full = ::new Image(bstr);
+ bstr = L"ST_CONN_OVER.bmp";
+ img_conn_over = ::new Image(bstr);
+ bstr = L"ST_CONN_OK_SKIP.bmp";
+ img_conn_ok_skip = ::new Image(bstr);
+ bstr = L"ST_CONN_FULL_SKIP.bmp";
+ img_conn_full_skip = ::new Image(bstr);
+ bstr = L"ST_CONN_OVER_SKIP.bmp";
+ img_conn_over_skip = ::new Image(bstr);
+ bstr = L"ST_ERROR.bmp";
+ img_error = ::new Image(bstr);
+ bstr = L"ST_BROAD_OK.bmp";
+ img_broad_ok = ::new Image(bstr);
+ bstr = L"ST_BROAD_FULL.bmp";
+ img_broad_full = ::new Image(bstr);
+}
+
+void WmPaintProc(HWND hwnd){
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ if (backGra){
+ MakeBackLock.on();
+ hdc = BeginPaint(hwnd, &paint);
+ RECT *rcRect; // \95`\89æ\94Í\88Í
+ rcRect = &(paint.rcPaint);
+ LONG width = rcRect->right - rcRect->left + 1;
+ LONG height = rcRect->bottom - rcRect->top + 1;
+
+ Graphics g2(hdc);
+ Rect r(rcRect->left, rcRect->top, width, height);
+ g2.DrawImage(backBmp,r, rcRect->left, rcRect->top, width, height, UnitPixel);
+ EndPaint(hwnd, &paint);
+ MakeBackLock.off();
+ }
+}
+
+void WmSizeProc(HWND hwnd, LPARAM lParam){
+ UINT width = LOWORD(lParam);
+ UINT height = HIWORD(lParam);
+
+ MakeBack(hwnd, width, height);
+
+}
+
+void WmLButtonDownProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+
+ ChannelDataLock.on();
+ cd = channelDataTop;
+ while(cd){
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(TRUE);
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+ int sx = cd->getPosX() + cd->getWidth();
+ int sy = cd->getPosY();
+ int index = 0;
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if ( ( (!cd->getOpenFlg())
+ && (sx + index*14 < x)
+ && (x < sx + (index+1)*14)
+ && (sy < y)
+ && (y < sy + 14) )
+ || sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+ ){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ index++;
+ }
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+}
+
+void WmLButtonDblclkProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+
+ ChannelDataLock.on();
+ cd = channelDataTop;
+ while(cd){
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ if (!(cd->getOpenFlg())){
+ changeFlg = TRUE;
+ cd->setOpenFlg(TRUE);
+ } else {
+ changeFlg = TRUE;
+ cd->setOpenFlg(FALSE);
+ }
+ cd->setSelected(TRUE);
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+/* int sx = cd->getPosX() + cd->getWidth();
+ int sy = cd->getPosY();
+ int index = 0;
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if ( ( (!cd->getOpenFlg())
+ && (sx + index*14 < x)
+ && (x < sx + (index+1)*14)
+ && (sy < y)
+ && (y < sy + 14) )
+ || sd->checkDown(LOWORD(lParam), HIWORD(lParam))
+ ){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ index++;
+ }*/
+ cd = cd->getNextData();
+ }
+ ChannelDataLock.off();
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+}
+
+void WmRButtonDownProc(HWND hwnd, LPARAM lParam){
+ ChannelData *cd;
+ bool changeFlg = FALSE;
+ bool channel_selected = FALSE;
+ bool servent_selected = FALSE;
+ int channel_id = 0;
+ int servent_id = 0;
+
+ cd = channelDataTop;
+ while(cd){
+ if (cd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!(cd->isSelected())){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(TRUE);
+ channel_id = cd->getChannelId();
+ channel_selected = TRUE;
+ } else {
+ if (cd->isSelected()){
+ changeFlg = TRUE;
+ }
+ cd->setSelected(FALSE);
+ }
+ ServentData *sd = cd->getServentDataTop();
+ while(sd){
+ if (sd->checkDown(LOWORD(lParam), HIWORD(lParam))){
+ if (!sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(TRUE);
+ servent_id = sd->getServentId();
+ servent_selected = TRUE;
+ } else {
+ if (sd->getSelected()){
+ changeFlg = TRUE;
+ }
+ sd->setSelected(FALSE);
+ }
+ sd = sd->getNextData();
+ }
+ cd = cd->getNextData();
+ }
+ if (changeFlg){
+ MakeBack(hwnd);
+ }
+
+ if (channel_selected){
+ PopupChannelMenu(channel_id);
+ } else if (servent_selected){
+ PopupServentMenu(servent_id);
+ } else {
+ PopupOtherMenu();
+ }
+}
+
+LRESULT CALLBACK GUIProc (HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ switch(message){
+ case WM_CREATE: // \83E\83B\83\93\83h\83E\8dì\90¬
+ WmCreateProc(hwnd);
+ break;
+
+ case WM_PAINT: // \95`\89æ
+ WmPaintProc(hwnd);
+ break;
+
+ case WM_SIZE: // \83T\83C\83Y\95Ï\8dX
+ WmSizeProc(hwnd,lParam);
+ break;
+
+ case WM_LBUTTONDOWN: // \8d¶\83{\83^\83\93\89\9f\82·
+ WmLButtonDownProc(hwnd,lParam);
+ break;
+
+ case WM_RBUTTONDOWN: // \89E\83{\83^\83\93\89\9f\82·
+ WmRButtonDownProc(hwnd,lParam);
+ break;
+
+ case WM_LBUTTONDBLCLK: // \8d¶\83_\83u\83\8b\83N\83\8a\83b\83N
+ WmLButtonDblclkProc(hwnd,lParam);
+ break;
+
+ case WM_ERASEBKGND: // \94w\8ci\8fÁ\8b\8e
+ return TRUE; // \94w\8ci\82Í\8fÁ\82³\82È\82¢
+
+ case WM_CLOSE:
+ //if (backImage){
+ // ::delete backImage;
+ // backImage = NULL;
+ //}
+ GetWindowPlacement(hwnd, &winPlace);
+ guiFlg = true;
+ DestroyWindow( hwnd );
+ break;
+ case WM_DESTROY:
+ GetWindowPlacement(hwnd, &winPlace);
+ guiFlg = true;
+ guiThread.active = false;
+
+ // wait until GUI thread terminated,
+ // and then dispose background image.
+ while (1)
+ {
+ if (guiThread.finish)
+ break;
+ }
+ if (backImage)
+ {
+ ::delete backImage;
+ backImage = NULL;
+ }
+
+ guiWnd = NULL;
+ break;
+ case WM_START:
+ ghStart = ::CreateWindow(szWindowClass3,
+ "Peercast-IM@S",
+ WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX),
+ 0,
+ 0,
+ 400,
+ 300,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+ ::ShowWindow(ghStart, SW_SHOWNORMAL);
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+Gdiplus::Image *data1 = NULL;
+Gdiplus::Image *data2 = NULL;
+Gdiplus::Bitmap *startBmp = NULL;
+Gdiplus::Graphics *startGra = NULL;
+WLock MakeStartLock;
+
+LRESULT CALLBACK StartProc (HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ SolidBrush b(Color::Black);
+ bstr_t bstr;
+
+ switch(message){
+ case WM_CREATE:
+ startBmp = ::new Bitmap(400,300);
+ startGra = ::new Graphics(startBmp);
+ bstr = L"data1.jpg";
+ data1 = ::new Image(bstr);
+ bstr = L"data2.jpg";
+ data2 = ::new Image(bstr);
+ // \8d\95\82Å\93h\82è\82Â\82Ô\82µ
+ startGra->FillRectangle(&b, 0, 0, 400, 300);
+ break;
+ case WM_PAINT:
+ if (startGra){
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ MakeStartLock.on();
+ hdc = BeginPaint(hwnd, &paint);
+ RECT *rcRect;
+ rcRect = &(paint.rcPaint);
+ LONG width = rcRect->right - rcRect->left + 1;
+ LONG height = rcRect->bottom - rcRect->top + 1;
+
+ Graphics g2(hdc);
+ Rect r(rcRect->left, rcRect->top, width, height);
+ g2.DrawImage(startBmp, r, rcRect->left, rcRect->top, width, height, UnitPixel);
+ EndPaint(hwnd, &paint);
+ MakeStartLock.off();
+ }
+ break;
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_CLOSE:
+ DestroyWindow(ghStart);
+ if (startBmp){
+ ::delete startBmp;
+ }
+ if (startGra){
+ ::delete startGra;
+ }
+ if (data1){
+ ::delete data1;
+ }
+ if (data2){
+ ::delete data2;
+ }
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+THREAD_PROC FestivalStart(ThreadInfo *thread){
+
+ while(startGra==NULL){
+ sys->sleep(100);
+ }
+
+ sys->sleep(1000);
+
+ MakeStartLock.on();
+ Font font(L"\82l\82r \82o\83S\83V\83b\83N",40);
+ StringFormat format;
+ format.SetAlignment(StringAlignmentCenter);
+ startGra->SetTextRenderingHint(TextRenderingHintAntiAlias);
+ PointF origin(199.0f,49.0f);
+ RectF rect(0,0,400,100);
+ LinearGradientBrush b1(rect, Color::LightSkyBlue, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\91æ\82Q\89ñ", -1, &font, origin, &format, &b1);
+ origin.Y += 50;
+ LinearGradientBrush b2(rect, Color::LightGreen, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\83A\83C\83h\83\8b\83}\83X\83^\81[", -1, &font, origin, &format, &b2);
+ origin.Y += 50;
+ LinearGradientBrush b3(rect, Color::LightGoldenrodYellow, Color::White, LinearGradientModeHorizontal);
+ startGra->DrawString(L"\83t\83@\83\93\8a´\8eÓ\8dÕ", -1, &font, origin, &format, &b3);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(3000);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(0,0,80,400), 200,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(80,0,80,400), 266,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(160,0,80,400), 332,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(240,0,80,400), 398,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(320,0,80,400), 464,200,66,330, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(0,0,80,400), 530,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(80,0,80,400), 584,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(160,0,80,400), 638,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(240,0,80,400), 692,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ MakeStartLock.on();
+ startGra->DrawImage(data1, Rect(320,0,80,400), 746,200,54,270, UnitPixel);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(500);
+
+ for (int i=1; i<=10; i++){
+ ColorMatrix mtx = {
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.1f*i, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+ ImageAttributes att;
+
+ MakeStartLock.on();
+ att.SetColorMatrix(&mtx, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
+ startGra->DrawImage(data2, Rect(0,0,400,300), 360,130,400,300, UnitPixel, &att);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(100);
+ }
+
+ sys->sleep(2000);
+
+ MakeStartLock.on();
+ INT style = FontStyleBold;
+ Font font2(L"\82l\82r \82o\83S\83V\83b\83N",70,style,UnitPoint);
+ PointF origin2(199.0f,99.0f);
+ SolidBrush bs(Color::Black);
+ startGra->DrawString(L"START!", -1, &font2, origin2, &format, &bs);
+ Font font3(L"\82l\82r \82o\83S\83V\83b\83N",70,style,UnitPoint);
+ LinearGradientBrush bx(rect, Color::LightPink, Color::DeepPink, LinearGradientModeHorizontal);
+ startGra->DrawString(L"START!", -1, &font3, origin2, &format, &bx);
+ MakeStartLock.off();
+ InvalidateRect(ghStart, NULL, FALSE);
+ sys->sleep(5000);
+
+ SendMessage(ghStart, WM_CLOSE, 0, 0);
+ return 0;
+}
--- /dev/null
+// ------------------------------------------------
+// File : gui.h
+// Date: 4-apr-2002
+// Author: giles
+//
+// (c) 2002 peercast.org
+// ------------------------------------------------
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// ------------------------------------------------
+
+#ifndef _GUI_H
+#define _GUI_H
+
+#include "sys.h"
+#include "gdiplus.h"
+#include "channel.h"
+
+extern LRESULT CALLBACK GUIProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK StartProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+extern void ADDLOG(const char *str,int id,bool sel,void *data, LogBuffer::TYPE type);
+
+extern String iniFileName;
+extern HWND guiWnd;
+extern int logID;
+
+enum
+{
+ WM_INITSETTINGS = WM_USER,
+ WM_GETPORTNUMBER,
+ WM_PLAYCHANNEL,
+ WM_TRAYICON,
+ WM_SHOWGUI,
+ WM_SHOWMENU,
+ WM_PROCURL,
+ WM_START
+
+};
+
+class IdData
+{
+private:
+ int channel_id;
+ int servent_id;
+ unsigned int ip_addr;
+
+public:
+ IdData(int cid, int sid, unsigned int ip){
+ channel_id = cid;
+ servent_id = sid;
+ ip_addr = ip;
+ }
+
+ int getChannelId(){return channel_id;};
+ int getServentId(){return servent_id;};
+ unsigned int getIpAddr(){return ip_addr;};
+};
+
+class ServentData
+{
+private:
+ int servent_id;
+ int type;
+// unsigned int tnum;
+ int status;
+// String agent;
+ Host host;
+ String hostname;
+// unsigned int syncpos;
+// char *typeStr;
+// char *statusStr;
+// bool infoFlg;
+// bool relay;
+// bool firewalled;
+ unsigned int totalRelays;
+ unsigned int totalListeners;
+// int vp_ver;
+// char ver_ex_prefix[2];
+// int ver_ex_number;
+
+ bool EnableFlg;
+ bool infoFlg;
+ ServentData *next;
+ ChanHit chanHit;
+ bool selected;
+ int posX;
+ int posY;
+ int width;
+ int height;
+
+ unsigned int lastSkipTime;
+ unsigned int lastSkipCount;
+
+public:
+ ServentData(){
+ next = NULL;
+ EnableFlg = false;
+ infoFlg = false;
+
+ posX = 0;
+ posY = 0;
+ width = 0;
+ selected = false;
+
+ }
+ void setData(Servent *s, ChanHit *hit, unsigned int listeners, unsigned int relays, bool infoFlg);
+ bool getInfoFlg(){return infoFlg;}
+ ChanHit *getChanHit(){return &chanHit;};
+ int getStatus(){return status;};
+ Host getHost(){return host;};
+
+ int getServentId(){return servent_id;};
+
+ bool getEnableFlg(){return EnableFlg;};
+ void setEnableFlg(bool f){EnableFlg = f;};
+ ServentData *getNextData(){return next;};
+ void setNextData(ServentData *s){next = s;};
+ bool getSelected(){return selected;};
+ void setSelected(bool f){selected = f; if (!f){posX=0;posY=0;}};
+ int getWidth(){return width;};
+ void setWidth(int w){width = w;};
+ int getHeight(){return height;};
+ void setHeight(int h){height = h;};
+ String getName(){return hostname;};
+ void setName(String n){hostname = n;};
+
+ int drawServent(Gdiplus::Graphics *g, int x, int y);
+
+ bool checkDown(int x, int y);
+
+};
+
+class ChannelData {
+
+private:
+ int channel_id;
+ char name[257];
+ int bitRate;
+ unsigned int lastPlayStart;
+ int status;
+ int totalListeners;
+ int totalRelays;
+ int localListeners;
+ int localRelays;
+ bool stayConnected;
+ ChanHit chDisp;
+ bool bTracker;
+ unsigned int lastSkipTime;
+ unsigned int skipCount;
+
+ bool EnableFlg;
+ ChannelData *next;
+
+ int posX;
+ int posY;
+ int width;
+ int height;
+ bool selected;
+ ServentData *serventDataTop;
+ bool openFlg;
+
+public:
+ ChannelData(){
+ EnableFlg = FALSE;
+ next = NULL;
+ posX = 0;
+ posY = 0;
+ width = 0;
+ height = 0;
+ selected = FALSE;
+ serventDataTop = NULL;
+ openFlg = FALSE;
+ }
+ int drawChannel(Gdiplus::Graphics *g, int x, int y);
+
+ void setData(Channel *);
+ int getChannelId(){return channel_id;};
+ char* getName(){return &(name[0]);};
+ int getBitRate(){return bitRate;};
+ bool isStayConnected(){return stayConnected;};
+ bool isTracker(){return bTracker;};
+ int getStatus(){return status;};
+ unsigned int getLastSkipTime(){return lastSkipTime;};
+
+ int getTotalListeners(){return totalListeners;};
+ int getTotalRelays(){return totalRelays;};
+ int getLocalListeners(){return localListeners;};
+ int getLocalRelays(){return localRelays;};
+
+ bool getEnableFlg(){return EnableFlg;};
+ void setEnableFlg(bool flg){EnableFlg = flg;};
+ ChannelData *getNextData(){return next;};
+ void setNextData(ChannelData* cd){next = cd;};
+
+ int getPosX(){return posX;};
+ void setPosX(int x){posX = x;}
+ int getPosY(){return posY;};
+ void setPosY(int y){posY = y;};
+ int getWidth(){return width;};
+ void setWidth(int w){width = w;};
+ int getHeight(){return height;};
+ void setHeight(int h){height = h;};
+ bool isSelected(){return selected;};
+ void setSelected(bool sel){selected = sel;};
+ bool getOpenFlg(){return openFlg;};
+ void setOpenFlg(bool b){openFlg = b;};
+
+ ServentData* getServentDataTop(){return serventDataTop;};
+ ServentData* findServentData(int servent_id);
+ void addServentData(ServentData *sd);
+ void deleteDisableServents();
+
+ bool setName(int servent_id, String name);
+ int getServentCount();
+
+ bool checkDown(int x, int y);
+};
+
+
+
+#endif
\ No newline at end of file
--- /dev/null
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Simple.rc
+//
+#define IDC_MYICON 2
+#define IDD_MAINWINDOW 101
+#define IDD_SIMPLE_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDS_APP_TITLE 103
+#define IDM_ABOUT 104
+#define IDM_EXIT 105
+#define IDS_HELLO 106
+#define IDI_SIMPLE 107
+#define IDI_SMALL 108
+#define IDC_SIMPLE 109
+#define IDI_SMALL2 109
+#define IDR_MAINFRAME 128
+#define IDR_TRAYMENU 130
+#define IDR_VERMENU 133
+#define IDD_CHANINFO 136
+#define IDR_LTRAYMENU 137
+#define IDC_LIST1 1000
+#define IDC_BUTTON7 1001
+#define IDC_ABOUTVER 1002
+#define IDC_CHECK1 1003
+#define IDC_EDIT1 1004
+#define IDC_LIST2 1005
+#define IDC_EDIT_PLAYING 1005
+#define IDC_COMBO1 1006
+#define IDC_EDIT_MESSAGE 1006
+#define IDC_CHECK2 1007
+#define IDC_EDIT_NAME 1007
+#define IDC_BUTTON1 1008
+#define IDC_EDIT_DESC 1008
+#define IDC_DETAILS 1009
+#define IDC_MAXRELAYS 1009
+#define IDC_LIST3 1010
+#define IDC_PLAY 1010
+#define IDC_CONTACT 1011
+#define IDC_EDIT2 1012
+#define IDC_FORMAT 1013
+#define IDC_EDIT_GENRE 1014
+#define IDC_KEEP 1015
+#define IDC_EDIT_STATUS 1016
+#define IDC_GROUPBOX_RELAY 1016
+#define IDC_EDIT_LISTENERS 1017
+#define IDC_STATIC_CONNECTION 1017
+#define IDC_LIST4 1018
+#define IDC_EDIT_HOSTS 1018
+#define IDC_STATIC_LOG 1018
+#define IDC_BUTTON4 1019
+#define IDC_BUTTON5 1020
+#define IDC_BUTTON6 1021
+#define IDC_EDIT3 1025
+#define IDC_EDIT5 1027
+#define IDC_LOGDEBUG 1037
+#define IDC_LOGNETWORK 1038
+#define IDC_LOGERRORS 1039
+#define IDC_CHECK9 1041
+#define IDC_BUTTON8 1043
+#define IDC_BUTTON10 1046
+#define IDC_BUTTON11 1047
+#define IDC_LOGCHANNELS 1050
+#define IDC_BUTTON2 1056
+#define IDC_EDIT4 1058
+#define IDC_BUTTON3 1059
+#define IDC_EDIT9 1060
+#define IDC_CHECK11 1061
+#define IDC_BUTTON9 1062
+#define IDM_SETTINGS_GUI 32771
+#define ID_POPUP_ABOUT 32779
+#define ID_POPUP_EXIT_CONFIRM 32781
+#define ID_POPUP_EXIT_NO 32782
+#define ID_POPUP_SETTINGS 32785
+#define ID_POPUP_CONNECTIONS 32786
+#define ID_POPUP_SHOWGUI 32788
+#define ID_POPUP_ALLCHANNELS 32791
+#define ID_POPUP_FAVORITES_EDIT 32792
+#define ID_POPUP_ADVANCED_INFORMATION 32793
+#define ID_POPUP_ADVANCED_SAVESETTINGS 32794
+#define ID_POPUP_UPGRADE 32795
+#define ID_POPUP_HELP 32796
+#define ID_POPUP_ADVANCED_VIEWLOG 32797
+#define ID_POPUP_FAVORITES_PLAYALL 32798
+#define ID_POPUP_ADVANCED_ALLCHANNELS 32799
+#define ID_POPUP_ADVANCED_RELAYEDCHANNELS 32800
+#define ID_POPUP_ADVANCED_BROADCAST 32801
+#define ID_FIND_CHANNELS 32808
+#define ID_POPUP_SHOWMESSAGES_PEERCAST 32814
+#define ID_POPUP_SHOWMESSAGES_BROADCASTERS 32815
+#define ID_POPUP_SHOWMESSAGES_TRACKINFO 32816
+#define ID_POPUP_POPUPMESSAGES_UPGRADEALERTS 32817
+#define ID_POPUP_YELLOWPAGES 32818
+#define ID_POPUP_ADVANCED_SHOWGUI 32819
+#define ID_POPUP_YELLOWPAGES1 32820
+#define ID_POPUP_YELLOWPAGES2 32821
+#define ID_POPUP_SAVE_GUI_POS 32823
+#define ID_POPUP_KEEP_DOWNSTREAMS 32825
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 142
+#define _APS_NEXT_COMMAND_VALUE 32826
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif