📄 servhs.cpp
字号:
// ------------------------------------------------// 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"
// -----------------------------------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("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())
{
if (
servMgr->bitrateFull(ch->getBitrate())
|| ((type == T_RELAY) && servMgr->relaysFull())
|| ((type == T_DIRECT) && servMgr->directFull())
|| !ch->isPlaying()
|| ch->isFull()
)
return false;
}
return true;
}
// -----------------------------------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) {
ChanInfo info;
servMgr->getChannel(str,info,relay);
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 (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)
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;}// -----------------------------------// 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -