HTTP proxy rewrite, by Wouter Spruit.
This commit is contained in:
parent
00d1dfb1e5
commit
81d56bc04b
13 changed files with 191 additions and 244 deletions
16
Makefile
16
Makefile
|
@ -125,19 +125,19 @@ MistInBuffer: src/input/mist_in.cpp src/input/input.cpp src/input/input_buffer.c
|
|||
outputs: MistOutFLV
|
||||
MistOutFLV: override LDLIBS += $(THREADLIB)
|
||||
MistOutFLV: override CPPFLAGS += "-DOUTPUTTYPE=\"output_progressive_flv.h\""
|
||||
MistOutFLV: src/output/mist_out.cpp src/output/output.cpp src/output/output_progressive_flv.cpp
|
||||
MistOutFLV: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_progressive_flv.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutMP4
|
||||
MistOutMP4: override LDLIBS += $(THREADLIB)
|
||||
MistOutMP4: override CPPFLAGS += "-DOUTPUTTYPE=\"output_progressive_mp4.h\""
|
||||
MistOutMP4: src/output/mist_out.cpp src/output/output.cpp src/output/output_progressive_mp4.cpp
|
||||
MistOutMP4: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_progressive_mp4.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutMP3
|
||||
MistOutMP3: override LDLIBS += $(THREADLIB)
|
||||
MistOutMP3: override CPPFLAGS += "-DOUTPUTTYPE=\"output_progressive_mp3.h\""
|
||||
MistOutMP3: src/output/mist_out.cpp src/output/output.cpp src/output/output_progressive_mp3.cpp
|
||||
MistOutMP3: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_progressive_mp3.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutRTMP
|
||||
|
@ -161,31 +161,31 @@ MistOutTS: src/output/mist_out.cpp src/output/output.cpp src/output/output_ts.cp
|
|||
outputs: MistOutHSS
|
||||
MistOutHSS: override LDLIBS += $(THREADLIB)
|
||||
MistOutHSS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_hss.h\""
|
||||
MistOutHSS: src/output/mist_out.cpp src/output/output.cpp src/output/output_hss.cpp
|
||||
MistOutHSS: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_hss.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutHLS
|
||||
MistOutHLS: override LDLIBS += $(THREADLIB)
|
||||
MistOutHLS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_hls.h\""
|
||||
MistOutHLS: src/output/mist_out.cpp src/output/output.cpp src/output/output_hls.cpp
|
||||
MistOutHLS: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_hls.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutHDS
|
||||
MistOutHDS: override LDLIBS += $(THREADLIB)
|
||||
MistOutHDS: override CPPFLAGS += "-DOUTPUTTYPE=\"output_hds.h\""
|
||||
MistOutHDS: src/output/mist_out.cpp src/output/output.cpp src/output/output_hds.cpp
|
||||
MistOutHDS: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_hds.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutSRT
|
||||
MistOutSRT: override LDLIBS += $(THREADLIB)
|
||||
MistOutSRT: override CPPFLAGS += "-DOUTPUTTYPE=\"output_srt.h\""
|
||||
MistOutSRT: src/output/mist_out.cpp src/output/output.cpp src/output/output_srt.cpp
|
||||
MistOutSRT: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_srt.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
outputs: MistOutJSON
|
||||
MistOutJSON: override LDLIBS += $(THREADLIB)
|
||||
MistOutJSON: override CPPFLAGS += "-DOUTPUTTYPE=\"output_json.h\""
|
||||
MistOutJSON: src/output/mist_out.cpp src/output/output.cpp src/output/output_json.cpp
|
||||
MistOutJSON: src/output/mist_out_http.cpp src/output/output.cpp src/output/output_json.cpp
|
||||
$(CXX) $(LDFLAGS) $(CPPFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
BUILT_SOURCES=controller/server.html.h connectors/embed.js.h
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h> //
|
||||
#include <getopt.h>
|
||||
|
||||
#include <mist/socket.h>
|
||||
|
@ -29,6 +32,25 @@
|
|||
/// Holds everything unique to HTTP Connectors.
|
||||
namespace Connector_HTTP {
|
||||
|
||||
static inline void builPipedPart(JSON::Value & p, char * argarr[], int & argnum, JSON::Value & argset){
|
||||
for (JSON::ObjIter it = argset.ObjBegin(); it != argset.ObjEnd(); ++it){
|
||||
if (it->second.isMember("option") && p.isMember(it->first)){
|
||||
if (it->second.isMember("type")){
|
||||
if (it->second["type"].asStringRef() == "str" && !p[it->first].isString()){
|
||||
p[it->first] = p[it->first].asString();
|
||||
}
|
||||
if ((it->second["type"].asStringRef() == "uint" || it->second["type"].asStringRef() == "int") && !p[it->first].isInt()){
|
||||
p[it->first] = JSON::Value(p[it->first].asInt()).asString();
|
||||
}
|
||||
}
|
||||
if (p[it->first].asStringRef().size() > 0){
|
||||
argarr[argnum++] = (char*)(it->second["option"].c_str());
|
||||
argarr[argnum++] = (char*)(p[it->first].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Class for keeping track of connections to connectors.
|
||||
class ConnConn{
|
||||
public:
|
||||
|
@ -62,6 +84,7 @@ namespace Connector_HTTP {
|
|||
tthread::mutex timeoutMutex; ///< Mutex for timeout thread.
|
||||
tthread::thread * timeouter = 0; ///< Thread that times out connections to connectors.
|
||||
JSON::Value capabilities; ///< Holds a list of all HTTP connectors and their properties
|
||||
JSON::Value ServConf; /// < holds configuration, loads from file in main
|
||||
|
||||
///\brief Function run as a thread to timeout requests on the proxy.
|
||||
///\param n A NULL-pointer
|
||||
|
@ -295,7 +318,7 @@ namespace Connector_HTTP {
|
|||
streamname = url.substr(7, url.length() - 10);
|
||||
}
|
||||
Util::Stream::sanitizeName(streamname);
|
||||
JSON::Value ServConf = JSON::fromFile(Util::getTmpFolder() + "streamlist");
|
||||
//JSON::Value ServConf = JSON::fromFile(Util::getTmpFolder() + "streamlist");
|
||||
std::string response;
|
||||
std::string host = H.GetHeader("Host");
|
||||
if (host.find(':')){
|
||||
|
@ -390,185 +413,90 @@ namespace Connector_HTTP {
|
|||
return proxyHandleUnsupported(H, conn); //anything else doesn't get handled
|
||||
}
|
||||
|
||||
///\brief Handles requests by dispatching them to the corresponding connector.
|
||||
///\param H The request to be handled.
|
||||
///\brief Handles requests by starting a corresponding output process.
|
||||
///\param H The request to be handled
|
||||
///\param conn The connection to the client that issued the request.
|
||||
///\param connector The type of connector to be invoked.
|
||||
///\return A timestamp indicating when the request was parsed.
|
||||
///\return -1 on failure, else 0.
|
||||
long long int proxyHandleThroughConnector(HTTP::Parser & H, Socket::Connection & conn, std::string & connector){
|
||||
static unsigned long long int confUpdateTime=0;
|
||||
static tthread::mutex updateLock;
|
||||
if( Util::bootSecs() -confUpdateTime > 10 ){
|
||||
tthread::lock_guard<tthread::mutex> guard(updateLock);
|
||||
if( Util::bootSecs() -confUpdateTime > 10 ){
|
||||
Connector_HTTP::ServConf = JSON::fromFile(Util::getTmpFolder() + "streamlist");
|
||||
confUpdateTime=Util::bootSecs();
|
||||
}
|
||||
}
|
||||
|
||||
//create a unique ID based on a hash of the user agent and host, followed by the stream name and connector
|
||||
std::string uid = Secure::md5(H.GetHeader("User-Agent") + conn.getHost()) + "_" + H.GetVar("stream") + "_" + connector;
|
||||
H.SetHeader("X-Stream", H.GetVar("stream"));
|
||||
H.SetHeader("X-UID", uid); //add the UID to the headers before copying
|
||||
H.SetHeader("X-Origin", conn.getHost()); //add the UID to the headers before copying
|
||||
std::string request = H.BuildRequest(); //copy the request for later forwarding to the connector
|
||||
std::string orig_url = H.getUrl();
|
||||
H.Clean();
|
||||
std::stringstream uidtemp;
|
||||
/// \todo verify the correct formation of the uid
|
||||
uidtemp << Secure::md5(H.GetHeader("User-Agent") + conn.getHost()) << "_" << H.GetVar("stream") << "_" << connector;
|
||||
std::string uid = uidtemp.str();
|
||||
|
||||
ConnConn * myCConn = 0;
|
||||
unsigned int counter = 0;
|
||||
//loop until a connection is available/created
|
||||
while (!myCConn){
|
||||
//lock the connection mutex before trying anything
|
||||
connMutex.lock();
|
||||
//check if a connection exists, and if not create one
|
||||
if ( !connectorConnections.count(uid)){
|
||||
connectorConnections[uid] = new ConnConn(new Socket::Connection(Util::getTmpFolder() + connector));
|
||||
connectorConnections[uid]->conn->setBlocking(false); //do not block on spool() with no data
|
||||
if (!connectorConnections[uid]->conn->spool() && !connectorConnections[uid]->conn){
|
||||
//unlock the connection mutex before exiting
|
||||
connMutex.unlock();
|
||||
DEBUG_MSG(DLVL_FAIL, "Created new connection (%s) failed - aborting request!", uid.c_str());
|
||||
return Util::getMS();
|
||||
}
|
||||
DEBUG_MSG(DLVL_HIGH, "Created new connection %s", uid.c_str());
|
||||
}
|
||||
|
||||
//attempt to lock the mutex for this connection
|
||||
if (connectorConnections[uid]->inUse.try_lock()){
|
||||
myCConn = connectorConnections[uid];
|
||||
//if the connection is dead, delete it and re-loop
|
||||
if (!myCConn->conn->spool() && !myCConn->conn->connected()){
|
||||
counter++;
|
||||
DEBUG_MSG(DLVL_HIGH, "Resetting existing connection %s", uid.c_str());
|
||||
connectorConnections.erase(uid);
|
||||
myCConn->inUse.unlock();
|
||||
delete myCConn;
|
||||
myCConn = 0;
|
||||
if (counter++ > 2){
|
||||
connMutex.unlock();
|
||||
DEBUG_MSG(DLVL_FAIL, "Created new connection (%s) failed - aborting request!", uid.c_str());
|
||||
return Util::getMS();
|
||||
}
|
||||
}else{
|
||||
DEBUG_MSG(DLVL_HIGH, "Using active connection %s", uid.c_str());
|
||||
}
|
||||
}
|
||||
//unlock the connection mutex before sleeping
|
||||
connMutex.unlock();
|
||||
//no connection yet? wait for 0.1 second and try again
|
||||
if ( !myCConn){
|
||||
Util::sleep(100);
|
||||
//fdIn and fdOut are connected to conn.sock
|
||||
int fdIn = conn.getSocket();
|
||||
int fdOut = conn.getSocket();
|
||||
|
||||
//taken from CheckProtocols (controller_connectors.cpp)
|
||||
char * argarr[20];
|
||||
for (int i=0; i<20; i++){argarr[i] = 0;}
|
||||
int id = -1;
|
||||
|
||||
for (unsigned int i=0; i < ServConf["config"]["protocols"].size(); ++i){
|
||||
std::cout << "checking: " << ServConf["config"]["protocols"][i]["connector"].asStringRef() <<std::endl;
|
||||
if ( ServConf["config"]["protocols"][i]["connector"].asStringRef() == connector ) {
|
||||
id = i;
|
||||
break; //pick the first protocol in the list that matches the connector
|
||||
}
|
||||
}
|
||||
if (id == -1) {
|
||||
DEBUG_MSG(DLVL_ERROR, "No connector found for: %s", connector.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_MSG(DLVL_HIGH, "Connector found: %s", connector.c_str());
|
||||
//build arguments for starting output process
|
||||
|
||||
std::string temphost=conn.getHost();
|
||||
std::string tempstream=H.GetVar("stream");
|
||||
// buildPipedArguments( , (char **)&argarr, Connector_HTTP::capabilities, temphost, tempstream);
|
||||
int argnum = 0;
|
||||
|
||||
std::string tmparg;
|
||||
tmparg = Util::getMyPath() + std::string("MistOut") + ServConf["config"]["protocols"][id]["connector"].asStringRef();
|
||||
struct stat buf;
|
||||
if (::stat(tmparg.c_str(), &buf) != 0){
|
||||
tmparg = Util::getMyPath() + std::string("MistConn") + ServConf["config"]["protocols"][id]["connector"].asStringRef();
|
||||
}
|
||||
|
||||
//we now have a locked, working connection
|
||||
|
||||
{//start a new timeout thread, if neccesary
|
||||
tthread::lock_guard<tthread::mutex> guard(timeoutStartMutex);
|
||||
if (timeoutMutex.try_lock()){
|
||||
if (timeouter){
|
||||
timeouter->join();
|
||||
delete timeouter;
|
||||
}
|
||||
timeoutThreadStarted = false;
|
||||
timeouter = new tthread::thread(Connector_HTTP::proxyTimeoutThread, 0);
|
||||
timeoutMutex.unlock();
|
||||
while (!timeoutThreadStarted){Util::sleep(10);}
|
||||
}
|
||||
}
|
||||
|
||||
//forward the original request
|
||||
myCConn->conn->SendNow(request);
|
||||
myCConn->lastUse = 0;
|
||||
unsigned int timeout = 0;
|
||||
unsigned int retries = 0;
|
||||
//set to only read headers
|
||||
H.headerOnly = true;
|
||||
//wait for a response
|
||||
while (myCConn->conn->connected() && conn.connected()){
|
||||
conn.spool();
|
||||
//check if the whole header was received
|
||||
if (myCConn->conn->spool() && H.Read(*(myCConn->conn))){
|
||||
//208 means the fragment is too new, retry in 3s
|
||||
if (H.url == "208"){
|
||||
while (myCConn->conn->Received().size() > 0){
|
||||
myCConn->conn->Received().get().clear();
|
||||
}
|
||||
retries++;
|
||||
if (retries >= 10){
|
||||
DEBUG_MSG(DLVL_HIGH, "Cancelled connection %s, because of 208 status repeated 10 times", uid.c_str());
|
||||
myCConn->conn->close();
|
||||
myCConn->inUse.unlock();
|
||||
//unset to only read headers
|
||||
H.headerOnly = false;
|
||||
return proxyHandleTimeout(H, conn, "Timeout: fragment too new");
|
||||
}
|
||||
myCConn->lastUse = 0;
|
||||
timeout = 0;
|
||||
Util::sleep(3000);
|
||||
myCConn->conn->SendNow(request);
|
||||
H.Clean();
|
||||
continue;
|
||||
}
|
||||
break; //continue down below this while loop
|
||||
}
|
||||
//keep trying unless the timeout triggers
|
||||
if (timeout++ > 4000){
|
||||
DEBUG_MSG(DLVL_HIGH, "Canceled connection %s, 4s timeout", uid.c_str());
|
||||
myCConn->conn->close();
|
||||
myCConn->inUse.unlock();
|
||||
//unset to only read headers
|
||||
H.headerOnly = false;
|
||||
return proxyHandleTimeout(H, conn, "Gateway timeout while waiting for response");
|
||||
}else{
|
||||
Util::sleep(100);
|
||||
}
|
||||
}
|
||||
//unset to only read headers
|
||||
H.headerOnly = false;
|
||||
if ( !myCConn->conn->connected() || !conn.connected()){
|
||||
//failure, disconnect and sent error to user
|
||||
myCConn->conn->close();
|
||||
myCConn->inUse.unlock();
|
||||
return proxyHandleTimeout(H, conn, "Gateway connection dropped");
|
||||
}else{
|
||||
long long int ret = Util::getMS();
|
||||
//success, check type of response
|
||||
if (H.GetHeader("MistMultiplex") != "No" && (H.GetHeader("Content-Length") != "" || H.GetHeader("Transfer-Encoding") == "chunked")){
|
||||
//known length - simply re-send the request with added headers and continue
|
||||
DEBUG_MSG(DLVL_HIGH, "Proxying %s - known length or chunked transfer encoding", uid.c_str());
|
||||
H.SetHeader("X-UID", uid);
|
||||
H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
|
||||
H.body = "";
|
||||
H.Proxy(*(myCConn->conn), conn);
|
||||
if (!conn.connected()){
|
||||
DEBUG_MSG(DLVL_HIGH, "Incoming connection to %s dropped, killing off connector", uid.c_str());
|
||||
myCConn->conn->close();
|
||||
}
|
||||
myCConn->inUse.unlock();
|
||||
}else{
|
||||
DEBUG_MSG(DLVL_HIGH, "Handing off %s - one-time connection", uid.c_str());
|
||||
//unknown length
|
||||
H.SetHeader("X-UID", uid);
|
||||
H.SetHeader("Server", "mistserver/" PACKAGE_VERSION "/" + Util::Config::libver);
|
||||
conn.SendNow(H.BuildResponse(H.url, H.method));
|
||||
//switch out the connection for an empty one - it makes no sense to keep these globally
|
||||
Socket::Connection * myConn = myCConn->conn;
|
||||
myCConn->conn = new Socket::Connection();
|
||||
myCConn->inUse.unlock();
|
||||
long long int last_data_time = Util::getMS();
|
||||
//continue sending data from this socket and keep it permanently in use
|
||||
while (myConn->connected() && conn.connected()){
|
||||
if (myConn->Received().size() || myConn->spool()){
|
||||
//forward any and all incoming data directly without parsing
|
||||
conn.SendNow(myConn->Received().get());
|
||||
myConn->Received().get().clear();
|
||||
last_data_time = Util::getMS();
|
||||
}else{
|
||||
Util::sleep(30);
|
||||
//if no data for 5000ms, cancel the connection
|
||||
if (Util::getMS() - last_data_time > 5000){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
myConn->close();
|
||||
delete myConn;
|
||||
conn.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
argarr[argnum++] = (char*)tmparg.c_str();
|
||||
JSON::Value & p = ServConf["config"]["protocols"][id];
|
||||
JSON::Value & pipedCapa = capabilities[p["connector"].asStringRef()];
|
||||
/// \todo why is the if(pipedCapa) line not working (nothing is added to argarr)??
|
||||
if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);}
|
||||
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
|
||||
|
||||
argarr[argnum++] = (char*)"-i";
|
||||
argarr[argnum++] = (char*)(temphost.c_str());
|
||||
argarr[argnum++] = (char*)"-s";
|
||||
argarr[argnum++] = (char*)(tempstream.c_str());
|
||||
INFO_MSG("argnum: %i", argnum);
|
||||
|
||||
//for (unsigned int i=0; i<20; i++){
|
||||
//std::cerr << "argv["<<i<< "] " << argarr[i] <<std::endl;
|
||||
//}
|
||||
|
||||
//std::cerr << "p: " << p.toPrettyString() <<std::endl;
|
||||
//std::cerr << "pipedCapa: " << pipedCapa.toPrettyString() <<std::endl;
|
||||
//std::cerr << "capa: " << capabilities.toPrettyString() <<std::endl;
|
||||
|
||||
int tempint = fileno(stderr);
|
||||
///start output process, fdIn and fdOut are connected to conn.sock
|
||||
Util::Procs::StartPiped(argarr, & fdIn, & fdOut, & tempint);
|
||||
conn.drop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
///\brief Determines the type of connector to be used for handling a request.
|
||||
|
@ -593,8 +521,8 @@ namespace Connector_HTTP {
|
|||
//it matched - handle it now
|
||||
std::string streamname = url.substr(found, url.size() - oit->second["url_match"].asStringRef().size() + 1);
|
||||
Util::Stream::sanitizeName(streamname);
|
||||
H.SetVar("stream", streamname);
|
||||
return oit->second["socket"];
|
||||
H.SetVar("stream", streamname);
|
||||
return oit->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -608,7 +536,7 @@ namespace Connector_HTTP {
|
|||
std::string streamname = url.substr(found, found_suf - found);
|
||||
Util::Stream::sanitizeName(streamname);
|
||||
H.SetVar("stream", streamname);
|
||||
return oit->second["socket"];
|
||||
return oit->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -645,16 +573,11 @@ namespace Connector_HTTP {
|
|||
conn.setBlocking(false); //do not block on conn.spool() when no data is available
|
||||
HTTP::Parser Client;
|
||||
while (conn.connected()){
|
||||
if (conn.spool() && Client.Read(conn)){
|
||||
//conn.peek reads data without removing it from pipe
|
||||
if (conn.peek() && Client.Read(conn)){
|
||||
std::string handler = proxyGetHandleType(Client);
|
||||
DEBUG_MSG(DLVL_HIGH, "Received request: %s (%d) => %s (%s)", Client.getUrl().c_str(), conn.getSocket(), handler.c_str(), Client.GetVar("stream").c_str());
|
||||
#if DEBUG >= DLVL_HIGH
|
||||
long long int startms = Util::getMS();
|
||||
long long int midms = 0;
|
||||
#define MID_BENCH midms =
|
||||
#else
|
||||
#define MID_BENCH
|
||||
#endif
|
||||
|
||||
bool closeConnection = false;
|
||||
if (Client.GetHeader("Connection") == "close"){
|
||||
closeConnection = true;
|
||||
|
@ -662,17 +585,14 @@ namespace Connector_HTTP {
|
|||
|
||||
if (handler == "none" || handler == "internal"){
|
||||
if (handler == "internal"){
|
||||
MID_BENCH proxyHandleInternal(Client, conn);
|
||||
proxyHandleInternal(Client, conn);
|
||||
}else{
|
||||
MID_BENCH proxyHandleUnsupported(Client, conn);
|
||||
proxyHandleUnsupported(Client, conn);
|
||||
}
|
||||
}else{
|
||||
MID_BENCH proxyHandleThroughConnector(Client, conn, handler);
|
||||
proxyHandleThroughConnector(Client, conn, handler);
|
||||
}
|
||||
#if DEBUG >= DLVL_HIGH
|
||||
long long int nowms = Util::getMS();
|
||||
DEBUG_MSG(DLVL_HIGH, "Completed request %d (%s) in %d ms (processing) / %d ms (transfer)", conn.getSocket(), handler.c_str(), (midms - startms), (nowms - midms));
|
||||
#endif
|
||||
DEBUG_MSG(DLVL_HIGH, "Completed request %d (%s) ", conn.getSocket(), handler.c_str());
|
||||
if (closeConnection){
|
||||
break;
|
||||
}
|
||||
|
@ -695,6 +615,7 @@ int main(int argc, char ** argv){
|
|||
capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed.";
|
||||
capa["optional"]["debug"]["option"] = "--debug";
|
||||
capa["optional"]["debug"]["type"] = "uint";
|
||||
Connector_HTTP::ServConf = JSON::fromFile(Util::getTmpFolder() + "streamlist");
|
||||
capa["desc"] = "Enables the generic HTTP listener, required by all other HTTP protocols. Needs other HTTP protocols enabled to do much of anything.";
|
||||
capa["deps"] = "";
|
||||
conf.addConnectorOptions(8080, capa);
|
||||
|
@ -729,10 +650,4 @@ int main(int argc, char ** argv){
|
|||
}
|
||||
|
||||
return conf.serveThreadedSocket(Connector_HTTP::proxyHandleHTTPConnection);
|
||||
|
||||
if (Connector_HTTP::timeouter){
|
||||
Connector_HTTP::timeouter->detach();
|
||||
delete Connector_HTTP::timeouter;
|
||||
}
|
||||
return 0;
|
||||
} //main
|
||||
|
|
|
@ -78,7 +78,6 @@ namespace Controller {
|
|||
return;
|
||||
}
|
||||
argarr[argnum++] = (char*)tmparg.c_str();
|
||||
argarr[argnum++] = (char*)"-n";
|
||||
JSON::Value & pipedCapa = capabilities["connectors"][p["connector"].asStringRef()];
|
||||
if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);}
|
||||
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
|
||||
|
@ -156,6 +155,7 @@ namespace Controller {
|
|||
//start up new/changed connectors
|
||||
for (iter = new_connectors.begin(); iter != new_connectors.end(); iter++){
|
||||
if (currentConnectors.count(iter->first) != 1 || currentConnectors[iter->first] != iter->second || !Util::Procs::isActive(toConn(iter->first))){
|
||||
if ( capabilities["connectors"][p[iter->first]["connector"].asString()].isMember("socket") ) {continue;}
|
||||
Log("CONF", "Starting connector: " + iter->second);
|
||||
// clear out old args
|
||||
for (i=0; i<15; i++){argarr[i] = 0;}
|
||||
|
|
|
@ -68,34 +68,35 @@ namespace Mist {
|
|||
}
|
||||
|
||||
void Input::checkHeaderTimes(std::string streamFile){
|
||||
if ( streamFile == "-" ){
|
||||
return;
|
||||
}
|
||||
std::string headerFile = streamFile + ".dtsh";
|
||||
FILE * tmp = fopen(headerFile.c_str(),"r");
|
||||
if (tmp == NULL) {
|
||||
if (tmp == NULL) {
|
||||
INFO_MSG("can't open file: %s (no header times compared, nothing removed)", headerFile.c_str() );
|
||||
return;
|
||||
}
|
||||
struct stat bufStream;
|
||||
return;
|
||||
}
|
||||
struct stat bufStream;
|
||||
struct stat bufHeader;
|
||||
//fstat(fileno(streamFile), &bufStream);
|
||||
//fstat(fileno(tmp), &bufHeader);
|
||||
|
||||
if (stat(streamFile.c_str(), &bufStream) !=0 || stat(headerFile.c_str(), &bufHeader) !=0){
|
||||
ERROR_MSG("could not get file info (no header times compared, nothing removed)");
|
||||
ERROR_MSG("could not get file info (no header times compared, nothing removed)");
|
||||
fclose(tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
int timeStream = bufStream.st_mtime;
|
||||
return;
|
||||
}
|
||||
|
||||
int timeStream = bufStream.st_mtime;
|
||||
int timeHeader = bufHeader.st_mtime;
|
||||
fclose(tmp);
|
||||
INFO_MSG("time header: %i time stream: %i ", timeHeader, timeStream);
|
||||
if (timeHeader < timeStream) {
|
||||
INFO_MSG("removing old header file: %s ",headerFile.c_str());
|
||||
//delete filename
|
||||
remove(headerFile.c_str());
|
||||
INFO_MSG("removing old header file: %s ",headerFile.c_str());
|
||||
//delete filename
|
||||
remove(headerFile.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int Input::run() {
|
||||
if (config->getBool("json")) {
|
||||
std::cerr << capa.toString() << std::endl;
|
||||
|
|
32
src/output/mist_out_http.cpp
Normal file
32
src/output/mist_out_http.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include OUTPUTTYPE
|
||||
#include <mist/config.h>
|
||||
#include <mist/socket.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
Util::Config conf(argv[0], PACKAGE_VERSION);
|
||||
mistOut::init(&conf);
|
||||
|
||||
mistOut::capa["forward"]["streamname"]["name"] = "Stream";
|
||||
mistOut::capa["forward"]["streamname"]["help"] = "What streamname to serve.";
|
||||
mistOut::capa["forward"]["streamname"]["type"] = "str";
|
||||
mistOut::capa["forward"]["streamname"]["option"] = "--stream";
|
||||
mistOut::capa["forward"]["ip"]["name"] = "IP";
|
||||
mistOut::capa["forward"]["ip"]["help"] = "IP of forwarded connection.";
|
||||
mistOut::capa["forward"]["ip"]["type"] = "str";
|
||||
mistOut::capa["forward"]["ip"]["option"] = "--ip";
|
||||
|
||||
conf.addOption("streamname",
|
||||
JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}"));
|
||||
conf.addOption("ip",
|
||||
JSON::fromString("{\"arg\":\"string\",\"short\":\"i\",\"long\":\"ip\",\"help\":\"Ip addr of connection.\"}"));
|
||||
if (conf.parseArgs(argc, argv)) {
|
||||
if (conf.getBool("json")) {
|
||||
std::cout << mistOut::capa.toString() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
Socket::Connection S(fileno(stdout),fileno(stdin) );
|
||||
mistOut tmp(S);
|
||||
return tmp.run();
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -123,6 +123,8 @@ namespace Mist {
|
|||
OutHDS::OutHDS(Socket::Connection & conn) : Output(conn) {
|
||||
audioTrack = 0;
|
||||
playUntil = 0;
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
void OutHDS::onFail(){
|
||||
|
@ -170,8 +172,6 @@ namespace Mist {
|
|||
while (HTTP_R.Read(myConn)){
|
||||
DEBUG_MSG(DLVL_DEVEL, "Received request: %s", HTTP_R.getUrl().c_str());
|
||||
if (HTTP_R.url.find(".abst") != std::string::npos){
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
std::string streamID = HTTP_R.url.substr(streamName.size() + 10);
|
||||
streamID = streamID.substr(0, streamID.find(".abst"));
|
||||
|
@ -184,8 +184,6 @@ namespace Mist {
|
|||
continue;
|
||||
}
|
||||
if (HTTP_R.url.find("f4m") == std::string::npos){
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
std::string tmp_qual = HTTP_R.url.substr(HTTP_R.url.find("/", 10) + 1);
|
||||
unsigned int tid;
|
||||
|
@ -246,8 +244,6 @@ namespace Mist {
|
|||
parseData = true;
|
||||
wantRequest = false;
|
||||
}else{
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
std::stringstream tmpstr;
|
||||
myMeta.toPrettyString(tmpstr);
|
||||
|
|
|
@ -75,6 +75,8 @@ namespace Mist {
|
|||
|
||||
OutHLS::OutHLS(Socket::Connection & conn) : Output(conn) {
|
||||
haveAvcc = false;
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutHLS::~OutHLS() {}
|
||||
|
@ -212,9 +214,7 @@ namespace Mist {
|
|||
void OutHLS::onRequest(){
|
||||
while (HTTP_R.Read(myConn)){
|
||||
DEBUG_MSG(DLVL_DEVEL, "Received request: %s", HTTP_R.getUrl().c_str());
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
AppleCompat = (HTTP_R.GetHeader("User-Agent").find("Apple") != std::string::npos);
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
if (HTTP_R.url.find(".m3u") == std::string::npos){
|
||||
std::string tmpStr = HTTP_R.getUrl();
|
||||
|
@ -257,7 +257,6 @@ namespace Mist {
|
|||
parseData = true;
|
||||
wantRequest = false;
|
||||
}else{
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
std::string request = HTTP_R.url.substr(HTTP_R.url.find("/", 5) + 1);
|
||||
HTTP_S.Clean();
|
||||
|
|
|
@ -44,7 +44,10 @@ std::string toUTF16(std::string original) {
|
|||
|
||||
|
||||
namespace Mist {
|
||||
OutHSS::OutHSS(Socket::Connection & conn) : Output(conn) { }
|
||||
OutHSS::OutHSS(Socket::Connection & conn) : Output(conn) {
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutHSS::~OutHSS() {}
|
||||
|
||||
|
@ -449,8 +452,6 @@ namespace Mist {
|
|||
sentHeader = false;
|
||||
while (HTTP_R.Read(myConn)) {
|
||||
DEBUG_MSG(DLVL_DEVEL, "(%d) Received request %s", getpid(), HTTP_R.getUrl().c_str());
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
initialize();
|
||||
if (HTTP_R.url.find("Manifest") != std::string::npos) {
|
||||
//Manifest, direct reply
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
namespace Mist {
|
||||
OutJSON::OutJSON(Socket::Connection & conn) : Output(conn){
|
||||
realTime = 0;
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutJSON::~OutJSON() {}
|
||||
|
@ -60,8 +62,6 @@ namespace Mist {
|
|||
while (HTTP_R.Read(myConn)){
|
||||
DEBUG_MSG(DLVL_DEVEL, "Received request %s", HTTP_R.getUrl().c_str());
|
||||
first = true;
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
jsonp = "";
|
||||
if (HTTP_R.GetVar("callback") != ""){
|
||||
jsonp = HTTP_R.GetVar("callback");
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
#include <mist/defines.h>
|
||||
|
||||
namespace Mist {
|
||||
OutProgressiveFLV::OutProgressiveFLV(Socket::Connection & conn) : Output(conn) { }
|
||||
OutProgressiveFLV::OutProgressiveFLV(Socket::Connection & conn) : Output(conn) {
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutProgressiveFLV::~OutProgressiveFLV() {}
|
||||
|
||||
|
@ -78,8 +81,6 @@ namespace Mist {
|
|||
if (HTTP_R.GetVar("video") != ""){
|
||||
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("video")).asInt());
|
||||
}
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
parseData = true;
|
||||
wantRequest = false;
|
||||
HTTP_R.Clean();
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
#include <mist/defines.h>
|
||||
|
||||
namespace Mist {
|
||||
OutProgressiveMP3::OutProgressiveMP3(Socket::Connection & conn) : Output(conn) { }
|
||||
OutProgressiveMP3::OutProgressiveMP3(Socket::Connection & conn) : Output(conn) {
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutProgressiveMP3::~OutProgressiveMP3() {}
|
||||
|
||||
|
@ -55,8 +58,6 @@ namespace Mist {
|
|||
if (HTTP_R.GetVar("audio") != ""){
|
||||
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("audio")).asInt());
|
||||
}
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
parseData = true;
|
||||
wantRequest = false;
|
||||
HTTP_R.Clean();
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
#include <mist/mp4_generic.h>
|
||||
|
||||
namespace Mist {
|
||||
OutProgressiveMP4::OutProgressiveMP4(Socket::Connection & conn) : Output(conn) { }
|
||||
OutProgressiveMP4::OutProgressiveMP4(Socket::Connection & conn) : Output(conn) {
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
OutProgressiveMP4::~OutProgressiveMP4() {}
|
||||
|
||||
|
@ -401,8 +404,6 @@ namespace Mist {
|
|||
void OutProgressiveMP4::onRequest(){
|
||||
if (HTTP_R.Read(myConn)){
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Received request: %s", HTTP_R.getUrl().c_str());
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
if (HTTP_R.GetVar("audio") != ""){
|
||||
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("audio")).asInt());
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
namespace Mist {
|
||||
OutProgressiveSRT::OutProgressiveSRT(Socket::Connection & conn) : Output(conn) {
|
||||
realTime = 0;
|
||||
myConn.setHost(config->getString("ip"));
|
||||
streamName = config->getString("streamname");
|
||||
}
|
||||
|
||||
void OutProgressiveSRT::onFail(){
|
||||
|
@ -72,8 +74,6 @@ namespace Mist {
|
|||
if (HTTP_R.GetVar("track") != ""){
|
||||
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("track")).asInt());
|
||||
}
|
||||
myConn.setHost(HTTP_R.GetHeader("X-Origin"));
|
||||
streamName = HTTP_R.GetHeader("X-Stream");
|
||||
parseData = true;
|
||||
wantRequest = false;
|
||||
HTTP_R.Clean();
|
||||
|
|
Loading…
Add table
Reference in a new issue