diff --git a/src/connectors/conn_http.cpp b/src/connectors/conn_http.cpp index a90b1c97..c2fdc658 100644 --- a/src/connectors/conn_http.cpp +++ b/src/connectors/conn_http.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "tinythread.h" #include "embed.js.h" @@ -59,6 +60,7 @@ namespace Connector_HTTP { tthread::mutex connMutex; ///< Mutex for adding/removing connector connections. 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 ///\brief Function run as a thread to timeout requests on the proxy. ///\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++){ 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++){ - if (( *it)["connector"].asStringRef() == "RTMP"){ - if (( *it)["port"].asInt() == 0){ - ( *it)["port"] = 1935ll; - } - JSON::Value tmp; - tmp["type"] = "rtmp"; - tmp["url"] = "rtmp://" + host + ":" + ( *it)["port"].asString() + "/play/" + streamname; - 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")){ + const std::string & cName = ( *it)["connector"].asStringRef(); + //if the connector has a port, + if (capabilities.isMember(cName) && capabilities[cName].isMember("optional") && capabilities[cName]["optional"].isMember("port")){ + //and a URL - then list the URL + if (capabilities[cName].isMember("url_type") && capabilities[cName].isMember("url_handler") && capabilities[cName].isMember("url_rel")){ + if (( *it)["port"].asInt() == 0){ + ( *it)["port"] = capabilities[cName]["optional"]["port"]["default"]; + } JSON::Value tmp; - tmp["type"] = "f4v"; - tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/dynamic/" + streamname + "/manifest.f4m"; - tmp["relurl"] = "/dynamic/" + streamname + "/manifest.f4m"; + tmp["type"] = capabilities[cName]["url_type"]; + size_t found = capabilities[cName]["url_rel"].asStringRef().find('$'); + 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); } - // check for smooth - if (conns.count("HTTPSmooth")){ - JSON::Value tmp; - tmp["type"] = "ism"; - tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/smooth/" + streamname + ".ism/Manifest"; - tmp["relurl"] = "/smooth/" + streamname + ".ism/Manifest"; - json_resp["source"].append(tmp); - } - // check for HLS - if (conns.count("HTTPLive")){ - JSON::Value tmp; - tmp["type"] = "hls"; - tmp["url"] = "http://" + host + ":" + ( *it)["port"].asString() + "/hls/" + streamname + "/index.m3u8"; - tmp["relurl"] = "/hls/" + streamname + "/index.m3u8"; - 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); + //check each enabled protocol separately to see if it depends on this connector + for (JSON::ObjIter oit = capabilities.ObjBegin(); oit != capabilities.ObjEnd(); oit++){ + //if it depends on this connector and has a URL, list it + 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")){ + JSON::Value tmp; + tmp["type"] = oit->second["url_type"]; + size_t found = oit->second["url_rel"].asStringRef().find('$'); + if (found != std::string::npos){ + tmp["relurl"] = oit->second["url_rel"].asStringRef().substr(0, found) + streamname + oit->second["url_rel"].asStringRef().substr(found+1); + }else{ + tmp["relurl"] = "/"; + } + tmp["url"] = oit->second["url_handler"].asStringRef() + "://" + host + ":" + ( *it)["port"].asString() + tmp["relurl"].asStringRef(); + json_resp["source"].append(tmp); + } } } } @@ -325,7 +313,7 @@ namespace Connector_HTTP { delete connectorConnections[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 #if DEBUG >= 4 std::cout << "Created new connection " << uid << std::endl; @@ -481,38 +469,46 @@ namespace Connector_HTTP { ///Possible values are: /// - "none" The request is not supported. /// - "internal" The request should be handled by the proxy itself. - /// - "dynamic" The request should be dispatched to the HTTP Dynamic Connector - /// - "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 + /// - anything else: The request should be dispatched to a connector on the named socket. std::string proxyGetHandleType(HTTP::Parser & H){ std::string url = H.getUrl(); - if (url.find("/dynamic/") != std::string::npos){ - std::string streamname = url.substr(9, url.find("/", 9) - 9); - Util::Stream::sanitizeName(streamname); - H.SetVar("stream", streamname); - return "dynamic"; - } - if (url.find("/smooth/") != std::string::npos && url.find(".ism") != std::string::npos){ - std::string streamname = url.substr(8, url.find("/", 8) - 12); - Util::Stream::sanitizeName(streamname); - H.SetVar("stream", streamname); - return "smooth"; - } - if (url.find("/hls/") != std::string::npos && (url.find(".m3u") != std::string::npos || url.find(".ts") != std::string::npos)){ - std::string streamname = url.substr(5, url.find("/", 5) - 5); - Util::Stream::sanitizeName(streamname); - H.SetVar("stream", streamname); - return "live"; + + //loop over the connectors + for (JSON::ObjIter oit = capabilities.ObjBegin(); oit != capabilities.ObjEnd(); oit++){ + //if it depends on HTTP and has a match or prefix... + 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 (oit->second.isMember("url_match")){ + size_t found = oit->second["url_match"].asStringRef().find('$'); + if (found != std::string::npos){ + 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)){ + //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"]; + } + } + } + //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){ 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"){ return "internal"; } @@ -607,6 +603,22 @@ int main(int argc, char ** argv){ return -1; } + //list available protocols and report about them + std::deque execs; + Util::getMyExec(execs); + std::string arg_one; + char const * conn_args[] = {0, "-j", 0}; + for (std::deque::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")); if ( !server_socket.connected()){ return 1; diff --git a/src/connectors/conn_http_dynamic.cpp b/src/connectors/conn_http_dynamic.cpp index 46010c8d..bb8316b0 100644 --- a/src/connectors/conn_http_dynamic.cpp +++ b/src/connectors/conn_http_dynamic.cpp @@ -341,6 +341,11 @@ int main(int argc, char ** argv){ JSON::Value capa; capa["desc"] = "Enables HTTP protocol Adobe-specific dynamic streaming (also known as HDS)."; 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.parseArgs(argc, argv); diff --git a/src/connectors/conn_http_live.cpp b/src/connectors/conn_http_live.cpp index 722da958..bb6b85ed 100644 --- a/src/connectors/conn_http_live.cpp +++ b/src/connectors/conn_http_live.cpp @@ -360,6 +360,11 @@ int main(int argc, char ** argv){ JSON::Value capa; capa["desc"] = "Enables HTTP protocol Apple-specific streaming (also known as HLS)."; 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.parseArgs(argc, argv); diff --git a/src/connectors/conn_http_progressive.cpp b/src/connectors/conn_http_progressive.cpp index 288c8803..1889c9af 100644 --- a/src/connectors/conn_http_progressive.cpp +++ b/src/connectors/conn_http_progressive.cpp @@ -219,6 +219,11 @@ int main(int argc, char ** argv){ JSON::Value capa; capa["desc"] = "Enables HTTP protocol progressive streaming."; 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.parseArgs(argc, argv); diff --git a/src/connectors/conn_http_smooth.cpp b/src/connectors/conn_http_smooth.cpp index 9af0bed2..e3c395de 100644 --- a/src/connectors/conn_http_smooth.cpp +++ b/src/connectors/conn_http_smooth.cpp @@ -476,6 +476,11 @@ int main(int argc, char ** argv){ JSON::Value capa; capa["desc"] = "Enables HTTP protocol Microsoft-specific smooth streaming through silverlight (also known as HSS)."; 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.parseArgs(argc, argv); diff --git a/src/connectors/conn_rtmp.cpp b/src/connectors/conn_rtmp.cpp index 9c734d7d..e12efa81 100644 --- a/src/connectors/conn_rtmp.cpp +++ b/src/connectors/conn_rtmp.cpp @@ -664,6 +664,9 @@ int main(int argc, char ** argv){ JSON::Value capa; capa["desc"] = "Enables the RTMP protocol which is used by Adobe Flash Player."; capa["deps"] = ""; + capa["url_rel"] = "/play/$"; + capa["url_handler"] = "rtmp"; + capa["url_type"] = "flash"; conf.addConnectorOptions(1935, capa); conf.parseArgs(argc, argv); if (conf.getBool("json")){ diff --git a/src/controller/controller.cpp b/src/controller/controller.cpp index 68576417..6ac46d7f 100644 --- a/src/controller/controller.cpp +++ b/src/controller/controller.cpp @@ -249,7 +249,6 @@ int main(int argc, char ** argv){ char const * conn_args[] = {0, "-j", 0}; for (std::deque::iterator it = execs.begin(); it != execs.end(); it++){ if ((*it).substr(0, 8) == "MistConn"){ - std::cout << "Exec: '" << (*it) << "'" << std::endl; arg_one = Util::getMyPath() + (*it); conn_args[0] = arg_one.c_str(); 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")); diff --git a/src/controller/controller_connectors.cpp b/src/controller/controller_connectors.cpp index be22221a..dbe0ef4b 100644 --- a/src/controller/controller_connectors.cpp +++ b/src/controller/controller_connectors.cpp @@ -18,7 +18,7 @@ namespace Controller { 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. @@ -71,12 +71,6 @@ namespace Controller { 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"]);} - 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.