Removed debug information, fixed controller, made HTTP connector auto-discover connectors.

This commit is contained in:
Thulinma 2013-08-12 16:25:36 +02:00
parent 221cd15b07
commit a254fe7195
8 changed files with 110 additions and 85 deletions

View file

@ -19,6 +19,7 @@
#include <mist/stream.h> #include <mist/stream.h>
#include <mist/timing.h> #include <mist/timing.h>
#include <mist/auth.h> #include <mist/auth.h>
#include <mist/procs.h>
#include "tinythread.h" #include "tinythread.h"
#include "embed.js.h" #include "embed.js.h"
@ -59,6 +60,7 @@ namespace Connector_HTTP {
tthread::mutex connMutex; ///< Mutex for adding/removing connector connections. tthread::mutex connMutex; ///< Mutex for adding/removing connector connections.
tthread::mutex timeoutMutex; ///< Mutex for timeout thread. tthread::mutex timeoutMutex; ///< Mutex for timeout thread.
tthread::thread * timeouter = 0; ///< Thread that times out connections to connectors. tthread::thread * timeouter = 0; ///< Thread that times out connections to connectors.
JSON::Value capabilities; ///< Holds a list of all HTTP connectors and their properties
///\brief Function run as a thread to timeout requests on the proxy. ///\brief Function run as a thread to timeout requests on the proxy.
///\param n A NULL-pointer ///\param n A NULL-pointer
@ -232,56 +234,42 @@ namespace Connector_HTTP {
for (JSON::ArrIter it = ServConf["config"]["protocols"].ArrBegin(); it != ServConf["config"]["protocols"].ArrEnd(); it++){ for (JSON::ArrIter it = ServConf["config"]["protocols"].ArrBegin(); it != ServConf["config"]["protocols"].ArrEnd(); it++){
conns.insert(( *it)["connector"].asStringRef()); conns.insert(( *it)["connector"].asStringRef());
} }
//first, see if we have RTMP working and output all the RTMP. //loop over the connectors.
for (JSON::ArrIter it = ServConf["config"]["protocols"].ArrBegin(); it != ServConf["config"]["protocols"].ArrEnd(); it++){ for (JSON::ArrIter it = ServConf["config"]["protocols"].ArrBegin(); it != ServConf["config"]["protocols"].ArrEnd(); it++){
if (( *it)["connector"].asStringRef() == "RTMP"){ const std::string & cName = ( *it)["connector"].asStringRef();
if (( *it)["port"].asInt() == 0){ //if the connector has a port,
( *it)["port"] = 1935ll; if (capabilities.isMember(cName) && capabilities[cName].isMember("optional") && capabilities[cName]["optional"].isMember("port")){
} //and a URL - then list the URL
JSON::Value tmp; if (capabilities[cName].isMember("url_type") && capabilities[cName].isMember("url_handler") && capabilities[cName].isMember("url_rel")){
tmp["type"] = "rtmp"; if (( *it)["port"].asInt() == 0){
tmp["url"] = "rtmp://" + host + ":" + ( *it)["port"].asString() + "/play/" + streamname; ( *it)["port"] = capabilities[cName]["optional"]["port"]["default"];
json_resp["source"].append(tmp); }
}
}
/// \todo Add raw MPEG2 TS support here?
//then, see if we have HTTP working and output all the HTTP.
for (JSON::ArrIter it = ServConf["config"]["protocols"].ArrBegin(); it != ServConf["config"]["protocols"].ArrEnd(); it++){
if (( *it)["connector"].asStringRef() == "HTTP"){
if (( *it)["port"].asInt() == 0){
( *it)["port"] = 8080ll;
}
// check for dynamic
if (conns.count("HTTPDynamic")){
JSON::Value tmp; JSON::Value tmp;
tmp["type"] = "f4v"; tmp["type"] = capabilities[cName]["url_type"];
tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/dynamic/" + streamname + "/manifest.f4m"; size_t found = capabilities[cName]["url_rel"].asStringRef().find('$');
tmp["relurl"] = "/dynamic/" + streamname + "/manifest.f4m"; if (found != std::string::npos){
tmp["relurl"] = capabilities[cName]["url_rel"].asStringRef().substr(0, found) + streamname + capabilities[cName]["url_rel"].asStringRef().substr(found+1);
}else{
tmp["relurl"] = "/";
}
tmp["url"] = capabilities[cName]["url_handler"].asStringRef() + "://" + host + ":" + ( *it)["port"].asString() + tmp["relurl"].asStringRef();
json_resp["source"].append(tmp); json_resp["source"].append(tmp);
} }
// check for smooth //check each enabled protocol separately to see if it depends on this connector
if (conns.count("HTTPSmooth")){ for (JSON::ObjIter oit = capabilities.ObjBegin(); oit != capabilities.ObjEnd(); oit++){
JSON::Value tmp; //if it depends on this connector and has a URL, list it
tmp["type"] = "ism"; if (conns.count(oit->first) && oit->second["deps"].asStringRef() == cName && oit->second.isMember("url_type") && oit->second.isMember("url_handler") && oit->second.isMember("url_rel")){
tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/smooth/" + streamname + ".ism/Manifest"; JSON::Value tmp;
tmp["relurl"] = "/smooth/" + streamname + ".ism/Manifest"; tmp["type"] = oit->second["url_type"];
json_resp["source"].append(tmp); size_t found = oit->second["url_rel"].asStringRef().find('$');
} if (found != std::string::npos){
// check for HLS tmp["relurl"] = oit->second["url_rel"].asStringRef().substr(0, found) + streamname + oit->second["url_rel"].asStringRef().substr(found+1);
if (conns.count("HTTPLive")){ }else{
JSON::Value tmp; tmp["relurl"] = "/";
tmp["type"] = "hls"; }
tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/hls/" + streamname + "/index.m3u8"; tmp["url"] = oit->second["url_handler"].asStringRef() + "://" + host + ":" + ( *it)["port"].asString() + tmp["relurl"].asStringRef();
tmp["relurl"] = "/hls/" + streamname + "/index.m3u8"; json_resp["source"].append(tmp);
json_resp["source"].append(tmp); }
}
// check for progressive
if (conns.count("HTTPProgressive")){
JSON::Value tmp;
tmp["type"] = "flv";
tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/" + streamname + ".flv";
tmp["relurl"] = "/" + streamname + ".flv";
json_resp["source"].append(tmp);
} }
} }
} }
@ -325,7 +313,7 @@ namespace Connector_HTTP {
delete connectorConnections[uid]; delete connectorConnections[uid];
connectorConnections.erase(uid); connectorConnections.erase(uid);
} }
connectorConnections[uid] = new ConnConn(new Socket::Connection("/tmp/mist/http_" + connector)); connectorConnections[uid] = new ConnConn(new Socket::Connection("/tmp/mist/" + connector));
connectorConnections[uid]->conn->setBlocking(false); //do not block on spool() with no data connectorConnections[uid]->conn->setBlocking(false); //do not block on spool() with no data
#if DEBUG >= 4 #if DEBUG >= 4
std::cout << "Created new connection " << uid << std::endl; std::cout << "Created new connection " << uid << std::endl;
@ -481,38 +469,46 @@ namespace Connector_HTTP {
///Possible values are: ///Possible values are:
/// - "none" The request is not supported. /// - "none" The request is not supported.
/// - "internal" The request should be handled by the proxy itself. /// - "internal" The request should be handled by the proxy itself.
/// - "dynamic" The request should be dispatched to the HTTP Dynamic Connector /// - anything else: The request should be dispatched to a connector on the named socket.
/// - "progressive" The request should be dispatched to the HTTP Progressive Connector
/// - "smooth" The request should be dispatched to the HTTP Smooth Connector
/// - "live" The request should be dispatched to the HTTP Live Connector
std::string proxyGetHandleType(HTTP::Parser & H){ std::string proxyGetHandleType(HTTP::Parser & H){
std::string url = H.getUrl(); std::string url = H.getUrl();
if (url.find("/dynamic/") != std::string::npos){
std::string streamname = url.substr(9, url.find("/", 9) - 9); //loop over the connectors
Util::Stream::sanitizeName(streamname); for (JSON::ObjIter oit = capabilities.ObjBegin(); oit != capabilities.ObjEnd(); oit++){
H.SetVar("stream", streamname); //if it depends on HTTP and has a match or prefix...
return "dynamic"; if (oit->second["deps"].asStringRef() == "HTTP" && oit->second.isMember("socket") && (oit->second.isMember("url_match") || oit->second.isMember("url_prefix"))){
} //if there is a matcher, try to match
if (url.find("/smooth/") != std::string::npos && url.find(".ism") != std::string::npos){ if (oit->second.isMember("url_match")){
std::string streamname = url.substr(8, url.find("/", 8) - 12); size_t found = oit->second["url_match"].asStringRef().find('$');
Util::Stream::sanitizeName(streamname); if (found != std::string::npos){
H.SetVar("stream", streamname); if (oit->second["url_match"].asStringRef().substr(0, found) == url.substr(0, found) && oit->second["url_match"].asStringRef().substr(found+1) == url.substr(url.size() - (oit->second["url_match"].asStringRef().size() - found) + 1)){
return "smooth"; //it matched - handle it now
} std::string streamname = url.substr(found, url.size() - oit->second["url_match"].asStringRef().size() + 1);
if (url.find("/hls/") != std::string::npos && (url.find(".m3u") != std::string::npos || url.find(".ts") != std::string::npos)){ Util::Stream::sanitizeName(streamname);
std::string streamname = url.substr(5, url.find("/", 5) - 5); H.SetVar("stream", streamname);
Util::Stream::sanitizeName(streamname); return oit->second["socket"];
H.SetVar("stream", streamname); }
return "live"; }
}
//if there is a prefix, try to match
if (oit->second.isMember("url_prefix")){
size_t found = oit->second["url_prefix"].asStringRef().find('$');
if (found != std::string::npos){
size_t found_suf = url.find(oit->second["url_prefix"].asStringRef().substr(found+1), found);
if (oit->second["url_prefix"].asStringRef().substr(0, found) == url.substr(0, found) && found_suf != std::string::npos){
//it matched - handle it now
std::string streamname = url.substr(found, found_suf - found);
Util::Stream::sanitizeName(streamname);
H.SetVar("stream", streamname);
return oit->second["socket"];
}
}
}
}
} }
if (url.length() > 4){ if (url.length() > 4){
std::string ext = url.substr(url.length() - 4, 4); std::string ext = url.substr(url.length() - 4, 4);
if (ext == ".flv" || ext == ".mp3"){
std::string streamname = url.substr(1, url.length() - 5);
Util::Stream::sanitizeName(streamname);
H.SetVar("stream", streamname);
return "progressive";
}
if (ext == ".ico"){ if (ext == ".ico"){
return "internal"; return "internal";
} }
@ -607,6 +603,22 @@ int main(int argc, char ** argv){
return -1; return -1;
} }
//list available protocols and report about them
std::deque<std::string> execs;
Util::getMyExec(execs);
std::string arg_one;
char const * conn_args[] = {0, "-j", 0};
for (std::deque<std::string>::iterator it = execs.begin(); it != execs.end(); it++){
if ((*it).substr(0, 8) == "MistConn"){
arg_one = Util::getMyPath() + (*it);
conn_args[0] = arg_one.c_str();
Connector_HTTP::capabilities[(*it).substr(8)] = JSON::fromString(Util::Procs::getOutputOf((char**)conn_args));
if (Connector_HTTP::capabilities[(*it).substr(8)].size() < 1){
Connector_HTTP::capabilities.removeMember((*it).substr(8));
}
}
}
Socket::Server server_socket = Socket::Server(conf.getInteger("listen_port"), conf.getString("listen_interface")); Socket::Server server_socket = Socket::Server(conf.getInteger("listen_port"), conf.getString("listen_interface"));
if ( !server_socket.connected()){ if ( !server_socket.connected()){
return 1; return 1;

View file

@ -341,6 +341,11 @@ int main(int argc, char ** argv){
JSON::Value capa; JSON::Value capa;
capa["desc"] = "Enables HTTP protocol Adobe-specific dynamic streaming (also known as HDS)."; capa["desc"] = "Enables HTTP protocol Adobe-specific dynamic streaming (also known as HDS).";
capa["deps"] = "HTTP"; capa["deps"] = "HTTP";
capa["url_rel"] = "/dynamic/$/manifest.f4m";
capa["url_prefix"] = "/dynamic/$/";
capa["url_handler"] = "http";
capa["url_type"] = "flash";
capa["socket"] = "http_dynamic";
conf.addBasicConnectorOptions(capa); conf.addBasicConnectorOptions(capa);
conf.parseArgs(argc, argv); conf.parseArgs(argc, argv);

View file

@ -360,6 +360,11 @@ int main(int argc, char ** argv){
JSON::Value capa; JSON::Value capa;
capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS)."; capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS).";
capa["deps"] = "HTTP"; capa["deps"] = "HTTP";
capa["url_rel"] = "/hls/$/index.m3u8";
capa["url_prefix"] = "/hls/$/";
capa["url_handler"] = "http";
capa["url_type"] = "hls";
capa["socket"] = "http_live";
conf.addBasicConnectorOptions(capa); conf.addBasicConnectorOptions(capa);
conf.parseArgs(argc, argv); conf.parseArgs(argc, argv);

View file

@ -219,6 +219,11 @@ int main(int argc, char ** argv){
JSON::Value capa; JSON::Value capa;
capa["desc"] = "Enables HTTP protocol progressive streaming."; capa["desc"] = "Enables HTTP protocol progressive streaming.";
capa["deps"] = "HTTP"; capa["deps"] = "HTTP";
capa["url_rel"] = "/$.flv";
capa["url_match"] = "/$.flv";
capa["url_handler"] = "http";
capa["url_type"] = "flash";
capa["socket"] = "http_progressive";
conf.addBasicConnectorOptions(capa); conf.addBasicConnectorOptions(capa);
conf.parseArgs(argc, argv); conf.parseArgs(argc, argv);

View file

@ -476,6 +476,11 @@ int main(int argc, char ** argv){
JSON::Value capa; JSON::Value capa;
capa["desc"] = "Enables HTTP protocol Microsoft-specific smooth streaming through silverlight (also known as HSS)."; capa["desc"] = "Enables HTTP protocol Microsoft-specific smooth streaming through silverlight (also known as HSS).";
capa["deps"] = "HTTP"; capa["deps"] = "HTTP";
capa["url_rel"] = "/smooth/$.ism/Manifest";
capa["url_prefix"] = "/smooth/$.ism/";
capa["url_handler"] = "http";
capa["url_type"] = "ism";
capa["socket"] = "http_smooth";
conf.addBasicConnectorOptions(capa); conf.addBasicConnectorOptions(capa);
conf.parseArgs(argc, argv); conf.parseArgs(argc, argv);

View file

@ -664,6 +664,9 @@ int main(int argc, char ** argv){
JSON::Value capa; JSON::Value capa;
capa["desc"] = "Enables the RTMP protocol which is used by Adobe Flash Player."; capa["desc"] = "Enables the RTMP protocol which is used by Adobe Flash Player.";
capa["deps"] = ""; capa["deps"] = "";
capa["url_rel"] = "/play/$";
capa["url_handler"] = "rtmp";
capa["url_type"] = "flash";
conf.addConnectorOptions(1935, capa); conf.addConnectorOptions(1935, capa);
conf.parseArgs(argc, argv); conf.parseArgs(argc, argv);
if (conf.getBool("json")){ if (conf.getBool("json")){

View file

@ -249,7 +249,6 @@ int main(int argc, char ** argv){
char const * conn_args[] = {0, "-j", 0}; char const * conn_args[] = {0, "-j", 0};
for (std::deque<std::string>::iterator it = execs.begin(); it != execs.end(); it++){ for (std::deque<std::string>::iterator it = execs.begin(); it != execs.end(); it++){
if ((*it).substr(0, 8) == "MistConn"){ if ((*it).substr(0, 8) == "MistConn"){
std::cout << "Exec: '" << (*it) << "'" << std::endl;
arg_one = Util::getMyPath() + (*it); arg_one = Util::getMyPath() + (*it);
conn_args[0] = arg_one.c_str(); conn_args[0] = arg_one.c_str();
capabilities["connectors"][(*it).substr(8)] = JSON::fromString(Util::Procs::getOutputOf((char**)conn_args)); capabilities["connectors"][(*it).substr(8)] = JSON::fromString(Util::Procs::getOutputOf((char**)conn_args));
@ -258,9 +257,6 @@ int main(int argc, char ** argv){
} }
} }
} }
std::cout << capabilities.toPrettyString() << std::endl;
createAccount(conf.getString("account")); createAccount(conf.getString("account"));

View file

@ -18,7 +18,7 @@ namespace Controller {
static inline std::string toConn(long long i){ static inline std::string toConn(long long i){
return std::string("Conn") + JSON::Value(i).asStringRef(); return std::string("Conn") + JSON::Value(i).asString();
} }
///\brief Checks if the binary mentioned in the protocol argument is currently active, if so, restarts it. ///\brief Checks if the binary mentioned in the protocol argument is currently active, if so, restarts it.
@ -71,12 +71,6 @@ namespace Controller {
JSON::Value & pipedCapa = capabilities["connectors"][p["connector"].asStringRef()]; JSON::Value & pipedCapa = capabilities["connectors"][p["connector"].asStringRef()];
if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);} if (pipedCapa.isMember("required")){builPipedPart(p, argarr, argnum, pipedCapa["required"]);}
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);} if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
for (int i = 0; i < argnum; ++i){
if (argarr[i] > 0){
std::cerr << argarr[i] << " ";
}
}
std::cerr << std::endl;
} }
///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary. ///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary.