servhs.cpp
上传用户:chn_coc
上传日期:2007-12-20
资源大小:563k
文件大小:38k
源码类别:

P2P编程

开发平台:

Windows_Unix

  1. // ------------------------------------------------ // 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"
  2. #include "version2.h"
  3. // ----------------------------------- 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; // fetch command while (*cp) { char c = *cp++; if (c == '=') break; else *cmd++ = c; } *cmd = 0; // fetch arg while (*cp) { char c = *cp++; if (c == '&') break; else *arg++ = c; } *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);
  4. LOG_DEBUG("Admin client"); handshakeCMD(fn+7);
  5. }else if (strncmp(fn,"/http/",6)==0)
  6. {
  7. String dirName = fn+6;
  8. if (!isAllowed(ALLOW_HTML))
  9. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  10. if (!handshakeAuth(http,fn,false))
  11. throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
  12. handshakeRemoteFile(dirName);
  13. }else if (strncmp(fn,"/html/",6)==0)
  14. {
  15. String dirName = fn+1;
  16. if (!isAllowed(ALLOW_HTML))
  17. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  18. if (handshakeAuth(http,fn,true))
  19. handshakeLocalFile(dirName);
  20. }else if (strncmp(fn,"/admin/?",8)==0) { if (!isAllowed(ALLOW_HTML)) throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  21. 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);
  22. 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. if (mountArg)
  23. { if (strcmp(c->mount,mountArg)==0)
  24. { ChanInfo newInfo = c->info; newInfo.track.title.set(songArg,String::T_ESC);
  25. 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);
  26. } } }
  27. c=c->next; } } }else if (strncmp(fn,"/pls/",5)==0) {
  28. if (!sock->host.isLocalhost())
  29. if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
  30. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  31. ChanInfo info;
  32. if (servMgr->getChannel(fn+5,info,isPrivate())) handshakePLS(info,false);
  33. else
  34. throw HTTPException(HTTP_SC_NOTFOUND,404);
  35. }else if (strncmp(fn,"/stream/",8)==0) {
  36. if (!sock->host.isLocalhost())
  37. if (!isAllowed(ALLOW_DIRECT) || !isFiltered(ServFilter::F_DIRECT))
  38. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  39. triggerChannel(fn+8,ChanInfo::SP_HTTP,isPrivate());
  40. }else if (strncmp(fn,"/channel/",9)==0) {
  41. if (!sock->host.isLocalhost())
  42. if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
  43. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  44. triggerChannel(fn+9,ChanInfo::SP_PCP,false);
  45. }else 
  46. {
  47. while (http.nextHeader());
  48. http.writeLine(HTTP_SC_FOUND);
  49. http.writeLineF("Location: /%s/index.html",servMgr->htmlPath);
  50. http.writeLine("");
  51. } }else if (http.isRequest("GIV")) {
  52. HTTP http(*sock);
  53. while (http.nextHeader()) ;
  54. if (!isAllowed(ALLOW_NETWORK))
  55. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  56. GnuID id;
  57. id.clear();
  58. char *idstr = strstr(in,"/");
  59. if (idstr)
  60. id.fromStr(idstr+1);
  61. char ipstr[64];
  62. sock->host.toStr(ipstr);
  63. if (id.isSet())
  64. {
  65. // 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)
  66. throw HTTPException(HTTP_SC_NOTFOUND,404);
  67. if (!ch->acceptGIV(sock))
  68. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  69. LOG_DEBUG("Accepted GIV channel %s from: %s",idstr,ipstr);
  70. sock=NULL; // release this servent but dont close socket.
  71. }else 
  72. {
  73. if (!servMgr->acceptGIV(sock))
  74. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  75. LOG_DEBUG("Accepted GIV PCP from: %s",ipstr);
  76. sock=NULL; // release this servent but dont close socket.
  77. }
  78. }else if (http.isRequest(PCX_PCP_CONNECT))
  79. {
  80. if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
  81. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  82. processIncomingPCP(true);
  83. }else if (http.isRequest("PEERCAST CONNECT"))
  84. { if (!isAllowed(ALLOW_NETWORK) || !isFiltered(ServFilter::F_NETWORK))
  85. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  86. LOG_DEBUG("PEERCAST client"); processServent(); }else if (http.isRequest("SOURCE")) { if (!isAllowed(ALLOW_BROADCAST))
  87. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  88. 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);
  89. 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); } } // -----------------------------------
  90. bool Servent::canStream(Channel *ch)
  91. {
  92. if (ch==NULL)
  93. return false;
  94. if (servMgr->isDisabled)
  95. return false;
  96. if (!isPrivate())
  97. {
  98. if  (
  99. servMgr->bitrateFull(ch->getBitrate())
  100. || ((type == T_RELAY) && servMgr->relaysFull())
  101. || ((type == T_DIRECT) && servMgr->directFull())
  102. || !ch->isPlaying()
  103. || ch->isFull()
  104. )
  105. return false;
  106. }
  107. return true;
  108. }
  109. // ----------------------------------- void Servent::handshakeIncoming() { setStatus(S_HANDSHAKE); char buf[1024]; 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) {
  110. ChanInfo info;
  111. servMgr->getChannel(str,info,relay);
  112. if (proto == ChanInfo::SP_PCP)
  113. type = T_RELAY;
  114. else
  115. type = T_DIRECT;
  116. outputProtocol = proto;
  117. processStream(false,info);
  118. } // ----------------------------------- 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:
  119. content = MIME_RAM;
  120. break;
  121. 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));
  122. if (getLocalURL(url)) { 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)
  123. type = PlayList::T_RAM;
  124. 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; } // ----------------------------------- // 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); } // -----------------------------------
  125. bool Servent::handshakeAuth(HTTP &http,const char *args,bool local)
  126. {
  127. char user[64],pass[64];
  128. user[0] = pass[0] = 0;
  129. char *pwd  = getCGIarg(args, "pass=");
  130. if ((pwd) && strlen(servMgr->password))
  131. {
  132. String tmp = pwd;
  133. char *as = strstr(tmp.cstr(),"&");
  134. if (as) *as = 0;
  135. if (strcmp(tmp,servMgr->password)==0)
  136. {
  137.     while (http.nextHeader());
  138. return true;
  139. }
  140. }
  141. Cookie gotCookie;
  142. cookie.clear();
  143.     while (http.nextHeader())
  144. {
  145. char *arg = http.getArgStr();
  146. if (!arg)
  147. continue;
  148. switch (servMgr->authType)
  149. {
  150. case ServMgr::AUTH_HTTPBASIC:
  151. if (http.isHeader("Authorization"))
  152. http.getAuthUserPass(user,pass);
  153. break;
  154. case ServMgr::AUTH_COOKIE:
  155. if (http.isHeader("Cookie"))
  156. {
  157. LOG_DEBUG("Got cookie: %s",arg);
  158. char *idp=arg;
  159. while ((idp = strstr(idp,"id=")))
  160. {
  161. idp+=3;
  162. gotCookie.set(idp,sock->host.ip);
  163. if (servMgr->cookieList.contains(gotCookie))
  164. {
  165. LOG_DEBUG("Cookie found");
  166. cookie = gotCookie;
  167. break;
  168. }
  169. }
  170. }
  171. break;
  172. }
  173. }
  174. if (sock->host.isLocalhost())
  175. return true;
  176. switch (servMgr->authType)
  177. {
  178. case ServMgr::AUTH_HTTPBASIC:
  179. if ((strcmp(pass,servMgr->password)==0) && strlen(servMgr->password))
  180. return true;
  181. break;
  182. case ServMgr::AUTH_COOKIE:
  183. if (servMgr->cookieList.contains(cookie))
  184. return true;
  185. break;
  186. }
  187. if (servMgr->authType == ServMgr::AUTH_HTTPBASIC)
  188. {
  189. http.writeLine(HTTP_SC_UNAUTHORIZED);
  190. http.writeLine("WWW-Authenticate: Basic realm="PeerCast Admin"");
  191. }else if (servMgr->authType == ServMgr::AUTH_COOKIE)
  192. {
  193. String file = servMgr->htmlPath;
  194. file.append("/login.html");
  195. if (local)
  196. handshakeLocalFile(file);
  197. else
  198. handshakeRemoteFile(file);
  199. }
  200. return false;
  201. }
  202. // ----------------------------------- void Servent::handshakeCMD(char *cmd) { char result[256]; char arg[512]; char curr[256]; char jumpStr[128]; char *jumpArg=NULL; bool retHTML=true; strcpy(result,"OK"); HTTP http(*sock); HTML html("",*sock);
  203. if (!handshakeAuth(http,cmd,true))
  204. 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);
  205. jumpArg = jumpStr; }else if (cmpCGIarg(cmd,"cmd=","reg"))
  206. {
  207. char idstr[128];
  208. chanMgr->broadcastID.toStr(idstr);
  209. sprintf(jumpStr,"http://www.peercast.org/register/?id=%s",idstr);
  210. jumpArg = jumpStr;
  211. }else if (cmpCGIarg(cmd,"cmd=","edit_bcid"))
  212. {
  213. char *cp = cmd;
  214. GnuID id;
  215. BCID *bcid;
  216. while (cp=nextCGIarg(cp,curr,arg))
  217. {
  218. if (strcmp(curr,"id")==0)
  219. id.fromStr(arg);
  220. else if (strcmp(curr,"del")==0)
  221. servMgr->removeValidBCID(id);
  222. else if (strcmp(curr,"valid")==0)
  223. {
  224. bcid = servMgr->findValidBCID(id);
  225. if (bcid)
  226. bcid->valid = getCGIargBOOL(arg);
  227. }
  228. }
  229. peercastInst->saveSettings();
  230. sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
  231. jumpArg = jumpStr;
  232. }else if (cmpCGIarg(cmd,"cmd=","add_bcid"))
  233. {
  234. BCID *bcid = new BCID();
  235. char *cp = cmd;
  236. bool result=false;
  237. while (cp=nextCGIarg(cp,curr,arg))
  238. {
  239. if (strcmp(curr,"id")==0)
  240. bcid->id.fromStr(arg);
  241. else if (strcmp(curr,"name")==0)
  242. bcid->name.set(arg);
  243. else if (strcmp(curr,"email")==0)
  244. bcid->email.set(arg);
  245. else if (strcmp(curr,"url")==0)
  246. bcid->url.set(arg);
  247. else if (strcmp(curr,"valid")==0)
  248. bcid->valid = getCGIargBOOL(arg);
  249. else if (strcmp(curr,"result")==0)
  250. result = true;
  251. }
  252. LOG_DEBUG("Adding BCID : %s",bcid->name.cstr());
  253. servMgr->addValidBCID(bcid);
  254. peercastInst->saveSettings();
  255. if (result) { http.writeLine(HTTP_SC_OK); http.writeLine("");
  256. http.writeString("OK");
  257. }else
  258. {
  259. sprintf(jumpStr,"/%s/bcid.html",servMgr->htmlPath);
  260. jumpArg = jumpStr;
  261. }
  262. }else if (cmpCGIarg(cmd,"cmd=","apply")) { servMgr->numFilters = 0; ServFilter *currFilter=servMgr->filters;
  263. bool brRoot=false;
  264. bool getUpd=false;
  265. int showLog=0;
  266. int allowServer1=0;
  267. int allowServer2=0;
  268. int newPort=servMgr->serverHost.port;
  269. 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)
  270. brRoot = getCGIargBOOL(arg);
  271. else if (strcmp(curr,"getupd")==0)
  272. getUpd = getCGIargBOOL(arg);
  273. else if (strcmp(curr,"huint")==0)
  274. chanMgr->setUpdateInterval(getCGIargINT(arg));
  275. else if (strcmp(curr,"forceip")==0) servMgr->forceIP = arg; else if (strcmp(curr,"htmlPath")==0)
  276. {
  277. strcpy(servMgr->htmlPath,"html/");
  278. strcat(servMgr->htmlPath,arg);
  279. }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)
  280. servMgr->minGnuIncoming = atoi(arg);
  281. else if (strcmp(curr,"maxpgnu")==0)
  282. servMgr->maxGnuIncoming = atoi(arg);
  283. // connections
  284. else if (strcmp(curr,"maxcin")==0)
  285. servMgr->maxControl = getCGIargINT(arg);
  286. 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)
  287. servMgr->maxDirect = getCGIargINT(arg);
  288. else if (strcmp(curr,"maxrelaypc")==0) chanMgr->maxRelaysPerChannel = getCGIargINT(arg); else if (strncmp(curr,"filt_",5)==0) { 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) {
  289. if (!PCP_FORCE_YP)
  290. { String str(arg,String::T_ESC); str.convertTo(String::T_ASCII); servMgr->rootHost = str;
  291. }
  292. } 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; }
  293. else if (strcmp(curr,"logDebug")==0)
  294. showLog |= atoi(arg)?(1<<LogBuffer::T_DEBUG):0;
  295. else if (strcmp(curr,"logErrors")==0)
  296. showLog |= atoi(arg)?(1<<LogBuffer::T_ERROR):0;
  297. else if (strcmp(curr,"logNetwork")==0)
  298. showLog |= atoi(arg)?(1<<LogBuffer::T_NETWORK):0;
  299. else if (strcmp(curr,"logChannel")==0)
  300. showLog |= atoi(arg)?(1<<LogBuffer::T_CHANNEL):0;
  301. else if (strcmp(curr,"allowHTML1")==0)
  302. allowServer1 |= atoi(arg)?(ALLOW_HTML):0;
  303. else if (strcmp(curr,"allowNetwork1")==0)
  304. allowServer1 |= atoi(arg)?(ALLOW_NETWORK):0;
  305. else if (strcmp(curr,"allowBroadcast1")==0)
  306. allowServer1 |= atoi(arg)?(ALLOW_BROADCAST):0;
  307. else if (strcmp(curr,"allowDirect1")==0)
  308. allowServer1 |= atoi(arg)?(ALLOW_DIRECT):0;
  309. else if (strcmp(curr,"allowHTML2")==0)
  310. allowServer2 |= atoi(arg)?(ALLOW_HTML):0;
  311. else if (strcmp(curr,"allowBroadcast2")==0)
  312. allowServer2 |= atoi(arg)?(ALLOW_BROADCAST):0;
  313. } servMgr->showLog = showLog;
  314. servMgr->allowServer1 = allowServer1; servMgr->allowServer2 = allowServer2;
  315. if (servMgr->serverHost.port != newPort)
  316. {
  317. Host lh(ClientSocket::getIP(NULL),newPort);
  318. char ipstr[64];
  319. lh.toStr(ipstr);
  320. sprintf(jumpStr,"http://%s/%s/settings.html",ipstr,servMgr->htmlPath);
  321. servMgr->serverHost.port = newPort;
  322. servMgr->restartServer=true;
  323. //html.setRefresh(3);
  324. //html.setRefreshURL(jumpStr);
  325. //html.startHTML();
  326. //html.addHead();
  327. // html.startBody();
  328. // html.startTagEnd("h1","Please wait...");
  329. // html.end();
  330. //html.end();
  331. //char ipstr[64];
  332. //servMgr->serverHost.toStr(ipstr);
  333. //sprintf(jumpStr,"/%s/settings.html",ipstr,servMgr->htmlPath);
  334. jumpArg = jumpStr;
  335. }else
  336. {
  337. sprintf(jumpStr,"/%s/settings.html",servMgr->htmlPath);
  338. jumpArg = jumpStr;
  339. }
  340. peercastInst->saveSettings();
  341. peercastApp->updateSettings();
  342. if ((servMgr->isRoot) && (brRoot))
  343. servMgr->broadcastRootSettings(getUpd);
  344. }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);
  345. }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); } }
  346. info.bcID = chanMgr->broadcastID;
  347. Channel *c = chanMgr->createChannel(info,NULL); if (c) c->startURL(curl.cstr()); sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
  348. 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);
  349. jumpArg = jumpStr; }else if (cmpCGIarg(cmd,"cmd=","hitlist")) { bool stayConnected=hasCGIarg(cmd,"relay");
  350. int index = 0;
  351. 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(); } } }
  352. chl = chl->next;
  353. index++; } char *findArg = getCGIarg(cmd,"keywords="); if (hasCGIarg(cmd,"relay")) { sys->sleep(500); sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
  354. 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)
  355. chanMgr->clearHitLists();
  356. else if (strcmp(curr,"packets")==0) { stats.clearRange(Stats::PACKETSSTART,Stats::PACKETSEND); servMgr->numVersions = 0; } } sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
  357. 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);
  358. 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; sys->sleep(500); sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
  359. 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);
  360. 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) c->stayConnected = true; sprintf(jumpStr,"/%s/relays.html",servMgr->htmlPath);
  361. jumpArg = jumpStr; }else if (cmpCGIarg(cmd,"cmd=","relay")) {
  362. 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);
  363. 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("");
  364. }else{ sprintf(jumpStr,"/%s/index.html",servMgr->htmlPath);
  365. jumpArg = jumpStr;
  366. } } }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"",
  367. stats.getPerSecond(Stats::BYTESOUT)-stats.getPerSecond(Stats::LOCALBYTESOUT),
  368. stats.getPerSecond(Stats::BYTESIN)-stats.getPerSecond(Stats::LOCALBYTESIN)
  369. ));
  370. 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)));
  371. XML::Node *an = new XML::Node("channels_relayed total="%d"",chanMgr->numChannels());
  372. rn->add(an);
  373. Channel *c = chanMgr->channel;
  374. while (c)
  375. {
  376. if (c->isActive())
  377. an->add(createChannelXML(c));
  378. c=c->next;
  379. }
  380. // add public channels { XML::Node *fn = new XML::Node("channels_found total="%d"",chanMgr->numHitLists()); rn->add(fn);
  381. ChanHitList *chl = chanMgr->hitlist; while (chl)
  382. { if (chl->isUsed())
  383. if (!chl->info.isPrivate()) fn->add(createChannelXML(chl));
  384. chl = chl->next;
  385. }
  386. }
  387. if (servMgr->isRoot)
  388. {
  389. // add private channels
  390. {
  391. XML::Node *pn = new XML::Node("priv_channels");
  392. rn->add(pn);
  393. ChanHitList *chl = chanMgr->hitlist;
  394. while (chl)
  395. {
  396. if (chl->isUsed())
  397. if (chl->info.isPrivate())
  398. pn->add(createChannelXML(chl));
  399. chl = chl->next;
  400. }
  401. }
  402. }
  403. 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)); } }
  404. rn->add(hc);
  405.     sock->writeLine(HTTP_SC_OK);
  406. sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
  407.     sock->writeLineF("%s %s",HTTP_HS_CONTENT,MIME_XML);
  408. sock->writeLine("Connection: close");
  409.     sock->writeLine("");
  410. xml.write(*sock);
  411. } // ----------------------------------- 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"))
  412. { info.name.set(arg,String::T_ASCII);
  413. info.name.convertTo(String::T_UNICODE);
  414. }else if (http.isHeader("x-audiocast-url") || http.isHeader("icy-url") || http.isHeader("ice-url"))
  415. 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"))
  416. { info.genre.set(arg,String::T_ASCII);
  417. info.genre.convertTo(String::T_UNICODE);
  418. }else if (http.isHeader("x-audiocast-description") || http.isHeader("ice-description"))
  419. { info.desc.set(arg,String::T_ASCII);
  420. info.desc.convertTo(String::T_UNICODE);
  421. }else if (http.isHeader("Authorization")) http.getAuthUserPass(NULL,pwd); else if (http.isHeader(PCX_HS_CHANNELID)) info.id.fromStr(arg);
  422. 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;
  423. else if (stristr(arg,MIME_MMS)) info.srcProtocol = ChanInfo::SP_MMS;
  424. else if (stristr(arg,MIME_XPCP))
  425. info.srcProtocol = ChanInfo::SP_PCP;
  426. else if (stristr(arg,MIME_XPEERCAST))
  427. info.srcProtocol = ChanInfo::SP_PEERCAST;
  428. 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))
  429. info.contentType = ChanInfo::T_PLS;
  430. 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)
  431. {
  432. if (!sock->host.isLocalhost() || strlen(loginPassword))
  433. throw HTTPException(HTTP_SC_UNAUTHORIZED,401);
  434. }
  435. // we need a valid IP address before we start
  436. servMgr->checkFirewall();
  437. // attach channel ID to name, channel ID is also encoded with IP address  // to help prevent channel hijacking.  info.id = chanMgr->broadcastID;
  438. 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("%snn",HTTP_SC_OK); else sock->writeLine("OK");
  439. Channel *c = chanMgr->findChannelByID(info.id); if (c)
  440. {
  441. LOG_CHANNEL("ICY channel already active, closing old one");
  442. c->thread.shutdown();
  443. }
  444. info.comment = chanMgr->broadcastMsg; info.bcID = chanMgr->broadcastID;
  445. c = chanMgr->createChannel(info,loginMount); if (!c) throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  446. c->startICY(sock,type); }
  447. // -----------------------------------
  448. void Servent::handshakeLocalFile(const char *fn)
  449. {
  450. HTTP http(*sock);
  451. String fileName;
  452. fileName = peercastApp->getPath();
  453. fileName.append(fn);
  454. LOG_DEBUG("Writing HTML file: %s",fileName.cstr());
  455. HTML html("",*sock);
  456. char *args = strstr(fileName.cstr(),"?");
  457. if (args)
  458. *args++=0;
  459. if (fileName.contains(".htm"))
  460. {
  461. html.writeOK(MIME_HTML);
  462. html.writeTemplate(fileName.cstr(),args);
  463. }else if (fileName.contains(".css"))
  464. {
  465. html.writeOK(MIME_CSS);
  466. html.writeRawFile(fileName.cstr());
  467. }else if (fileName.contains(".jpg"))
  468. {
  469. html.writeOK(MIME_JPEG);
  470. html.writeRawFile(fileName.cstr());
  471. }else if (fileName.contains(".gif"))
  472. {
  473. html.writeOK(MIME_GIF);
  474. html.writeRawFile(fileName.cstr());
  475. }else if (fileName.contains(".png"))
  476. {
  477. html.writeOK(MIME_PNG);
  478. html.writeRawFile(fileName.cstr());
  479. }
  480. }
  481. // -----------------------------------
  482. void Servent::handshakeRemoteFile(const char *dirName)
  483. {
  484. ClientSocket *rsock = sys->createSocket();
  485. if (!rsock)
  486. throw HTTPException(HTTP_SC_UNAVAILABLE,503);
  487. const char *hostName = "www.peercast.org"; // hardwired for "security"
  488. Host host;
  489. host.fromStrName(hostName,80);
  490. rsock->open(host);
  491. rsock->connect();
  492. HTTP rhttp(*rsock);
  493. rhttp.writeLineF("GET /%s HTTP/1.0",dirName);
  494. rhttp.writeLineF("%s %s",HTTP_HS_HOST,hostName);
  495. rhttp.writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
  496. rhttp.writeLineF("%s %s",HTTP_HS_ACCEPT,"*/*");
  497. rhttp.writeLine("");
  498. String contentType;
  499. bool isTemplate = false;
  500. while (rhttp.nextHeader())
  501. {
  502. char *arg = rhttp.getArgStr();
  503. if (arg) 
  504. {
  505. if (rhttp.isHeader("content-type"))
  506. contentType = arg;
  507. }
  508. }
  509. MemoryStream mem(100*1024);
  510. while (!rsock->eof())
  511. {
  512. int len=0;
  513. char buf[4096];
  514. len = rsock->readUpto(buf,sizeof(buf));
  515. if (len==0)
  516. break;
  517. else
  518. mem.write(buf,len);
  519. }
  520. rsock->close();
  521. int fileLen = mem.getPosition();
  522. mem.len = fileLen;
  523. mem.rewind();
  524. if (contentType.contains(MIME_HTML))
  525. isTemplate = true;
  526. sock->writeLine(HTTP_SC_OK);
  527. sock->writeLineF("%s %s",HTTP_HS_SERVER,PCX_AGENT);
  528. sock->writeLineF("%s %s",HTTP_HS_CACHE,"no-cache");
  529. sock->writeLineF("%s %s",HTTP_HS_CONNECTION,"close");
  530. sock->writeLineF("%s %s",HTTP_HS_CONTENT,contentType.cstr());
  531. sock->writeLine("");
  532. if (isTemplate)
  533. {
  534. HTML html("",*sock);
  535. html.readTemplate(mem,sock,0);
  536. }else
  537. sock->write(mem.buf,fileLen);
  538. mem.free();
  539. }